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 @@ -228,6 +228,7 @@ static constexpr unsigned Bits = Size; static constexpr unsigned FirstBit = Offset; static constexpr unsigned LastBit = Shift + Bits - 1; + static constexpr unsigned NextBit = Shift + Bits; private: template friend struct bitfields_details::Impl; @@ -275,6 +276,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::NextBit == 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 @@ -758,7 +758,7 @@ BAD_ICMP_PREDICATE = ICMP_SLE + 1 }; using PredicateField = - Bitfield::Element; // Next bit:6 + Bitfield::Element; protected: CmpInst(Type *ty, Instruction::OtherOps op, Predicate pred, @@ -1096,12 +1096,16 @@ /// 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, - using CallInstReservedField = Bitfield::Element; // Next bit:2 - using CallingConvField = Bitfield::Element; // Next bit:12 - protected: + // The first two bits are reserved by CallInst for fast retrieval, + using CallInstReservedField = Bitfield::Element; + using CallingConvField = + Bitfield::Element; + static_assert( + Bitfield::areContiguous(), + "Bitfields must be contiguous"); + /// 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 @@ -23,6 +23,7 @@ #include "llvm/IR/SymbolTableListTraits.h" #include "llvm/IR/User.h" #include "llvm/IR/Value.h" +#include "llvm/Support/AtomicOrdering.h" #include "llvm/Support/Casting.h" #include #include @@ -53,7 +54,7 @@ protected: // The 15 first bits of `Value::SubclassData` are available for subclasses of // `Instruction` to use. - using OpaqueField = Bitfield::Element; // Next bit:15 + using OpaqueField = Bitfield::Element; // Template alias so that all Instruction storing alignment use the same // definiton. @@ -61,10 +62,18 @@ // 2^29. We store them as Log2(Alignment), so we need 5 bits to encode the 30 // possible values. template - using AlignmentBitfieldElement = + using AlignmentBitfieldElementT = typename Bitfield::Element; + template + using BoolBitfieldElementT = typename Bitfield::Element; + + template + using AtomicOrderingBitfieldElementT = + 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 @@ -60,9 +60,12 @@ class AllocaInst : public UnaryInstruction { Type *AllocatedType; - using AlignmentField = AlignmentBitfieldElement<0>; // Next bit:5 - using UsedWithInAllocaField = Bitfield::Element; // Next bit:6 - using SwiftErrorField = Bitfield::Element; // Next bit:7 + using AlignmentField = AlignmentBitfieldElementT<0>; + using UsedWithInAllocaField = BoolBitfieldElementT; + using SwiftErrorField = BoolBitfieldElementT; + static_assert(Bitfield::areContiguous(), + "Bitfields must be contiguous"); protected: // Note: Instruction needs to be a friend here to call cloneImpl. @@ -168,10 +171,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 AlignmentField = AlignmentBitfieldElement<1>; // Next bit:6 - using OrderingField = Bitfield::Element; // Next bit:9 + using VolatileField = BoolBitfieldElementT<0>; + using AlignmentField = AlignmentBitfieldElementT; + using OrderingField = AtomicOrderingBitfieldElementT; + static_assert( + Bitfield::areContiguous(), + "Bitfields must be contiguous"); void AssertOK(); @@ -295,10 +300,12 @@ /// An instruction for storing to memory. class StoreInst : public Instruction { - using VolatileField = Bitfield::Element; // Next bit:1 - using AlignmentField = AlignmentBitfieldElement<1>; // Next bit:6 - using OrderingField = Bitfield::Element; // Next bit:9 + using VolatileField = BoolBitfieldElementT<0>; + using AlignmentField = AlignmentBitfieldElementT; + using OrderingField = AtomicOrderingBitfieldElementT; + static_assert( + Bitfield::areContiguous(), + "Bitfields must be contiguous"); void AssertOK(); @@ -434,8 +441,7 @@ /// An instruction for ordering other memory operations. class FenceInst : public Instruction { - using OrderingField = Bitfield::Element; // Next bit:4 + using OrderingField = AtomicOrderingBitfieldElementT<0>; void Init(AtomicOrdering Ordering, SyncScope::ID SSID); @@ -538,15 +544,15 @@ return User::operator new(s, 3); } - // FIXME: Reuse bit 1 that was used by `syncscope.` - using VolatileField = Bitfield::Element; // Next bit:1 + using VolatileField = BoolBitfieldElementT<0>; using SuccessOrderingField = - Bitfield::Element; // Next bit:5 + AtomicOrderingBitfieldElementT; using FailureOrderingField = - Bitfield::Element; // Next bit:8 - using WeakField = Bitfield::Element; // Next bit:9 + AtomicOrderingBitfieldElementT; + using WeakField = BoolBitfieldElementT; + static_assert(Bitfield::areContiguous(), + "Bitfields must be contiguous"); /// Always returns the natural type alignment. /// FIXME: Introduce a proper alignment @@ -738,13 +744,14 @@ return User::operator new(s, 2); } - // FIXME: Reuse bit 1 that was used by `syncscope.` - using VolatileField = Bitfield::Element; // Next bit:1 + using VolatileField = BoolBitfieldElementT<0>; using AtomicOrderingField = - Bitfield::Element; // Next bit:5 - using OperationField = Bitfield::Element; // Next bit:9 + AtomicOrderingBitfieldElementT; + using OperationField = Bitfield::Element; + static_assert(Bitfield::areContiguous(), + "Bitfields must be contiguous"); BinOp getOperation() const { return getSubclassData(); } @@ -1572,6 +1579,9 @@ }; using TailCallKindField = Bitfield::Element; + static_assert( + Bitfield::areContiguous(), + "Bitfields must be contiguous"); TailCallKind getTailCallKind() const { return getSubclassData(); @@ -2735,7 +2745,7 @@ /// cleanup. /// class LandingPadInst : public Instruction { - using CleanupField = Bitfield::Element; + using CleanupField = BoolBitfieldElementT<0>; /// The number of operands actually allocated. NumOperands is /// the number actually in use. @@ -4106,7 +4116,7 @@ // CatchSwitchInst Class //===----------------------------------------------------------------------===// class CatchSwitchInst : public Instruction { - using UnwindDestField = Bitfield::Element; // Next bit:1 + using UnwindDestField = BoolBitfieldElementT<0>; /// The number of operands actually allocated. NumOperands is /// the number actually in use. @@ -4455,7 +4465,8 @@ //===----------------------------------------------------------------------===// class CleanupReturnInst : public Instruction { - using UnwindDestField = Bitfield::Element; // Next bit:1 + using UnwindDestField = BoolBitfieldElementT<0>; + private: CleanupReturnInst(const CleanupReturnInst &RI); CleanupReturnInst(Value *CleanupPad, BasicBlock *UnwindBB, unsigned Values, 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;