1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 10:42:39 +01:00

[Bitfields][NFC] Make sure bitfields are contiguous

Differential Revision: https://reviews.llvm.org/D83202
This commit is contained in:
Guillaume Chatelet 2020-07-07 14:35:12 +00:00
parent b9d820cbde
commit a3a41cd01b
5 changed files with 86 additions and 33 deletions

View File

@ -228,6 +228,7 @@ struct Bitfield {
static constexpr unsigned Bits = Size; static constexpr unsigned Bits = Size;
static constexpr unsigned FirstBit = Offset; static constexpr unsigned FirstBit = Offset;
static constexpr unsigned LastBit = Shift + Bits - 1; static constexpr unsigned LastBit = Shift + Bits - 1;
static constexpr unsigned NextBit = Shift + Bits;
private: private:
template <typename, typename> friend struct bitfields_details::Impl; template <typename, typename> friend struct bitfields_details::Impl;
@ -275,6 +276,12 @@ struct Bitfield {
template <typename A, typename B> static constexpr bool isOverlapping() { template <typename A, typename B> static constexpr bool isOverlapping() {
return A::LastBit >= B::FirstBit && B::LastBit >= A::FirstBit; return A::LastBit >= B::FirstBit && B::LastBit >= A::FirstBit;
} }
template <typename A> static constexpr bool areContiguous() { return true; }
template <typename A, typename B, typename... Others>
static constexpr bool areContiguous() {
return A::NextBit == B::FirstBit && areContiguous<B, Others...>();
}
}; };
} // namespace llvm } // namespace llvm

View File

@ -758,7 +758,7 @@ public:
BAD_ICMP_PREDICATE = ICMP_SLE + 1 BAD_ICMP_PREDICATE = ICMP_SLE + 1
}; };
using PredicateField = using PredicateField =
Bitfield::Element<Predicate, 0, 6, LAST_ICMP_PREDICATE>; // Next bit:6 Bitfield::Element<Predicate, 0, 6, LAST_ICMP_PREDICATE>;
protected: protected:
CmpInst(Type *ty, Instruction::OtherOps op, Predicate pred, CmpInst(Type *ty, Instruction::OtherOps op, Predicate pred,
@ -1096,12 +1096,16 @@ using ConstOperandBundleDef = OperandBundleDefT<const Value *>;
/// subclass requires. Note that accessing the end of the argument list isn't /// subclass requires. Note that accessing the end of the argument list isn't
/// as cheap as most other operations on the base class. /// as cheap as most other operations on the base class.
class CallBase : public Instruction { class CallBase : public Instruction {
// The first two bits are reserved by CallInst for fast retrieving,
using CallInstReservedField = Bitfield::Element<unsigned, 0, 2>; // Next bit:2
using CallingConvField = Bitfield::Element<CallingConv::ID, 2, 10,
CallingConv::MaxID>; // Next bit:12
protected: protected:
// The first two bits are reserved by CallInst for fast retrieval,
using CallInstReservedField = Bitfield::Element<unsigned, 0, 2>;
using CallingConvField =
Bitfield::Element<CallingConv::ID, CallInstReservedField::NextBit, 10,
CallingConv::MaxID>;
static_assert(
Bitfield::areContiguous<CallInstReservedField, CallingConvField>(),
"Bitfields must be contiguous");
/// The last operand is the called operand. /// The last operand is the called operand.
static constexpr int CalledOperandOpEndIdx = -1; static constexpr int CalledOperandOpEndIdx = -1;

View File

@ -23,6 +23,7 @@
#include "llvm/IR/SymbolTableListTraits.h" #include "llvm/IR/SymbolTableListTraits.h"
#include "llvm/IR/User.h" #include "llvm/IR/User.h"
#include "llvm/IR/Value.h" #include "llvm/IR/Value.h"
#include "llvm/Support/AtomicOrdering.h"
#include "llvm/Support/Casting.h" #include "llvm/Support/Casting.h"
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
@ -53,7 +54,7 @@ class Instruction : public User,
protected: protected:
// The 15 first bits of `Value::SubclassData` are available for subclasses of // The 15 first bits of `Value::SubclassData` are available for subclasses of
// `Instruction` to use. // `Instruction` to use.
using OpaqueField = Bitfield::Element<uint16_t, 0, 15>; // Next bit:15 using OpaqueField = Bitfield::Element<uint16_t, 0, 15>;
// Template alias so that all Instruction storing alignment use the same // Template alias so that all Instruction storing alignment use the same
// definiton. // definiton.
@ -61,10 +62,18 @@ protected:
// 2^29. We store them as Log2(Alignment), so we need 5 bits to encode the 30 // 2^29. We store them as Log2(Alignment), so we need 5 bits to encode the 30
// possible values. // possible values.
template <unsigned Offset> template <unsigned Offset>
using AlignmentBitfieldElement = using AlignmentBitfieldElementT =
typename Bitfield::Element<unsigned, Offset, 5, typename Bitfield::Element<unsigned, Offset, 5,
Value::MaxAlignmentExponent>; Value::MaxAlignmentExponent>;
template <unsigned Offset>
using BoolBitfieldElementT = typename Bitfield::Element<bool, Offset, 1>;
template <unsigned Offset>
using AtomicOrderingBitfieldElementT =
typename Bitfield::Element<AtomicOrdering, Offset, 3,
AtomicOrdering::LAST>;
private: private:
// The last bit is used to store whether the instruction has metadata attached // The last bit is used to store whether the instruction has metadata attached
// or not. // or not.

View File

@ -60,9 +60,12 @@ class LLVMContext;
class AllocaInst : public UnaryInstruction { class AllocaInst : public UnaryInstruction {
Type *AllocatedType; Type *AllocatedType;
using AlignmentField = AlignmentBitfieldElement<0>; // Next bit:5 using AlignmentField = AlignmentBitfieldElementT<0>;
using UsedWithInAllocaField = Bitfield::Element<bool, 5, 1>; // Next bit:6 using UsedWithInAllocaField = BoolBitfieldElementT<AlignmentField::NextBit>;
using SwiftErrorField = Bitfield::Element<bool, 6, 1>; // Next bit:7 using SwiftErrorField = BoolBitfieldElementT<UsedWithInAllocaField::NextBit>;
static_assert(Bitfield::areContiguous<AlignmentField, UsedWithInAllocaField,
SwiftErrorField>(),
"Bitfields must be contiguous");
protected: protected:
// Note: Instruction needs to be a friend here to call cloneImpl. // 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 /// An instruction for reading from memory. This uses the SubclassData field in
/// Value to store whether or not the load is volatile. /// Value to store whether or not the load is volatile.
class LoadInst : public UnaryInstruction { class LoadInst : public UnaryInstruction {
using VolatileField = Bitfield::Element<bool, 0, 1>; // Next bit:1 using VolatileField = BoolBitfieldElementT<0>;
using AlignmentField = AlignmentBitfieldElement<1>; // Next bit:6 using AlignmentField = AlignmentBitfieldElementT<VolatileField::NextBit>;
using OrderingField = Bitfield::Element<AtomicOrdering, 6, 3, using OrderingField = AtomicOrderingBitfieldElementT<AlignmentField::NextBit>;
AtomicOrdering::LAST>; // Next bit:9 static_assert(
Bitfield::areContiguous<VolatileField, AlignmentField, OrderingField>(),
"Bitfields must be contiguous");
void AssertOK(); void AssertOK();
@ -295,10 +300,12 @@ private:
/// An instruction for storing to memory. /// An instruction for storing to memory.
class StoreInst : public Instruction { class StoreInst : public Instruction {
using VolatileField = Bitfield::Element<bool, 0, 1>; // Next bit:1 using VolatileField = BoolBitfieldElementT<0>;
using AlignmentField = AlignmentBitfieldElement<1>; // Next bit:6 using AlignmentField = AlignmentBitfieldElementT<VolatileField::NextBit>;
using OrderingField = Bitfield::Element<AtomicOrdering, 6, 3, using OrderingField = AtomicOrderingBitfieldElementT<AlignmentField::NextBit>;
AtomicOrdering::LAST>; // Next bit:9 static_assert(
Bitfield::areContiguous<VolatileField, AlignmentField, OrderingField>(),
"Bitfields must be contiguous");
void AssertOK(); void AssertOK();
@ -434,8 +441,7 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(StoreInst, Value)
/// An instruction for ordering other memory operations. /// An instruction for ordering other memory operations.
class FenceInst : public Instruction { class FenceInst : public Instruction {
using OrderingField = Bitfield::Element<AtomicOrdering, 1, 3, using OrderingField = AtomicOrderingBitfieldElementT<0>;
AtomicOrdering::LAST>; // Next bit:4
void Init(AtomicOrdering Ordering, SyncScope::ID SSID); void Init(AtomicOrdering Ordering, SyncScope::ID SSID);
@ -543,11 +549,18 @@ public:
return User::operator new(s, 3); return User::operator new(s, 3);
} }
using VolatileField = Bitfield::Element<bool, 0, 1>; // Next bit:1 using VolatileField = BoolBitfieldElementT<0>;
using WeakField = Bitfield::Element<bool, 1, 1>; // Next bit:2 using WeakField = BoolBitfieldElementT<VolatileField::NextBit>;
using SuccessOrderingField = AtomicOrderingBitfieldElement<2>; // Next bit:5 using SuccessOrderingField =
using FailureOrderingField = AtomicOrderingBitfieldElement<5>; // Next bit:8 AtomicOrderingBitfieldElementT<WeakField::NextBit>;
using AlignmentField = AlignmentBitfieldElement<8>; // Next bit:13 using FailureOrderingField =
AtomicOrderingBitfieldElementT<SuccessOrderingField::NextBit>;
using AlignmentField =
AlignmentBitfieldElementT<FailureOrderingField::NextBit>;
static_assert(
Bitfield::areContiguous<VolatileField, WeakField, SuccessOrderingField,
FailureOrderingField, AlignmentField>(),
"Bitfields must be contiguous");
/// Return the alignment of the memory that is being allocated by the /// Return the alignment of the memory that is being allocated by the
/// instruction. /// instruction.
@ -755,10 +768,14 @@ public:
return User::operator new(s, 2); return User::operator new(s, 2);
} }
using VolatileField = Bitfield::Element<bool, 0, 1>; // Next bit:1 using VolatileField = BoolBitfieldElementT<0>;
using AtomicOrderingField = AtomicOrderingBitfieldElement<1>; // Next bit:4 using AtomicOrderingField =
using OperationField = BinOpBitfieldElement<4>; // Next bit:8 AtomicOrderingBitfieldElementT<VolatileField::NextBit>;
using AlignmentField = AlignmentBitfieldElement<8>; // Next bit:13 using OperationField = BinOpBitfieldElement<AtomicOrderingField::NextBit>;
using AlignmentField = AlignmentBitfieldElementT<OperationField::NextBit>;
static_assert(Bitfield::areContiguous<VolatileField, AtomicOrderingField,
OperationField, AlignmentField>(),
"Bitfields must be contiguous");
BinOp getOperation() const { return getSubclassData<OperationField>(); } BinOp getOperation() const { return getSubclassData<OperationField>(); }
@ -1591,6 +1608,9 @@ public:
}; };
using TailCallKindField = Bitfield::Element<TailCallKind, 0, 2, TCK_LAST>; using TailCallKindField = Bitfield::Element<TailCallKind, 0, 2, TCK_LAST>;
static_assert(
Bitfield::areContiguous<TailCallKindField, CallBase::CallingConvField>(),
"Bitfields must be contiguous");
TailCallKind getTailCallKind() const { TailCallKind getTailCallKind() const {
return getSubclassData<TailCallKindField>(); return getSubclassData<TailCallKindField>();
@ -2754,7 +2774,7 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(PHINode, Value)
/// cleanup. /// cleanup.
/// ///
class LandingPadInst : public Instruction { class LandingPadInst : public Instruction {
using CleanupField = Bitfield::Element<bool, 0, 1>; using CleanupField = BoolBitfieldElementT<0>;
/// The number of operands actually allocated. NumOperands is /// The number of operands actually allocated. NumOperands is
/// the number actually in use. /// the number actually in use.
@ -4125,7 +4145,7 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ResumeInst, Value)
// CatchSwitchInst Class // CatchSwitchInst Class
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
class CatchSwitchInst : public Instruction { class CatchSwitchInst : public Instruction {
using UnwindDestField = Bitfield::Element<unsigned, 0, 1>; // Next bit:1 using UnwindDestField = BoolBitfieldElementT<0>;
/// The number of operands actually allocated. NumOperands is /// The number of operands actually allocated. NumOperands is
/// the number actually in use. /// the number actually in use.
@ -4474,7 +4494,8 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CatchReturnInst, Value)
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
class CleanupReturnInst : public Instruction { class CleanupReturnInst : public Instruction {
using UnwindDestField = Bitfield::Element<unsigned, 0, 1>; // Next bit:1 using UnwindDestField = BoolBitfieldElementT<0>;
private: private:
CleanupReturnInst(const CleanupReturnInst &RI); CleanupReturnInst(const CleanupReturnInst &RI);
CleanupReturnInst(Value *CleanupPad, BasicBlock *UnwindBB, unsigned Values, CleanupReturnInst(Value *CleanupPad, BasicBlock *UnwindBB, unsigned Values,

View File

@ -192,6 +192,18 @@ TEST(BitfieldsTest, isOverlapping) {
EXPECT_FALSE((Bitfield::isOverlapping<C, D>())); EXPECT_FALSE((Bitfield::isOverlapping<C, D>()));
} }
TEST(BitfieldsTest, areContiguous) {
using A = Bitfield::Element<unsigned, 0, 1>; // Next Bit:1
using B = Bitfield::Element<unsigned, 1, 4>; // Next Bit:5
using C = Bitfield::Element<unsigned, 5, 3>; // Next Bit:8
EXPECT_TRUE((Bitfield::areContiguous<A, B>()));
EXPECT_TRUE((Bitfield::areContiguous<A, B, C>()));
EXPECT_FALSE((Bitfield::areContiguous<A, C>()));
EXPECT_FALSE((Bitfield::areContiguous<A, A>()));
EXPECT_FALSE((Bitfield::areContiguous<B, A>()));
}
TEST(BitfieldsTest, FullUint64) { TEST(BitfieldsTest, FullUint64) {
uint64_t Storage = 0; uint64_t Storage = 0;
using Value = Bitfield::Element<uint64_t, 0, 64>; using Value = Bitfield::Element<uint64_t, 0, 64>;