diff --git a/include/llvm/ADT/Bitfields.h b/include/llvm/ADT/Bitfields.h index 9891b4692e8..d93f6483fa5 100644 --- a/include/llvm/ADT/Bitfields.h +++ b/include/llvm/ADT/Bitfields.h @@ -228,6 +228,7 @@ struct Bitfield { 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 @@ struct Bitfield { 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/include/llvm/IR/InstrTypes.h b/include/llvm/IR/InstrTypes.h index 770d3183a90..8408c8772b2 100644 --- a/include/llvm/IR/InstrTypes.h +++ b/include/llvm/IR/InstrTypes.h @@ -758,7 +758,7 @@ public: 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 @@ using ConstOperandBundleDef = OperandBundleDefT; /// 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/include/llvm/IR/Instruction.h b/include/llvm/IR/Instruction.h index a85353ff902..a03eac0ad40 100644 --- a/include/llvm/IR/Instruction.h +++ b/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 @@ class Instruction : public User, 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 @@ protected: // 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/include/llvm/IR/Instructions.h b/include/llvm/IR/Instructions.h index 7119b1392d2..0afc585dfbe 100644 --- a/include/llvm/IR/Instructions.h +++ b/include/llvm/IR/Instructions.h @@ -60,9 +60,12 @@ class LLVMContext; 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 @@ private: /// 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 @@ private: /// 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 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(StoreInst, Value) /// 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); @@ -543,11 +549,18 @@ public: return User::operator new(s, 3); } - using VolatileField = Bitfield::Element; // Next bit:1 - using WeakField = Bitfield::Element; // Next bit:2 - using SuccessOrderingField = AtomicOrderingBitfieldElement<2>; // Next bit:5 - using FailureOrderingField = AtomicOrderingBitfieldElement<5>; // Next bit:8 - using AlignmentField = AlignmentBitfieldElement<8>; // Next bit:13 + using VolatileField = BoolBitfieldElementT<0>; + using WeakField = BoolBitfieldElementT; + using SuccessOrderingField = + AtomicOrderingBitfieldElementT; + using FailureOrderingField = + AtomicOrderingBitfieldElementT; + using AlignmentField = + AlignmentBitfieldElementT; + static_assert( + Bitfield::areContiguous(), + "Bitfields must be contiguous"); /// Return the alignment of the memory that is being allocated by the /// instruction. @@ -755,10 +768,14 @@ public: return User::operator new(s, 2); } - using VolatileField = Bitfield::Element; // Next bit:1 - using AtomicOrderingField = AtomicOrderingBitfieldElement<1>; // Next bit:4 - using OperationField = BinOpBitfieldElement<4>; // Next bit:8 - using AlignmentField = AlignmentBitfieldElement<8>; // Next bit:13 + using VolatileField = BoolBitfieldElementT<0>; + using AtomicOrderingField = + AtomicOrderingBitfieldElementT; + using OperationField = BinOpBitfieldElement; + using AlignmentField = AlignmentBitfieldElementT; + static_assert(Bitfield::areContiguous(), + "Bitfields must be contiguous"); BinOp getOperation() const { return getSubclassData(); } @@ -1591,6 +1608,9 @@ public: }; using TailCallKindField = Bitfield::Element; + static_assert( + Bitfield::areContiguous(), + "Bitfields must be contiguous"); TailCallKind getTailCallKind() const { return getSubclassData(); @@ -2754,7 +2774,7 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(PHINode, Value) /// 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. @@ -4125,7 +4145,7 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ResumeInst, Value) // 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. @@ -4474,7 +4494,8 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CatchReturnInst, Value) //===----------------------------------------------------------------------===// 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/unittests/ADT/BitFieldsTest.cpp b/unittests/ADT/BitFieldsTest.cpp index 759c1839499..3062d5d7f29 100644 --- a/unittests/ADT/BitFieldsTest.cpp +++ b/unittests/ADT/BitFieldsTest.cpp @@ -192,6 +192,18 @@ TEST(BitfieldsTest, isOverlapping) { 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;