diff --git a/llvm/include/llvm/ADT/Bitfields.h b/llvm/include/llvm/ADT/Bitfields.h --- a/llvm/include/llvm/ADT/Bitfields.h +++ b/llvm/include/llvm/ADT/Bitfields.h @@ -275,6 +275,12 @@ template static constexpr bool isOverlapping() { return A::LastBit >= B::FirstBit && B::LastBit >= A::FirstBit; } + + template static constexpr bool areContiguous() { return true; } + template + static constexpr bool areContiguous() { + return A::LastBit + 1 == B::FirstBit && areContiguous(); + } }; } // namespace llvm diff --git a/llvm/include/llvm/IR/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h --- a/llvm/include/llvm/IR/InstrTypes.h +++ b/llvm/include/llvm/IR/InstrTypes.h @@ -1096,12 +1096,15 @@ /// subclass requires. Note that accessing the end of the argument list isn't /// as cheap as most other operations on the base class. class CallBase : public Instruction { - // The first two bits are reserved by CallInst for fast retrieving, +protected: + // The first two bits are reserved by CallInst for fast retrieval, using CallInstReservedField = Bitfield::Element; // Next bit:2 using CallingConvField = Bitfield::Element; // Next bit:12 + static_assert( + Bitfield::areContiguous(), + "Bitfields must be contiguous"); -protected: /// The last operand is the called operand. static constexpr int CalledOperandOpEndIdx = -1; diff --git a/llvm/include/llvm/IR/Instruction.h b/llvm/include/llvm/IR/Instruction.h --- a/llvm/include/llvm/IR/Instruction.h +++ b/llvm/include/llvm/IR/Instruction.h @@ -65,6 +65,9 @@ typename Bitfield::Element; + template + using BoolBitfieldElement = typename Bitfield::Element; + private: // The last bit is used to store whether the instruction has metadata attached // or not. diff --git a/llvm/include/llvm/IR/Instructions.h b/llvm/include/llvm/IR/Instructions.h --- a/llvm/include/llvm/IR/Instructions.h +++ b/llvm/include/llvm/IR/Instructions.h @@ -52,6 +52,10 @@ class DataLayout; class LLVMContext; +template +using AtomicOrderingBitfieldElement = + typename Bitfield::Element; + //===----------------------------------------------------------------------===// // AllocaInst Class //===----------------------------------------------------------------------===// @@ -61,8 +65,11 @@ Type *AllocatedType; using AlignmentField = AlignmentBitfieldElement<0>; // Next bit:5 - using UsedWithInAllocaField = Bitfield::Element; // Next bit:6 - using SwiftErrorField = Bitfield::Element; // Next bit:7 + using UsedWithInAllocaField = BoolBitfieldElement<5>; // Next bit:6 + using SwiftErrorField = BoolBitfieldElement<6>; // Next bit:7 + static_assert(Bitfield::areContiguous(), + "Bitfields must be contiguous"); protected: // Note: Instruction needs to be a friend here to call cloneImpl. @@ -168,10 +175,12 @@ /// An instruction for reading from memory. This uses the SubclassData field in /// Value to store whether or not the load is volatile. class LoadInst : public UnaryInstruction { - using VolatileField = Bitfield::Element; // Next bit:1 + using VolatileField = BoolBitfieldElement<0>; // Next bit:1 using AlignmentField = AlignmentBitfieldElement<1>; // Next bit:6 - using OrderingField = Bitfield::Element; // Next bit:9 + using OrderingField = AtomicOrderingBitfieldElement<6>; // Next bit:9 + static_assert( + Bitfield::areContiguous(), + "Bitfields must be contiguous"); void AssertOK(); @@ -295,10 +304,12 @@ /// An instruction for storing to memory. class StoreInst : public Instruction { - using VolatileField = Bitfield::Element; // Next bit:1 + using VolatileField = BoolBitfieldElement<0>; // Next bit:1 using AlignmentField = AlignmentBitfieldElement<1>; // Next bit:6 - using OrderingField = Bitfield::Element; // Next bit:9 + using OrderingField = AtomicOrderingBitfieldElement<6>; // Next bit:9 + static_assert( + Bitfield::areContiguous(), + "Bitfields must be contiguous"); void AssertOK(); @@ -434,8 +445,7 @@ /// An instruction for ordering other memory operations. class FenceInst : public Instruction { - using OrderingField = Bitfield::Element; // Next bit:4 + using OrderingField = AtomicOrderingBitfieldElement<0>; // Next bit:3 void Init(AtomicOrdering Ordering, SyncScope::ID SSID); @@ -538,15 +548,13 @@ return User::operator new(s, 3); } - // FIXME: Reuse bit 1 that was used by `syncscope.` - using VolatileField = Bitfield::Element; // Next bit:1 - using SuccessOrderingField = - Bitfield::Element; // Next bit:5 - using FailureOrderingField = - Bitfield::Element; // Next bit:8 - using WeakField = Bitfield::Element; // Next bit:9 + using VolatileField = BoolBitfieldElement<0>; // Next bit:1 + using SuccessOrderingField = AtomicOrderingBitfieldElement<1>; // Next bit:4 + using FailureOrderingField = AtomicOrderingBitfieldElement<4>; // Next bit:7 + using WeakField = BoolBitfieldElement<7>; // Next bit:8 + static_assert(Bitfield::areContiguous(), + "Bitfields must be contiguous"); /// Always returns the natural type alignment. /// FIXME: Introduce a proper alignment @@ -738,13 +746,13 @@ return User::operator new(s, 2); } - // FIXME: Reuse bit 1 that was used by `syncscope.` - using VolatileField = Bitfield::Element; // Next bit:1 - using AtomicOrderingField = - Bitfield::Element; // Next bit:5 - using OperationField = Bitfield::Element; // Next bit:9 + using VolatileField = BoolBitfieldElement<0>; // Next bit:1 + using AtomicOrderingField = AtomicOrderingBitfieldElement<1>; // Next bit:4 + using OperationField = Bitfield::Element; // Next bit:8 + static_assert(Bitfield::areContiguous(), + "Bitfields must be contiguous"); BinOp getOperation() const { return getSubclassData(); } @@ -1572,6 +1580,9 @@ }; using TailCallKindField = Bitfield::Element; + static_assert( + Bitfield::areContiguous(), + "Bitfields must be contiguous"); TailCallKind getTailCallKind() const { return getSubclassData(); @@ -2735,7 +2746,7 @@ /// cleanup. /// class LandingPadInst : public Instruction { - using CleanupField = Bitfield::Element; + using CleanupField = BoolBitfieldElement<0>; /// The number of operands actually allocated. NumOperands is /// the number actually in use. diff --git a/llvm/unittests/ADT/BitFieldsTest.cpp b/llvm/unittests/ADT/BitFieldsTest.cpp --- a/llvm/unittests/ADT/BitFieldsTest.cpp +++ b/llvm/unittests/ADT/BitFieldsTest.cpp @@ -192,6 +192,18 @@ EXPECT_FALSE((Bitfield::isOverlapping())); } +TEST(BitfieldsTest, areContiguous) { + using A = Bitfield::Element; // Next Bit:1 + using B = Bitfield::Element; // Next Bit:5 + using C = Bitfield::Element; // Next Bit:8 + EXPECT_TRUE((Bitfield::areContiguous())); + EXPECT_TRUE((Bitfield::areContiguous())); + + EXPECT_FALSE((Bitfield::areContiguous())); + EXPECT_FALSE((Bitfield::areContiguous())); + EXPECT_FALSE((Bitfield::areContiguous())); +} + TEST(BitfieldsTest, FullUint64) { uint64_t Storage = 0; using Value = Bitfield::Element;