Index: llvm/include/llvm/Support/Bitfields.h =================================================================== --- /dev/null +++ llvm/include/llvm/Support/Bitfields.h @@ -0,0 +1,63 @@ +//===-- llvm/Support/BitFields.h - Utilities for C++ bit-fields -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Utilities for wrangling C++ bit-fields. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_BIT_FIELDS_H +#define LLVM_SUPPORT_BIT_FIELDS_H + +#include "llvm/Support/MathExtras.h" + +/// Gets the width in bits of Type::Field, which must be a bitfield with an +/// underlying type that's an unsigned integer. +/// +/// clang constant-folds this nicely, but other compilers (e.g. gcc) are not +/// quite as smart. So don't rely on this being free. +#define LLVM_BITFIELD_WIDTH(Type, Field) \ + [] { \ + static_assert(::std::is_unsigned::value, \ + #Type "::" #Field " must be an unsigned integral type."); \ + Type T; \ + ::memset(&T, 0xff, sizeof(T)); \ + uint64_t Bits = T.Field; \ + assert(::llvm::isMask_64(Bits) && "Error reading " #Type "::" #Field); \ + return ::llvm::countTrailingOnes(Bits); \ + }() + +/// Does +/// +/// DstContainer.DstField = Src; +/// +/// asserts that Src fits inside Dst. DstField must be a bitfield with +/// an unsigned integral underlying type. +/// +/// For example: +/// +/// \code +/// Struct T { +/// unsigned X : 2; +/// }; +/// +/// T t; +/// LLVM_CHECKED_BITFIELD_ASSIGN(t, X, 3); // t.X = 3; +/// LLVM_CHECKED_BITFIELD_ASSIGN(t, X, 42); // error: 42 doesn't fit in T::X. +/// \endcode +/// +#define LLVM_CHECKED_BITFIELD_ASSIGN(DstContainer, DstField, Src) \ + do { \ + auto V = (Src); \ + assert(::llvm::isUIntN( \ + LLVM_BITFIELD_WIDTH(decltype(DstContainer), DstField), V) && \ + #Src " is too wide to fit inside " #DstContainer "::" #DstField); \ + DstContainer.DstField = V; \ + } while (0) + +#endif Index: llvm/unittests/Support/BitfieldsTest.cpp =================================================================== --- /dev/null +++ llvm/unittests/Support/BitfieldsTest.cpp @@ -0,0 +1,65 @@ +//===- unittests/Support/MathExtrasTest.cpp - math utils tests ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Bitfields.h" +#include "gtest/gtest.h" + +namespace { + +TEST(BitfieldsTest, BitfieldWidth) { + struct S { + unsigned a : 1; + uint32_t b : 32; + uint64_t c : 64; + uint64_t d : 1; + uint64_t e : 10; + }; + // Can't stick LLVM_BITFIELD_WIDTH macro into EXPECT_EQ -- the two macros' + // magics are at odds. + int V; + V = LLVM_BITFIELD_WIDTH(S, a); + EXPECT_EQ(1, V); + V = LLVM_BITFIELD_WIDTH(S, b); + EXPECT_EQ(32, V); + V = LLVM_BITFIELD_WIDTH(S, c); + EXPECT_EQ(64, V); + V = LLVM_BITFIELD_WIDTH(S, d); + EXPECT_EQ(1, V); + V = LLVM_BITFIELD_WIDTH(S, e); + EXPECT_EQ(10, V); +} + +TEST(BitfieldsTest, BitfieldAssign) { + struct { + unsigned a : 1; + uint32_t b : 32; + uint64_t c : 64; + } S; + + LLVM_CHECKED_BITFIELD_ASSIGN(S, a, 0); + EXPECT_EQ(0U, S.a); + LLVM_CHECKED_BITFIELD_ASSIGN(S, a, 1); + EXPECT_EQ(1U, S.a); + + LLVM_CHECKED_BITFIELD_ASSIGN(S, b, std::numeric_limits::max()); + EXPECT_EQ(std::numeric_limits::max(), S.b); + LLVM_CHECKED_BITFIELD_ASSIGN(S, b, 0); + EXPECT_EQ(0U, S.b); + LLVM_CHECKED_BITFIELD_ASSIGN(S, b, 42); + EXPECT_EQ(42U, S.b); + + LLVM_CHECKED_BITFIELD_ASSIGN(S, c, std::numeric_limits::max()); + EXPECT_EQ(std::numeric_limits::max(), S.c); + LLVM_CHECKED_BITFIELD_ASSIGN(S, c, std::numeric_limits::max()); + EXPECT_EQ(std::numeric_limits::max(), S.c); + LLVM_CHECKED_BITFIELD_ASSIGN(S, c, 0); + EXPECT_EQ(0U, S.c); +} + +} // namespace Index: llvm/unittests/Support/CMakeLists.txt =================================================================== --- llvm/unittests/Support/CMakeLists.txt +++ llvm/unittests/Support/CMakeLists.txt @@ -6,6 +6,7 @@ AlignOfTest.cpp AllocatorTest.cpp ArrayRecyclerTest.cpp + BitfieldsTest.cpp BlockFrequencyTest.cpp BranchProbabilityTest.cpp Casting.cpp