Index: llvm/include/llvm/ADT/BitField.h =================================================================== --- /dev/null +++ llvm/include/llvm/ADT/BitField.h @@ -0,0 +1,278 @@ +//===- llvm/ADT/BitField.h - Safe Portable Bit-field ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_BITFIELD_H +#define LLVM_ADT_BITFIELD_H + +#include "llvm/ADT/STLExtras.h" + +namespace llvm { + +template ::value || + std::is_enum::value)>::type> +class BitField { + template + using enable_if_underlying_integral_t = + typename std::enable_if::value || + std::is_enum::value>::type; + + static constexpr bool is_bool_v = std::is_same::value; + + using TVal = typename std::conditional< + std::is_enum::value, std::underlying_type, + std::conditional>::type::type; + + static constexpr bool is_signed_v = std::is_signed::value; + + using TInt = typename smallest_integral::type; + + using TSInt = typename std::make_signed::type; + using TUInt = typename std::make_unsigned::type; + + using TNative = typename std::conditional< + sizeof(TInt) < sizeof(int), + typename std::conditional::type, + TInt>::type; + + using TSNative = typename std::make_signed::type; + using TUNative = typename std::make_unsigned::type; + + using TCast = typename std::conditional::type; + + static constexpr TUInt Mask = bit_maskof(); + TInt Value; + + template static void verify(T2 V) { + if (Size < bit_sizeof(V)) { + if (is_signed_v) { + assert(int64_t(V) >= (int64_t(-1) << (Size - 1)) && + int64_t(V) <= ~(int64_t(-1) << (Size - 1)) && + "Value does not fit into bit-field!"); + } else + assert(uint64_t(V) <= ~(~uint64_t(0) << Size) && + "Value does not fit into bit-field!"); + } + } + + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField &set(TNative N) { + Value = TInt((TUNative(Value) & ~TUNative(Mask)) | + ((TUNative(N) << Offset) & TUNative(Mask))); + return *this; + } + + LLVM_ATTRIBUTE_ALWAYS_INLINE static TUNative get(TUNative V) { + return (V & TUNative(Mask)) >> Offset; + } + + LLVM_ATTRIBUTE_ALWAYS_INLINE static TSNative get(TSNative V) { + return (V << (bit_sizeof() - (Offset + Size))) >> + (bit_sizeof() - Size); + } + +public: + template > + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField &operator=(T2 RHS) { + verify(RHS); + return set(TNative(RHS)); + } + + template > + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField &operator+=(T2 RHS) { + TUNative N = TUNative(RHS) << Offset; + TUNative V = TUNative(Value); + TUNative Rest = V & ~TUNative(Mask); + Value = TInt(((V + N) & TUNative(Mask)) | Rest); + return *this; + } + + template > + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField &operator-=(T2 RHS) { + TUNative N = TUNative(RHS) << Offset; + TUNative V = TUNative(Value); + TUNative Rest = V & ~TUNative(Mask); + Value = TInt(((V - N) & TUNative(Mask)) | Rest); + return *this; + } + + template > + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField &operator*=(T2 RHS) { + TUNative N = TUNative(RHS); + TUNative V = TUNative(Value); + TUNative Rest = V & ~TUNative(Mask); + Value = TInt(((V * N) & TUNative(Mask)) | Rest); + return *this; + } + + template > + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField &operator/=(T2 RHS) { + TUNative N = TUNative(RHS); + TUNative V = TUNative(Value); + TUNative Rest = V & ~TUNative(Mask); + Value = TInt(((V / N) & TUNative(Mask)) | Rest); + return *this; + } + + template > + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField &operator%=(T2 RHS) { + return set(*this % TNative(RHS)); + } + + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField operator~() const { + return {TInt(TUNative(Value) ^ TUNative(Mask))}; + } + + template > + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField &operator&=(T2 RHS) { + TUNative N = (TUNative(RHS) << Offset) | ~TUNative(Mask); + Value = TInt(TUNative(Value) & N); + return *this; + } + + template > + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField &operator|=(T2 RHS) { + TUNative N = (TUNative(RHS) << Offset) & TUNative(Mask); + Value = TInt(TUNative(Value) | N); + return *this; + } + + template > + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField &operator^=(T2 RHS) { + TUNative N = (TUNative(RHS) << Offset) & TUNative(Mask); + Value = TInt(TUNative(Value) ^ N); + return *this; + } + + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField &operator<<=(size_t BitCount) { + TUNative V = TUNative(Value); + TUNative Rest = V & ~TUNative(Mask); + Value = TInt((((V & TUNative(Mask)) << BitCount) & TUNative(Mask)) | Rest); + return *this; + } + + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField &operator>>=(size_t BitCount) { + TUNative V = TUNative(Value); + TUNative Rest = V & ~TUNative(Mask); + Value = TInt((((V & TUNative(Mask)) >> BitCount) & TUNative(Mask)) | Rest); + return *this; + } + + LLVM_ATTRIBUTE_ALWAYS_INLINE operator TCast() const { + return TCast(get(TNative(Value))); + } + LLVM_ATTRIBUTE_ALWAYS_INLINE explicit operator bool() const { + return Value & TInt(Mask); + } + + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField &operator++() { return *this += 1; } + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField operator++(int) { + BitField Tmp = *this; + ++*this; + return Tmp; + } + + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField &operator--() { return *this -= 1; } + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField operator--(int) { + BitField Tmp = *this; + --*this; + return Tmp; + } +}; + +template class BitField { + using TInt = typename smallest_integral::type; + + using TNative = typename std::conditional::type; + + static constexpr TInt Mask = bit_maskof(); + TInt Value; + +public: + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField &operator=(bool RHS) { + Value = TInt((TNative(Value) & ~TNative(Mask)) | (TNative(RHS) << Offset)); + return *this; + } + + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField &operator+=(bool RHS) { + return operator|=(RHS); + } + + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField &operator-=(bool RHS) { + return operator^=(RHS); + } + + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField &operator*=(bool RHS) { + return operator&=(RHS); + } + + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField operator~() const { + return {TInt(TNative(Value) ^ TNative(Mask))}; + } + + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField &operator&=(bool RHS) { + Value = TInt(TNative(Value) & (TNative(RHS) << Offset)); + return *this; + } + + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField &operator|=(bool RHS) { + Value = TInt(TNative(Value) | (TNative(RHS) << Offset)); + return *this; + } + + LLVM_ATTRIBUTE_ALWAYS_INLINE BitField &operator^=(bool RHS) { + Value = TInt(TNative(Value) ^ (TNative(RHS) << Offset)); + return *this; + } + + LLVM_ATTRIBUTE_ALWAYS_INLINE bool operator==(bool RHS) const { + return static_cast(*this) == RHS; + } + + LLVM_ATTRIBUTE_ALWAYS_INLINE bool operator!=(bool RHS) const { + return static_cast(*this) != RHS; + } + + LLVM_ATTRIBUTE_ALWAYS_INLINE explicit operator bool() const { + return Value & TInt(Mask); + } + + LLVM_ATTRIBUTE_ALWAYS_INLINE operator uint8_t() const { + return uint8_t((TNative(Value) >> Offset) & TNative(1)); + } +}; + + +template +struct TypeBitTraits> { + static constexpr unsigned Low = Offset; + static constexpr unsigned Count = Sz; +}; + + +#define BEGIN_PACKED_BITFIELDS(Bits) \ + union { \ + ::llvm::smallest_integral::type PackedBitfieldsData = 0; \ + ::llvm::BitField<0, ::llvm::bit_sizeof() + +#define ADD_PACKED_BITFIELD(Type, Bits, Name) \ + * 0 + Bits, Type > Name; \ + ::llvm::BitField<(::llvm::bit_offsetof() + \ + ::llvm::bit_sizeof()), \ + (::llvm::bit_sizeof() - \ + (::llvm::bit_offsetof() + \ + ::llvm::bit_sizeof())) + +#define END_PACKED_BITFIELDS() \ + , decltype(PackedBitfieldsData)> SubclassData; \ + } + +} // end namespace llvm + +#endif // LLVM_ADT_BITFIELD_H Index: llvm/include/llvm/ADT/STLExtras.h =================================================================== --- llvm/include/llvm/ADT/STLExtras.h +++ llvm/include/llvm/ADT/STLExtras.h @@ -1018,6 +1018,41 @@ std::is_base_of::value && are_base_of::value; }; +template struct TypeBitTraits { + static constexpr unsigned Low = 0; + static constexpr unsigned Count = sizeof(T) * CHAR_BIT; +}; + +template constexpr inline size_t bit_sizeof() { + return TypeBitTraits::Count; +} +template constexpr inline size_t bit_sizeof(const T &) { + return bit_sizeof(); +} + +template constexpr inline size_t bit_offsetof() { + return TypeBitTraits::Low; +} +template constexpr inline size_t bit_offsetof(const T &) { + return bit_offsetof(); +} + +template +constexpr inline + typename smallest_integral() + bit_sizeof()>::type + bit_maskof() { + constexpr + typename smallest_integral() + bit_sizeof()>::type + One = 1; + return ((One << bit_sizeof()) - One) << bit_offsetof(); +} +template +constexpr inline + typename smallest_integral() + bit_sizeof()>::type + bit_maskof(const T &) { + return bit_maskof(); +} + //===----------------------------------------------------------------------===// // Extra additions for arrays //===----------------------------------------------------------------------===// Index: llvm/include/llvm/ADT/SubclassData.h =================================================================== --- /dev/null +++ llvm/include/llvm/ADT/SubclassData.h @@ -0,0 +1,82 @@ +//===-- llvm/ADT/SubclassData.h ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_SUBCLASSDATA_H +#define LLVM_ADT_SUBCLASSDATA_H + +#include "llvm/ADT/BitField.h" + +#define DECLARE_SUBCLASS_DATA(Class) \ + struct Class##SubclassDataImpl { \ + protected: \ + struct FINAL_LIMITS { \ + static constexpr int Begin = \ + ::llvm::bit_offsetof(); \ + static constexpr int End = \ + Begin + ::llvm::bit_sizeof(); \ + static_assert(Begin <= End, "Invalid " #Class " Subclass Data Size!"); \ + }; \ + }; \ + LLVM_ATTRIBUTE_ALWAYS_INLINE auto &Class##SubclassData() { \ + return reinterpret_cast(SubclassData); \ + } \ + LLVM_ATTRIBUTE_ALWAYS_INLINE auto &Class##SubclassData() const { \ + return reinterpret_cast(SubclassData); \ + } + + +#define BEGIN_SUBCLASS_DATA(Owner, Class) \ + using Owner##SubclassDataBase = Owner##SubclassDataImpl; \ + struct Owner##SubclassDataImpl : private Owner##SubclassDataBase { \ + union Fields { \ + private: \ + friend struct Class::Owner##SubclassDataImpl; \ + typedef Class::Owner##SubclassDataBase::FINAL_LIMITS + + +#define ADD_SUBCLASS_BITFIELD(Owner, Type, Bits, Name) \ + PREV_##Name; \ + \ + public: \ + llvm::BitField< \ + ((Bits) < 0 ? (PREV_##Name::End + Bits) : PREV_##Name::Begin), \ + ((Bits) < 0 ? -(Bits) : (Bits)), Type> \ + Name; \ + \ + private: \ + typedef struct NEXT_##Name { \ + static constexpr int Begin = \ + PREV_##Name::Begin + ((Bits) < 0 ? 0 : (Bits)); \ + \ + static constexpr int End = \ + PREV_##Name::End + ((Bits) < 0 ? (Bits) : 0); \ + \ + static_assert(Begin <= End, "Not enough bits for field " #Name " in " \ + #Owner " Subclass Data!"); \ + } + + +#define END_SUBCLASS_DATA(Owner) \ + END_LIMITS; \ + }; \ + protected: \ + using FINAL_LIMITS = Fields::END_LIMITS; \ + }; \ + LLVM_ATTRIBUTE_ALWAYS_INLINE auto &Owner##SubclassData() { \ + return reinterpret_cast( \ + Owner::Owner##SubclassData()); \ + } \ + LLVM_ATTRIBUTE_ALWAYS_INLINE auto &Owner##SubclassData() const { \ + return reinterpret_cast( \ + Owner::Owner##SubclassData()); \ + } + +#define TYPEOF_SUBCLASS_BITFIELD(Owner, Name) \ + decltype(Owner##SubclassDataImpl::Fields::Name) + +#endif // LLVM_ADT_SUBCLASSDATA_H Index: llvm/include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -434,7 +434,7 @@ }; /// OverflowingBinaryOperatorOptionalFlags - Flags for serializing -/// OverflowingBinaryOperator's SubclassOptionalData contents. +/// OverflowingBinaryOperator's Subclass Data contents. enum OverflowingBinaryOperatorOptionalFlags { OBO_NO_UNSIGNED_WRAP = 0, OBO_NO_SIGNED_WRAP = 1 @@ -455,7 +455,7 @@ }; /// PossiblyExactOperatorOptionalFlags - Flags for serializing -/// PossiblyExactOperator's SubclassOptionalData contents. +/// PossiblyExactOperator's Subclass Data contents. enum PossiblyExactOperatorOptionalFlags { PEO_EXACT = 0 }; /// Encoded AtomicOrdering values. Index: llvm/include/llvm/IR/BasicBlock.h =================================================================== --- llvm/include/llvm/IR/BasicBlock.h +++ llvm/include/llvm/IR/BasicBlock.h @@ -66,6 +66,11 @@ InstListType InstList; Function *Parent; + BEGIN_VALUE_SUBCLASS_DATA(BasicBlock) + ADD_VALUE_SUBCLASS_BITFIELD(int, 8, BlockAddressRefCount) + ADD_VALUE_SUBCLASS_BITFIELD(unsigned, -32, Ordinal) + END_VALUE_SUBCLASS_DATA() + void setParent(Function *parent); /// Constructor. @@ -393,7 +398,9 @@ /// Returns true if there are any uses of this basic block other than /// direct branches, switches, etc. to it. - bool hasAddressTaken() const { return getSubclassDataFromValue() != 0; } + bool hasAddressTaken() const { + return ValueSubclassData().BlockAddressRefCount != 0; + } /// Update all phi nodes in this basic block to refer to basic block \p New /// instead of basic block \p Old. @@ -435,16 +442,10 @@ /// This is almost always 0, sometimes one possibly, but almost never 2, and /// inconceivably 3 or more. void AdjustBlockAddressRefCount(int Amt) { - setValueSubclassData(getSubclassDataFromValue()+Amt); - assert((int)(signed char)getSubclassDataFromValue() >= 0 && + ValueSubclassData().BlockAddressRefCount += Amt; + assert(ValueSubclassData().BlockAddressRefCount >= 0 && "Refcount wrap-around"); } - - /// Shadow Value::setValueSubclassData with a private forwarding method so - /// that any future subclasses cannot accidentally use it. - void setValueSubclassData(unsigned short D) { - Value::setValueSubclassData(D); - } }; // Create wrappers for C Binding types (see CBindingWrapping.h). Index: llvm/include/llvm/IR/Constants.h =================================================================== --- llvm/include/llvm/IR/Constants.h +++ llvm/include/llvm/IR/Constants.h @@ -885,7 +885,7 @@ /// /// This class uses the standard Instruction opcodes to define the various /// constant expressions. The Opcode field for the ConstantExpr class is -/// maintained in the Value::SubclassData field. +/// maintained in the ValueSubclassData::Opcode field. class ConstantExpr : public Constant { friend struct ConstantExprKeyType; friend class Constant; @@ -894,10 +894,15 @@ Value *handleOperandChangeImpl(Value *From, Value *To); protected: + BEGIN_VALUE_SUBCLASS_DATA(ConstantExpr) + ADD_VALUE_SUBCLASS_BITFIELD(unsigned, 8, Opcode) + ADD_VALUE_SUBCLASS_OPTIONALDATA() + END_VALUE_SUBCLASS_DATA() + ConstantExpr(Type *ty, unsigned Opcode, Use *Ops, unsigned NumOps) : Constant(ty, ConstantExprVal, Ops, NumOps) { - // Operation type (an Instruction opcode) is stored as the SubclassData. - setValueSubclassData(Opcode); + // Operation type (an Instruction opcode). + ValueSubclassData().Opcode = Opcode; } public: @@ -1207,7 +1212,7 @@ Type *OnlyIfReducedTy = nullptr); /// Return the opcode at the root of this constant expression - unsigned getOpcode() const { return getSubclassDataFromValue(); } + unsigned getOpcode() const { return ValueSubclassData().Opcode; } /// Return the ICMP or FCMP predicate value. Assert if this is not an ICMP or /// FCMP constant expression. @@ -1257,13 +1262,6 @@ static bool classof(const Value *V) { return V->getValueID() == ConstantExprVal; } - -private: - // Shadow Value::setValueSubclassData with a private forwarding method so that - // subclasses cannot accidentally use it. - void setValueSubclassData(unsigned short D) { - Value::setValueSubclassData(D); - } }; template <> Index: llvm/include/llvm/IR/DerivedTypes.h =================================================================== --- llvm/include/llvm/IR/DerivedTypes.h +++ llvm/include/llvm/IR/DerivedTypes.h @@ -40,9 +40,13 @@ class IntegerType : public Type { friend class LLVMContextImpl; + BEGIN_TYPE_SUBCLASS_DATA(IntegerType) + ADD_TYPE_SUBCLASS_BITFIELD(unsigned, 24, NumBits) + END_TYPE_SUBCLASS_DATA() + protected: explicit IntegerType(LLVMContext &C, unsigned NumBits) : Type(C, IntegerTyID){ - setSubclassData(NumBits); + TypeSubclassData().NumBits = NumBits; } public: @@ -50,7 +54,7 @@ enum { MIN_INT_BITS = 1, ///< Minimum number of bits that can be specified MAX_INT_BITS = (1<<24)-1 ///< Maximum number of bits that can be specified - ///< Note that bit width is stored in the Type classes SubclassData field + ///< Note that bit width is stored in the TypeSubclassData::NumBits field ///< which has 24 bits. This yields a maximum bit width of 16,777,215 ///< bits. }; @@ -68,7 +72,7 @@ } /// Get the number of bits in this IntegerType - unsigned getBitWidth() const { return getSubclassData(); } + unsigned getBitWidth() const { return TypeSubclassData().NumBits; } /// Return a bitmask with ones set for all of the bits that can be set by an /// unsigned version of this type. This is 0xFF for i8, 0xFFFF for i16, etc. @@ -108,6 +112,10 @@ class FunctionType : public Type { FunctionType(Type *Result, ArrayRef Params, bool IsVarArgs); + BEGIN_TYPE_SUBCLASS_DATA(FunctionType) + ADD_TYPE_SUBCLASS_BITFIELD(bool, 1, IsVarArgs) + END_TYPE_SUBCLASS_DATA() + public: FunctionType(const FunctionType &) = delete; FunctionType &operator=(const FunctionType &) = delete; @@ -125,7 +133,7 @@ /// Return true if the specified type is valid as an argument type. static bool isValidArgumentType(Type *ArgTy); - bool isVarArg() const { return getSubclassData()!=0; } + bool isVarArg() const { return TypeSubclassData().IsVarArgs; } Type *getReturnType() const { return ContainedTys[0]; } using param_iterator = Type::subtype_iterator; @@ -238,13 +246,12 @@ class StructType : public CompositeType { StructType(LLVMContext &C) : CompositeType(C, StructTyID) {} - enum { - /// This is the contents of the SubClassData field. - SCDB_HasBody = 1, - SCDB_Packed = 2, - SCDB_IsLiteral = 4, - SCDB_IsSized = 8 - }; + BEGIN_TYPE_SUBCLASS_DATA(StructType) + ADD_TYPE_SUBCLASS_BITFIELD(bool, 1, HasBody) + ADD_TYPE_SUBCLASS_BITFIELD(bool, 1, Packed) + ADD_TYPE_SUBCLASS_BITFIELD(bool, 1, IsLiteral) + ADD_TYPE_SUBCLASS_BITFIELD(bool, 1, IsSized) + END_TYPE_SUBCLASS_DATA() /// For a named struct that actually has a name, this is a pointer to the /// symbol table entry (maintained by LLVMContext) for the struct. @@ -295,15 +302,15 @@ return llvm::StructType::get(Ctx, StructFields); } - bool isPacked() const { return (getSubclassData() & SCDB_Packed) != 0; } + bool isPacked() const { return TypeSubclassData().Packed; } /// Return true if this type is uniqued by structural equivalence, false if it /// is a struct definition. - bool isLiteral() const { return (getSubclassData() & SCDB_IsLiteral) != 0; } + bool isLiteral() const { return TypeSubclassData().IsLiteral; } /// Return true if this is a type with an identity that has no body specified /// yet. These prints as 'opaque' in .ll files. - bool isOpaque() const { return (getSubclassData() & SCDB_HasBody) == 0; } + bool isOpaque() const { return !TypeSubclassData().HasBody; } /// isSized - Return true if this is a sized type. bool isSized(SmallPtrSetImpl *Visited = nullptr) const; @@ -579,6 +586,10 @@ class PointerType : public Type { explicit PointerType(Type *ElType, unsigned AddrSpace); + BEGIN_TYPE_SUBCLASS_DATA(PointerType) + ADD_TYPE_SUBCLASS_BITFIELD(unsigned, 24, AddressSpace) + END_TYPE_SUBCLASS_DATA() + Type *PointeeTy; public: @@ -604,7 +615,9 @@ static bool isLoadableOrStorableType(Type *ElemTy); /// Return the address space of the Pointer type. - inline unsigned getAddressSpace() const { return getSubclassData(); } + inline unsigned getAddressSpace() const { + return TypeSubclassData().AddressSpace; + } /// Implement support type inquiry through isa, cast, and dyn_cast. static bool classof(const Type *T) { Index: llvm/include/llvm/IR/Function.h =================================================================== --- llvm/include/llvm/IR/Function.h +++ llvm/include/llvm/IR/Function.h @@ -76,23 +76,15 @@ SymTab; ///< Symbol table of args/instructions AttributeList AttributeSets; ///< Parameter attributes - /* - * Value::SubclassData - * - * bit 0 : HasLazyArguments - * bit 1 : HasPrefixData - * bit 2 : HasPrologueData - * bit 3 : HasPersonalityFn - * bits 4-13 : CallingConvention - * bits 14 : HasGC - * bits 15 : [reserved] - */ - - /// Bits from GlobalObject::GlobalObjectSubclassData. - enum { - /// Whether this function is materializable. - IsMaterializableBit = 0, - }; + BEGIN_VALUE_SUBCLASS_DATA(Function) + ADD_VALUE_SUBCLASS_BITFIELD(bool, 1, HasLazyArguments) + ADD_VALUE_SUBCLASS_BITFIELD(bool, 1, HasPrefixData) + ADD_VALUE_SUBCLASS_BITFIELD(bool, 1, HasPrologueData) + ADD_VALUE_SUBCLASS_BITFIELD(bool, 1, HasPersonalityFn) + ADD_VALUE_SUBCLASS_BITFIELD(bool, 1, HasGC) + ADD_VALUE_SUBCLASS_BITFIELD(bool, 1, IsMaterializable) + ADD_VALUE_SUBCLASS_BITFIELD(CallingConv::ID, 10, CallingConvention) + END_VALUE_SUBCLASS_DATA() friend class SymbolTableListTraits; @@ -101,9 +93,7 @@ /// needs it. The hasLazyArguments predicate returns true if the arg list /// hasn't been set up yet. public: - bool hasLazyArguments() const { - return getSubclassDataFromValue() & (1<<0); - } + bool hasLazyArguments() const { return ValueSubclassData().HasLazyArguments; } private: void CheckLazyArguments() const { @@ -175,14 +165,8 @@ /// arguments. bool isVarArg() const { return getFunctionType()->isVarArg(); } - bool isMaterializable() const { - return getGlobalObjectSubClassData() & (1 << IsMaterializableBit); - } - void setIsMaterializable(bool V) { - unsigned Mask = 1 << IsMaterializableBit; - setGlobalObjectSubClassData((~Mask & getGlobalObjectSubClassData()) | - (V ? Mask : 0u)); - } + bool isMaterializable() const { return ValueSubclassData().IsMaterializable; } + void setIsMaterializable(bool V) { ValueSubclassData().IsMaterializable = V; } /// getIntrinsicID - This method returns the ID number of the specified /// function, or Intrinsic::not_intrinsic if the function is not an @@ -210,13 +194,12 @@ /// calling convention of this function. The enum values for the known /// calling conventions are defined in CallingConv.h. CallingConv::ID getCallingConv() const { - return static_cast((getSubclassDataFromValue() >> 4) & - CallingConv::MaxID); + return ValueSubclassData().CallingConvention; } void setCallingConv(CallingConv::ID CC) { - auto ID = static_cast(CC); - assert(!(ID & ~CallingConv::MaxID) && "Unsupported calling convention"); - setValueSubclassData((getSubclassDataFromValue() & 0xc00f) | (ID << 4)); + assert(!(static_cast(CC) & ~CallingConv::MaxID) && + "Unsupported calling convention"); + ValueSubclassData().CallingConvention = CC; } /// Return the attribute list for this Function. @@ -351,9 +334,7 @@ /// hasGC/getGC/setGC/clearGC - The name of the garbage collection algorithm /// to use during code generation. - bool hasGC() const { - return getSubclassDataFromValue() & (1<<14); - } + bool hasGC() const { return ValueSubclassData().HasGC; } const std::string &getGC() const; void setGC(std::string Str); void clearGC(); @@ -740,27 +721,21 @@ bool arg_empty() const { return arg_size() == 0; } /// Check whether this function has a personality function. - bool hasPersonalityFn() const { - return getSubclassDataFromValue() & (1<<3); - } + bool hasPersonalityFn() const { return ValueSubclassData().HasPersonalityFn; } /// Get the personality function associated with this function. Constant *getPersonalityFn() const; void setPersonalityFn(Constant *Fn); /// Check whether this function has prefix data. - bool hasPrefixData() const { - return getSubclassDataFromValue() & (1<<1); - } + bool hasPrefixData() const { return ValueSubclassData().HasPrefixData; } /// Get the prefix data associated with this function. Constant *getPrefixData() const; void setPrefixData(Constant *PrefixData); /// Check whether this function has prologue data. - bool hasPrologueData() const { - return getSubclassDataFromValue() & (1<<2); - } + bool hasPrologueData() const { return ValueSubclassData().HasPrologueData; } /// Get the prologue data associated with this function. Constant *getPrologueData() const; @@ -845,13 +820,6 @@ private: void allocHungoffUselist(); template void setHungoffOperand(Constant *C); - - /// Shadow Value::setValueSubclassData with a private forwarding method so - /// that subclasses cannot accidentally use it. - void setValueSubclassData(unsigned short D) { - Value::setValueSubclassData(D); - } - void setValueSubclassDataBit(unsigned Bit, bool On); }; /// Check whether null pointer dereferencing is considered undefined behavior Index: llvm/include/llvm/IR/GlobalObject.h =================================================================== --- llvm/include/llvm/IR/GlobalObject.h +++ llvm/include/llvm/IR/GlobalObject.h @@ -47,33 +47,22 @@ LinkageTypes Linkage, const Twine &Name, unsigned AddressSpace = 0) : GlobalValue(Ty, VTy, Ops, NumOps, Linkage, Name, AddressSpace), - ObjComdat(nullptr) { - setGlobalValueSubClassData(0); - } + ObjComdat(nullptr) {} Comdat *ObjComdat; - enum { - LastAlignmentBit = 4, - HasMetadataHashEntryBit, - HasSectionHashEntryBit, - GlobalObjectBits, - }; - static const unsigned GlobalObjectSubClassDataBits = - GlobalValueSubClassDataBits - GlobalObjectBits; - -private: - static const unsigned AlignmentBits = LastAlignmentBit + 1; - static const unsigned AlignmentMask = (1 << AlignmentBits) - 1; - static const unsigned GlobalObjectMask = (1 << GlobalObjectBits) - 1; + BEGIN_GLOBALVALUE_SUBCLASS_DATA(GlobalObject) + ADD_GLOBALVALUE_SUBCLASS_BITFIELD(unsigned, 5, EncodedAlignment) + ADD_GLOBALVALUE_SUBCLASS_BITFIELD(bool, 1, HasMetadataHashEntry) + ADD_GLOBALVALUE_SUBCLASS_BITFIELD(bool, 1, HasSectionHashEntry) + END_GLOBALVALUE_SUBCLASS_DATA() public: GlobalObject(const GlobalObject &) = delete; unsigned getAlignment() const { - unsigned Data = getGlobalValueSubClassData(); - unsigned AlignmentData = Data & AlignmentMask; - MaybeAlign Align = decodeMaybeAlign(AlignmentData); + MaybeAlign Align = + decodeMaybeAlign(GlobalValueSubclassData().EncodedAlignment); return Align ? Align->value() : 0; } @@ -82,24 +71,12 @@ "Please use `void setAlignment(MaybeAlign Align)`"); void setAlignment(MaybeAlign Align); - unsigned getGlobalObjectSubClassData() const { - unsigned ValueData = getGlobalValueSubClassData(); - return ValueData >> GlobalObjectBits; - } - - void setGlobalObjectSubClassData(unsigned Val) { - unsigned OldData = getGlobalValueSubClassData(); - setGlobalValueSubClassData((OldData & GlobalObjectMask) | - (Val << GlobalObjectBits)); - assert(getGlobalObjectSubClassData() == Val && "representation error"); - } - /// Check if this global has a custom object file section. /// /// This is more efficient than calling getSection() and checking for an empty /// string. bool hasSection() const { - return getGlobalValueSubClassData() & (1 << HasSectionHashEntryBit); + return GlobalValueSubclassData().HasSectionHashEntry; } /// Get the custom section of this global if it has one. @@ -194,17 +171,11 @@ void clearMetadata(); private: - void setGlobalObjectFlag(unsigned Bit, bool Val) { - unsigned Mask = 1 << Bit; - setGlobalValueSubClassData((~Mask & getGlobalValueSubClassData()) | - (Val ? Mask : 0u)); - } - bool hasMetadataHashEntry() const { - return getGlobalValueSubClassData() & (1 << HasMetadataHashEntryBit); + return GlobalValueSubclassData().HasMetadataHashEntry; } void setHasMetadataHashEntry(bool HasEntry) { - setGlobalObjectFlag(HasMetadataHashEntryBit, HasEntry); + GlobalValueSubclassData().HasMetadataHashEntry = HasEntry; } StringRef getSectionImpl() const; Index: llvm/include/llvm/IR/GlobalValue.h =================================================================== --- llvm/include/llvm/IR/GlobalValue.h +++ llvm/include/llvm/IR/GlobalValue.h @@ -44,7 +44,7 @@ class GlobalValue : public Constant { public: /// An enumeration for the kinds of linkage for global values. - enum LinkageTypes { + enum LinkageTypes : unsigned { ExternalLinkage = 0,///< Externally visible function AvailableExternallyLinkage, ///< Available for inspection, not emission. LinkOnceAnyLinkage, ///< Keep one copy of function when linking (inline) @@ -59,64 +59,77 @@ }; /// An enumeration for the kinds of visibility of global values. - enum VisibilityTypes { + enum VisibilityTypes : unsigned { DefaultVisibility = 0, ///< The GV is visible HiddenVisibility, ///< The GV is hidden ProtectedVisibility ///< The GV is protected }; /// Storage classes of global values for PE targets. - enum DLLStorageClassTypes { + enum DLLStorageClassTypes : unsigned { DefaultStorageClass = 0, DLLImportStorageClass = 1, ///< Function to be imported from DLL DLLExportStorageClass = 2 ///< Function to be accessible from DLL. }; + enum ThreadLocalMode : unsigned { + NotThreadLocal = 0, + GeneralDynamicTLSModel, + LocalDynamicTLSModel, + InitialExecTLSModel, + LocalExecTLSModel + }; + + enum class UnnamedAddr : unsigned { + None, + Local, + Global, + }; + protected: GlobalValue(Type *Ty, ValueTy VTy, Use *Ops, unsigned NumOps, LinkageTypes Linkage, const Twine &Name, unsigned AddressSpace) : Constant(PointerType::get(Ty, AddressSpace), VTy, Ops, NumOps), - ValueType(Ty), Visibility(DefaultVisibility), - UnnamedAddrVal(unsigned(UnnamedAddr::None)), - DllStorageClass(DefaultStorageClass), ThreadLocal(NotThreadLocal), - HasLLVMReservedName(false), IsDSOLocal(false), HasPartition(false), - IntID((Intrinsic::ID)0U), Parent(nullptr) { + ValueType(Ty), IntID((Intrinsic::ID)0U), Parent(nullptr) { setLinkage(Linkage); setName(Name); } Type *ValueType; - static const unsigned GlobalValueSubClassDataBits = 16; + BEGIN_PACKED_BITFIELDS(32) + // The linkage of this global. + ADD_PACKED_BITFIELD(LinkageTypes, 4, Linkage) - // All bitfields use unsigned as the underlying type so that MSVC will pack - // them. - unsigned Linkage : 4; // The linkage of this global - unsigned Visibility : 2; // The visibility style of this global - unsigned UnnamedAddrVal : 2; // This value's address is not significant - unsigned DllStorageClass : 2; // DLL storage class + // The visibility style of this global. + ADD_PACKED_BITFIELD(VisibilityTypes, 2, Visibility) - unsigned ThreadLocal : 3; // Is this symbol "Thread Local", if so, what is - // the desired model? + // This value's address is not significant. + ADD_PACKED_BITFIELD(UnnamedAddr, 2, UnnamedAddrVal) - /// True if the function's name starts with "llvm.". This corresponds to the - /// value of Function::isIntrinsic(), which may be true even if - /// Function::intrinsicID() returns Intrinsic::not_intrinsic. - unsigned HasLLVMReservedName : 1; + // DLL storage class. + ADD_PACKED_BITFIELD(DLLStorageClassTypes, 2, DllStorageClass) - /// If true then there is a definition within the same linkage unit and that - /// definition cannot be runtime preempted. - unsigned IsDSOLocal : 1; + // Is this symbol "Thread Local", if so, what is the desired model? + ADD_PACKED_BITFIELD(ThreadLocalMode, 3, ThreadLocal) - /// True if this symbol has a partition name assigned (see - /// https://lld.llvm.org/Partitions.html). - unsigned HasPartition : 1; + // True if the function's name starts with "llvm.". This corresponds to the + // value of Function::isIntrinsic(), which may be true even if + // Function::intrinsicID() returns Intrinsic::not_intrinsic. + ADD_PACKED_BITFIELD(bool, 1, HasLLVMReservedName) -private: - // Give subclasses access to what otherwise would be wasted padding. - // (16 + 4 + 2 + 2 + 2 + 3 + 1 + 1 + 1) == 32. - unsigned SubClassData : GlobalValueSubClassDataBits; + // If true then there is a definition within the same linkage unit and that + // definition cannot be runtime preempted. + ADD_PACKED_BITFIELD(bool, 1, IsDSOLocal) + + // True if this symbol has a partition name assigned (see + // https://lld.llvm.org/Partitions.html). + ADD_PACKED_BITFIELD(bool, 1, HasPartition) + END_PACKED_BITFIELDS(); + + DECLARE_SUBCLASS_DATA(GlobalValue) +private: friend class Constant; void destroyConstantImpl(); @@ -161,14 +174,6 @@ /// This is stored here to save space in Function on 64-bit hosts. Intrinsic::ID IntID; - unsigned getGlobalValueSubClassData() const { - return SubClassData; - } - void setGlobalValueSubClassData(unsigned V) { - assert(V < (1 << GlobalValueSubClassDataBits) && "It will not fit"); - SubClassData = V; - } - Module *Parent; // The containing module. // Used by SymbolTableListTraits. @@ -181,25 +186,11 @@ } public: - enum ThreadLocalMode { - NotThreadLocal = 0, - GeneralDynamicTLSModel, - LocalDynamicTLSModel, - InitialExecTLSModel, - LocalExecTLSModel - }; - GlobalValue(const GlobalValue &) = delete; unsigned getAlignment() const; unsigned getAddressSpace() const; - enum class UnnamedAddr { - None, - Local, - Global, - }; - bool hasGlobalUnnamedAddr() const { return getUnnamedAddr() == UnnamedAddr::Global; } @@ -213,10 +204,8 @@ return getUnnamedAddr() != UnnamedAddr::None; } - UnnamedAddr getUnnamedAddr() const { - return UnnamedAddr(UnnamedAddrVal); - } - void setUnnamedAddr(UnnamedAddr Val) { UnnamedAddrVal = unsigned(Val); } + UnnamedAddr getUnnamedAddr() const { return UnnamedAddrVal; } + void setUnnamedAddr(UnnamedAddr Val) { UnnamedAddrVal = Val; } static UnnamedAddr getMinUnnamedAddr(UnnamedAddr A, UnnamedAddr B) { if (A == UnnamedAddr::None || B == UnnamedAddr::None) @@ -233,7 +222,7 @@ static_cast(this)->getComdat()); } - VisibilityTypes getVisibility() const { return VisibilityTypes(Visibility); } + VisibilityTypes getVisibility() const { return Visibility; } bool hasDefaultVisibility() const { return Visibility == DefaultVisibility; } bool hasHiddenVisibility() const { return Visibility == HiddenVisibility; } bool hasProtectedVisibility() const { @@ -255,13 +244,9 @@ assert(Val == NotThreadLocal || getValueID() != Value::FunctionVal); ThreadLocal = Val; } - ThreadLocalMode getThreadLocalMode() const { - return static_cast(ThreadLocal); - } + ThreadLocalMode getThreadLocalMode() const { return ThreadLocal; } - DLLStorageClassTypes getDLLStorageClass() const { - return DLLStorageClassTypes(DllStorageClass); - } + DLLStorageClassTypes getDLLStorageClass() const { return DllStorageClass; } bool hasDLLImportStorageClass() const { return DllStorageClass == DLLImportStorageClass; } @@ -457,7 +442,7 @@ Linkage = LT; maybeSetDsoLocal(); } - LinkageTypes getLinkage() const { return LinkageTypes(Linkage); } + LinkageTypes getLinkage() const { return Linkage; } bool isDiscardableIfUnused() const { return isDiscardableIfUnused(getLinkage()); @@ -591,6 +576,15 @@ bool canBeOmittedFromSymbolTable() const; }; +#define BEGIN_GLOBALVALUE_SUBCLASS_DATA(Class) \ + BEGIN_SUBCLASS_DATA(GlobalValue, Class) + +#define ADD_GLOBALVALUE_SUBCLASS_BITFIELD(Type, Bits, Name) \ + ADD_SUBCLASS_BITFIELD(GlobalValue, Type, Bits, Name) + +#define END_GLOBALVALUE_SUBCLASS_DATA() \ + END_SUBCLASS_DATA(GlobalValue) + } // end namespace llvm #endif // LLVM_IR_GLOBALVALUE_H Index: llvm/include/llvm/IR/InstrTypes.h =================================================================== --- llvm/include/llvm/IR/InstrTypes.h +++ llvm/include/llvm/IR/InstrTypes.h @@ -103,6 +103,10 @@ class UnaryOperator : public UnaryInstruction { void AssertOK(); + BEGIN_VALUE_SUBCLASS_DATA(UnaryOperator) + ADD_VALUE_SUBCLASS_OPTIONALDATA() + END_VALUE_SUBCLASS_DATA() + protected: UnaryOperator(UnaryOps iType, Value *S, Type *Ty, const Twine &Name, Instruction *InsertBefore); @@ -188,6 +192,10 @@ class BinaryOperator : public Instruction { void AssertOK(); + BEGIN_VALUE_SUBCLASS_DATA(BinaryOperator) + ADD_VALUE_SUBCLASS_OPTIONALDATA() + END_VALUE_SUBCLASS_DATA() + protected: BinaryOperator(BinaryOps iType, Value *S1, Value *S2, Type *Ty, const Twine &Name, Instruction *InsertBefore); @@ -729,7 +737,7 @@ /// Some passes (e.g. InstCombine) depend on the bit-wise characteristics of /// FCMP_* values. Changing the bit patterns requires a potential change to /// those passes. - enum Predicate { + enum Predicate : unsigned { // Opcode U L G E Intuitive operation FCMP_FALSE = 0, ///< 0 0 0 0 Always false (always folded) FCMP_OEQ = 1, ///< 0 0 0 1 True if ordered and equal @@ -766,6 +774,10 @@ }; protected: + BEGIN_VALUE_SUBCLASS_DATA(CmpInst) + ADD_VALUE_SUBCLASS_BITFIELD(Predicate, 6, Predicate) + END_VALUE_SUBCLASS_DATA() + CmpInst(Type *ty, Instruction::OtherOps op, Predicate pred, Value *LHS, Value *RHS, const Twine &Name = "", Instruction *InsertBefore = nullptr, @@ -804,12 +816,10 @@ } /// Return the predicate for this instruction. - Predicate getPredicate() const { - return Predicate(getSubclassDataFromInstruction()); - } + Predicate getPredicate() const { return ValueSubclassData().Predicate; } /// Set the predicate for this instruction to the specified value. - void setPredicate(Predicate P) { setInstructionSubclassData(P); } + void setPredicate(Predicate P) { ValueSubclassData().Predicate = P; } static bool isFPPredicate(Predicate P) { return P >= FIRST_FCMP_PREDICATE && P <= LAST_FCMP_PREDICATE; @@ -979,13 +989,6 @@ } return Type::getInt1Ty(opnd_type->getContext()); } - -private: - // Shadow Value::setValueSubclassData with a private forwarding method so that - // subclasses cannot accidentally use it. - void setValueSubclassData(unsigned short D) { - Value::setValueSubclassData(D); - } }; // FIXME: these are redundant if CmpInst < BinaryOperator @@ -1110,13 +1113,17 @@ AttributeList Attrs; ///< parameter attributes for callable FunctionType *FTy; + BEGIN_VALUE_SUBCLASS_DATA(CallBase) + ADD_VALUE_SUBCLASS_BITFIELD(CallingConv::ID, 10, CallingConvention) + END_VALUE_SUBCLASS_DATA() + template CallBase(AttributeList const &A, FunctionType *FT, ArgsTy &&... Args) : Instruction(std::forward(Args)...), Attrs(A), FTy(FT) {} using Instruction::Instruction; - bool hasDescriptor() const { return Value::HasDescriptor; } + bool hasDescriptor() const { return User::ValueSubclassData().HasDescriptor; } unsigned getNumSubclassExtraOperands() const { switch (getOpcode()) { @@ -1360,14 +1367,13 @@ } CallingConv::ID getCallingConv() const { - return static_cast(getSubclassDataFromInstruction() >> 2); + return ValueSubclassData().CallingConvention; } void setCallingConv(CallingConv::ID CC) { - auto ID = static_cast(CC); - assert(!(ID & ~CallingConv::MaxID) && "Unsupported calling convention"); - setInstructionSubclassData((getSubclassDataFromInstruction() & 3) | - (ID << 2)); + assert(!(static_cast(CC) & ~CallingConv::MaxID) && + "Unsupported calling convention"); + ValueSubclassData().CallingConvention = CC; } /// Check if this call is an inline asm statement. Index: llvm/include/llvm/IR/Instruction.h =================================================================== --- llvm/include/llvm/IR/Instruction.h +++ llvm/include/llvm/IR/Instruction.h @@ -45,13 +45,11 @@ BasicBlock *Parent; DebugLoc DbgLoc; // 'dbg' Metadata cache. - enum { - /// This is a bit stored in the SubClassData field which indicates whether - /// this instruction has metadata attached to it or not. - HasMetadataBit = 1 << 15 - }; - protected: + BEGIN_VALUE_SUBCLASS_DATA(Instruction) + ADD_VALUE_SUBCLASS_BITFIELD(bool, 1, HasMetadata) // has metadata attached + END_VALUE_SUBCLASS_DATA() + ~Instruction(); // Use deleteValue() to delete a generic Instruction. public: @@ -457,9 +455,7 @@ private: /// Return true if we have an entry in the on-the-side metadata hash. - bool hasMetadataHashEntry() const { - return (getSubclassDataFromValue() & HasMetadataBit) != 0; - } + bool hasMetadataHashEntry() const { return ValueSubclassData().HasMetadata; } // These are all implemented in Metadata.cpp. MDNode *getMetadataImpl(unsigned KindID) const; @@ -634,9 +630,9 @@ /// (e.g. load is volatile) agree. bool isIdenticalTo(const Instruction *I) const; - /// This is like isIdenticalTo, except that it ignores the - /// SubclassOptionalData flags, which may specify conditions under which the - /// instruction's result is undefined. + /// This is like isIdenticalTo, except that it ignores the OptionalData flags, + /// which may specify conditions under which the instruction's result is + /// undefined. bool isIdenticalToWhenDefined(const Instruction *I) const; /// When checking for operation equivalence (using isSameOperationAs) it is @@ -739,37 +735,11 @@ private: friend class SymbolTableListTraits; - // Shadow Value::setValueSubclassData with a private forwarding method so that - // subclasses cannot accidentally use it. - void setValueSubclassData(unsigned short D) { - Value::setValueSubclassData(D); - } - - unsigned short getSubclassDataFromValue() const { - return Value::getSubclassDataFromValue(); - } - - void setHasMetadataHashEntry(bool V) { - setValueSubclassData((getSubclassDataFromValue() & ~HasMetadataBit) | - (V ? HasMetadataBit : 0)); - } + void setHasMetadataHashEntry(bool V) { ValueSubclassData().HasMetadata = V; } void setParent(BasicBlock *P); protected: - // Instruction subclasses can stick up to 15 bits of stuff into the - // SubclassData field of instruction with these members. - - // Verify that only the low 15 bits are used. - void setInstructionSubclassData(unsigned short D) { - assert((D & HasMetadataBit) == 0 && "Out of range value put into field"); - setValueSubclassData((getSubclassDataFromValue() & HasMetadataBit) | D); - } - - unsigned getSubclassDataFromInstruction() const { - return getSubclassDataFromValue() & ~HasMetadataBit; - } - Instruction(Type *Ty, unsigned iType, Use *Ops, unsigned NumOps, Instruction *InsertBefore = nullptr); Instruction(Type *Ty, unsigned iType, Use *Ops, unsigned NumOps, Index: llvm/include/llvm/IR/Instructions.h =================================================================== --- llvm/include/llvm/IR/Instructions.h +++ llvm/include/llvm/IR/Instructions.h @@ -59,6 +59,12 @@ class AllocaInst : public UnaryInstruction { Type *AllocatedType; + BEGIN_VALUE_SUBCLASS_DATA(AllocaInst) + ADD_VALUE_SUBCLASS_BITFIELD(unsigned, 5, EncodedAlignment) + ADD_VALUE_SUBCLASS_BITFIELD(bool, 1, IsUsedWithInAlloca) + ADD_VALUE_SUBCLASS_BITFIELD(bool, 1, IsSwiftError) + END_VALUE_SUBCLASS_DATA() + protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; @@ -110,7 +116,7 @@ /// Return the alignment of the memory that is being allocated by the /// instruction. unsigned getAlignment() const { - if (const auto MA = decodeMaybeAlign(getSubclassDataFromInstruction() & 31)) + if (const auto MA = decodeMaybeAlign(ValueSubclassData().EncodedAlignment)) return MA->value(); return 0; } @@ -124,25 +130,19 @@ /// Return true if this alloca is used as an inalloca argument to a call. Such /// allocas are never considered static even if they are in the entry block. bool isUsedWithInAlloca() const { - return getSubclassDataFromInstruction() & 32; + return ValueSubclassData().IsUsedWithInAlloca; } /// Specify whether this alloca is used to represent the arguments to a call. void setUsedWithInAlloca(bool V) { - setInstructionSubclassData((getSubclassDataFromInstruction() & ~32) | - (V ? 32 : 0)); + ValueSubclassData().IsUsedWithInAlloca = V; } /// Return true if this alloca is used as a swifterror argument to a call. - bool isSwiftError() const { - return getSubclassDataFromInstruction() & 64; - } + bool isSwiftError() const { return ValueSubclassData().IsSwiftError; } /// Specify whether this alloca is used to represent a swifterror. - void setSwiftError(bool V) { - setInstructionSubclassData((getSubclassDataFromInstruction() & ~64) | - (V ? 64 : 0)); - } + void setSwiftError(bool V) { ValueSubclassData().IsSwiftError = V; } // Methods for support type inquiry through isa, cast, and dyn_cast: static bool classof(const Instruction *I) { @@ -151,24 +151,25 @@ static bool classof(const Value *V) { return isa(V) && classof(cast(V)); } - -private: - // Shadow Instruction::setInstructionSubclassData with a private forwarding - // method so that subclasses cannot accidentally use it. - void setInstructionSubclassData(unsigned short D) { - Instruction::setInstructionSubclassData(D); - } }; //===----------------------------------------------------------------------===// // LoadInst Class //===----------------------------------------------------------------------===// -/// An instruction for reading from memory. This uses the SubclassData field in -/// Value to store whether or not the load is volatile. +/// An instruction for reading from memory. This uses the ValueSubclassData to +/// store whether or not the load is volatile. class LoadInst : public UnaryInstruction { void AssertOK(); + BEGIN_VALUE_SUBCLASS_DATA(LoadInst) + ADD_VALUE_SUBCLASS_BITFIELD(bool, 1, IsVolatile) + ADD_VALUE_SUBCLASS_BITFIELD(AtomicOrdering, 3, Ordering) + ADD_VALUE_SUBCLASS_BITFIELD(SyncScope::ID, bit_sizeof(), + SSID) + ADD_VALUE_SUBCLASS_BITFIELD(unsigned, 5, EncodedAlignment) + END_VALUE_SUBCLASS_DATA() + protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; @@ -230,13 +231,10 @@ isVolatile, Align, Order, SSID, InsertAtEnd) {} /// Return true if this is a load from a volatile memory location. - bool isVolatile() const { return getSubclassDataFromInstruction() & 1; } + bool isVolatile() const { return ValueSubclassData().IsVolatile; } /// Specify whether this is a volatile load or not. - void setVolatile(bool V) { - setInstructionSubclassData((getSubclassDataFromInstruction() & ~1) | - (V ? 1 : 0)); - } + void setVolatile(bool V) { ValueSubclassData().IsVolatile = V; } /// Return the alignment of the access that is being performed. /// FIXME: Remove this function once transition to Align is over. @@ -249,32 +247,25 @@ /// Return the alignment of the access that is being performed. MaybeAlign getAlign() const { - return decodeMaybeAlign((getSubclassDataFromInstruction() >> 1) & 31); + return decodeMaybeAlign(ValueSubclassData().EncodedAlignment); } void setAlignment(MaybeAlign Alignment); /// Returns the ordering constraint of this load instruction. - AtomicOrdering getOrdering() const { - return AtomicOrdering((getSubclassDataFromInstruction() >> 7) & 7); - } + AtomicOrdering getOrdering() const { return ValueSubclassData().Ordering; } /// Sets the ordering constraint of this load instruction. May not be Release /// or AcquireRelease. void setOrdering(AtomicOrdering Ordering) { - setInstructionSubclassData((getSubclassDataFromInstruction() & ~(7 << 7)) | - ((unsigned)Ordering << 7)); + ValueSubclassData().Ordering = Ordering; } /// Returns the synchronization scope ID of this load instruction. - SyncScope::ID getSyncScopeID() const { - return SSID; - } + SyncScope::ID getSyncScopeID() const { return ValueSubclassData().SSID; } /// Sets the synchronization scope ID of this load instruction. - void setSyncScopeID(SyncScope::ID SSID) { - this->SSID = SSID; - } + void setSyncScopeID(SyncScope::ID SSID) { ValueSubclassData().SSID = SSID; } /// Sets the ordering constraint and the synchronization scope ID of this load /// instruction. @@ -309,18 +300,6 @@ static bool classof(const Value *V) { return isa(V) && classof(cast(V)); } - -private: - // Shadow Instruction::setInstructionSubclassData with a private forwarding - // method so that subclasses cannot accidentally use it. - void setInstructionSubclassData(unsigned short D) { - Instruction::setInstructionSubclassData(D); - } - - /// The synchronization scope ID of this load instruction. Not quite enough - /// room in SubClassData for everything, so synchronization scope ID gets its - /// own field. - SyncScope::ID SSID; }; //===----------------------------------------------------------------------===// @@ -331,6 +310,14 @@ class StoreInst : public Instruction { void AssertOK(); + BEGIN_VALUE_SUBCLASS_DATA(StoreInst) + ADD_VALUE_SUBCLASS_BITFIELD(bool, 1, IsVolatile) + ADD_VALUE_SUBCLASS_BITFIELD(AtomicOrdering, 3, Ordering) + ADD_VALUE_SUBCLASS_BITFIELD(SyncScope::ID, bit_sizeof(), + SSID) + ADD_VALUE_SUBCLASS_BITFIELD(unsigned, 5, EncodedAlignment) + END_VALUE_SUBCLASS_DATA() + protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; @@ -359,13 +346,10 @@ } /// Return true if this is a store to a volatile memory location. - bool isVolatile() const { return getSubclassDataFromInstruction() & 1; } + bool isVolatile() const { return ValueSubclassData().IsVolatile; } /// Specify whether this is a volatile store or not. - void setVolatile(bool V) { - setInstructionSubclassData((getSubclassDataFromInstruction() & ~1) | - (V ? 1 : 0)); - } + void setVolatile(bool V) { ValueSubclassData().IsVolatile = V; } /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); @@ -380,32 +364,25 @@ } MaybeAlign getAlign() const { - return decodeMaybeAlign((getSubclassDataFromInstruction() >> 1) & 31); + return decodeMaybeAlign(ValueSubclassData().EncodedAlignment); } void setAlignment(MaybeAlign Alignment); /// Returns the ordering constraint of this store instruction. - AtomicOrdering getOrdering() const { - return AtomicOrdering((getSubclassDataFromInstruction() >> 7) & 7); - } + AtomicOrdering getOrdering() const { return ValueSubclassData().Ordering; } /// Sets the ordering constraint of this store instruction. May not be /// Acquire or AcquireRelease. void setOrdering(AtomicOrdering Ordering) { - setInstructionSubclassData((getSubclassDataFromInstruction() & ~(7 << 7)) | - ((unsigned)Ordering << 7)); + ValueSubclassData().Ordering = Ordering; } /// Returns the synchronization scope ID of this store instruction. - SyncScope::ID getSyncScopeID() const { - return SSID; - } + SyncScope::ID getSyncScopeID() const { return ValueSubclassData().SSID; } /// Sets the synchronization scope ID of this store instruction. - void setSyncScopeID(SyncScope::ID SSID) { - this->SSID = SSID; - } + void setSyncScopeID(SyncScope::ID SSID) { ValueSubclassData().SSID = SSID; } /// Sets the ordering constraint and the synchronization scope ID of this /// store instruction. @@ -443,18 +420,6 @@ static bool classof(const Value *V) { return isa(V) && classof(cast(V)); } - -private: - // Shadow Instruction::setInstructionSubclassData with a private forwarding - // method so that subclasses cannot accidentally use it. - void setInstructionSubclassData(unsigned short D) { - Instruction::setInstructionSubclassData(D); - } - - /// The synchronization scope ID of this store instruction. Not quite enough - /// room in SubClassData for everything, so synchronization scope ID gets its - /// own field. - SyncScope::ID SSID; }; template <> @@ -469,6 +434,12 @@ /// An instruction for ordering other memory operations. class FenceInst : public Instruction { + BEGIN_VALUE_SUBCLASS_DATA(FenceInst) + ADD_VALUE_SUBCLASS_BITFIELD(AtomicOrdering, 3, Ordering) + ADD_VALUE_SUBCLASS_BITFIELD(SyncScope::ID, bit_sizeof(), + SSID) + END_VALUE_SUBCLASS_DATA() + void Init(AtomicOrdering Ordering, SyncScope::ID SSID); protected: @@ -492,26 +463,19 @@ } /// Returns the ordering constraint of this fence instruction. - AtomicOrdering getOrdering() const { - return AtomicOrdering(getSubclassDataFromInstruction() >> 1); - } + AtomicOrdering getOrdering() const { return ValueSubclassData().Ordering; } /// Sets the ordering constraint of this fence instruction. May only be /// Acquire, Release, AcquireRelease, or SequentiallyConsistent. void setOrdering(AtomicOrdering Ordering) { - setInstructionSubclassData((getSubclassDataFromInstruction() & 1) | - ((unsigned)Ordering << 1)); + ValueSubclassData().Ordering = Ordering; } /// Returns the synchronization scope ID of this fence instruction. - SyncScope::ID getSyncScopeID() const { - return SSID; - } + SyncScope::ID getSyncScopeID() const { return ValueSubclassData().SSID; } /// Sets the synchronization scope ID of this fence instruction. - void setSyncScopeID(SyncScope::ID SSID) { - this->SSID = SSID; - } + void setSyncScopeID(SyncScope::ID SSID) { ValueSubclassData().SSID = SSID; } // Methods for support type inquiry through isa, cast, and dyn_cast: static bool classof(const Instruction *I) { @@ -520,18 +484,6 @@ static bool classof(const Value *V) { return isa(V) && classof(cast(V)); } - -private: - // Shadow Instruction::setInstructionSubclassData with a private forwarding - // method so that subclasses cannot accidentally use it. - void setInstructionSubclassData(unsigned short D) { - Instruction::setInstructionSubclassData(D); - } - - /// The synchronization scope ID of this fence instruction. Not quite enough - /// room in SubClassData for everything, so synchronization scope ID gets its - /// own field. - SyncScope::ID SSID; }; //===----------------------------------------------------------------------===// @@ -545,6 +497,15 @@ /// failure (false) as second element. /// class AtomicCmpXchgInst : public Instruction { + BEGIN_VALUE_SUBCLASS_DATA(AtomicCmpXchgInst) + ADD_VALUE_SUBCLASS_BITFIELD(bool, 1, IsVolatile) + ADD_VALUE_SUBCLASS_BITFIELD(AtomicOrdering, 3, SuccessOrdering) + ADD_VALUE_SUBCLASS_BITFIELD(AtomicOrdering, 3, FailureOrdering) + ADD_VALUE_SUBCLASS_BITFIELD(bool, 1, IsWeak) + ADD_VALUE_SUBCLASS_BITFIELD(SyncScope::ID, bit_sizeof(), + SSID) + END_VALUE_SUBCLASS_DATA() + void Init(Value *Ptr, Value *Cmp, Value *NewVal, AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, SyncScope::ID SSID); @@ -573,65 +534,48 @@ /// Return true if this is a cmpxchg from a volatile memory /// location. /// - bool isVolatile() const { - return getSubclassDataFromInstruction() & 1; - } + bool isVolatile() const { return ValueSubclassData().IsVolatile; } /// Specify whether this is a volatile cmpxchg. - /// - void setVolatile(bool V) { - setInstructionSubclassData((getSubclassDataFromInstruction() & ~1) | - (unsigned)V); - } + void setVolatile(bool V) { ValueSubclassData().IsVolatile = V; } /// Return true if this cmpxchg may spuriously fail. - bool isWeak() const { - return getSubclassDataFromInstruction() & 0x100; - } + bool isWeak() const { return ValueSubclassData().IsWeak; } - void setWeak(bool IsWeak) { - setInstructionSubclassData((getSubclassDataFromInstruction() & ~0x100) | - (IsWeak << 8)); - } + void setWeak(bool IsWeak) { ValueSubclassData().IsWeak = IsWeak; } /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); /// Returns the success ordering constraint of this cmpxchg instruction. AtomicOrdering getSuccessOrdering() const { - return AtomicOrdering((getSubclassDataFromInstruction() >> 2) & 7); + return ValueSubclassData().SuccessOrdering; } /// Sets the success ordering constraint of this cmpxchg instruction. void setSuccessOrdering(AtomicOrdering Ordering) { assert(Ordering != AtomicOrdering::NotAtomic && "CmpXchg instructions can only be atomic."); - setInstructionSubclassData((getSubclassDataFromInstruction() & ~0x1c) | - ((unsigned)Ordering << 2)); + ValueSubclassData().SuccessOrdering = Ordering; } /// Returns the failure ordering constraint of this cmpxchg instruction. AtomicOrdering getFailureOrdering() const { - return AtomicOrdering((getSubclassDataFromInstruction() >> 5) & 7); + return ValueSubclassData().FailureOrdering; } /// Sets the failure ordering constraint of this cmpxchg instruction. void setFailureOrdering(AtomicOrdering Ordering) { assert(Ordering != AtomicOrdering::NotAtomic && "CmpXchg instructions can only be atomic."); - setInstructionSubclassData((getSubclassDataFromInstruction() & ~0xe0) | - ((unsigned)Ordering << 5)); + ValueSubclassData().FailureOrdering = Ordering; } /// Returns the synchronization scope ID of this cmpxchg instruction. - SyncScope::ID getSyncScopeID() const { - return SSID; - } + SyncScope::ID getSyncScopeID() const { return ValueSubclassData().SSID; } /// Sets the synchronization scope ID of this cmpxchg instruction. - void setSyncScopeID(SyncScope::ID SSID) { - this->SSID = SSID; - } + void setSyncScopeID(SyncScope::ID SSID) { ValueSubclassData().SSID = SSID; } Value *getPointerOperand() { return getOperand(0); } const Value *getPointerOperand() const { return getOperand(0); } @@ -678,18 +622,6 @@ static bool classof(const Value *V) { return isa(V) && classof(cast(V)); } - -private: - // Shadow Instruction::setInstructionSubclassData with a private forwarding - // method so that subclasses cannot accidentally use it. - void setInstructionSubclassData(unsigned short D) { - Instruction::setInstructionSubclassData(D); - } - - /// The synchronization scope ID of this cmpxchg instruction. Not quite - /// enough room in SubClassData for everything, so synchronization scope ID - /// gets its own field. - SyncScope::ID SSID; }; template <> @@ -719,7 +651,7 @@ /// the descriptions, 'p' is the pointer to the instruction's memory location, /// 'old' is the initial value of *p, and 'v' is the other value passed to the /// instruction. These instructions always return 'old'. - enum BinOp { + enum BinOp : unsigned { /// *p = v Xchg, /// *p = old + v @@ -754,6 +686,16 @@ BAD_BINOP }; +private: + BEGIN_VALUE_SUBCLASS_DATA(AtomicRMWInst) + ADD_VALUE_SUBCLASS_BITFIELD(bool, 1, IsVolatile) + ADD_VALUE_SUBCLASS_BITFIELD(AtomicOrdering, 3, Ordering) + ADD_VALUE_SUBCLASS_BITFIELD(SyncScope::ID, bit_sizeof(), + SSID) + ADD_VALUE_SUBCLASS_BITFIELD(BinOp, 3, Operation) + END_VALUE_SUBCLASS_DATA() + +public: AtomicRMWInst(BinOp Operation, Value *Ptr, Value *Val, AtomicOrdering Ordering, SyncScope::ID SSID, Instruction *InsertBefore = nullptr); @@ -766,9 +708,7 @@ return User::operator new(s, 2); } - BinOp getOperation() const { - return static_cast(getSubclassDataFromInstruction() >> 5); - } + BinOp getOperation() const { return ValueSubclassData().Operation; } static StringRef getOperationName(BinOp Op); @@ -783,49 +723,33 @@ } void setOperation(BinOp Operation) { - unsigned short SubclassData = getSubclassDataFromInstruction(); - setInstructionSubclassData((SubclassData & 31) | - (Operation << 5)); + ValueSubclassData().Operation = Operation; } /// Return true if this is a RMW on a volatile memory location. - /// - bool isVolatile() const { - return getSubclassDataFromInstruction() & 1; - } + bool isVolatile() const { return ValueSubclassData().IsVolatile; } /// Specify whether this is a volatile RMW or not. - /// - void setVolatile(bool V) { - setInstructionSubclassData((getSubclassDataFromInstruction() & ~1) | - (unsigned)V); - } + void setVolatile(bool V) { ValueSubclassData().IsVolatile = V; } /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); /// Returns the ordering constraint of this rmw instruction. - AtomicOrdering getOrdering() const { - return AtomicOrdering((getSubclassDataFromInstruction() >> 2) & 7); - } + AtomicOrdering getOrdering() const { return ValueSubclassData().Ordering; } /// Sets the ordering constraint of this rmw instruction. void setOrdering(AtomicOrdering Ordering) { assert(Ordering != AtomicOrdering::NotAtomic && "atomicrmw instructions can only be atomic."); - setInstructionSubclassData((getSubclassDataFromInstruction() & ~(7 << 2)) | - ((unsigned)Ordering << 2)); + ValueSubclassData().Ordering = Ordering; } /// Returns the synchronization scope ID of this rmw instruction. - SyncScope::ID getSyncScopeID() const { - return SSID; - } + SyncScope::ID getSyncScopeID() const { return ValueSubclassData().SSID; } /// Sets the synchronization scope ID of this rmw instruction. - void setSyncScopeID(SyncScope::ID SSID) { - this->SSID = SSID; - } + void setSyncScopeID(SyncScope::ID SSID) { ValueSubclassData().SSID = SSID; } Value *getPointerOperand() { return getOperand(0); } const Value *getPointerOperand() const { return getOperand(0); } @@ -854,17 +778,6 @@ private: void Init(BinOp Operation, Value *Ptr, Value *Val, AtomicOrdering Ordering, SyncScope::ID SSID); - - // Shadow Instruction::setInstructionSubclassData with a private forwarding - // method so that subclasses cannot accidentally use it. - void setInstructionSubclassData(unsigned short D) { - Instruction::setInstructionSubclassData(D); - } - - /// The synchronization scope ID of this rmw instruction. Not quite enough - /// room in SubClassData for everything, so synchronization scope ID gets its - /// own field. - SyncScope::ID SSID; }; template <> @@ -893,6 +806,10 @@ Type *SourceElementType; Type *ResultElementType; + BEGIN_VALUE_SUBCLASS_DATA(GetElementPtrInst) + ADD_VALUE_SUBCLASS_OPTIONALDATA() + END_VALUE_SUBCLASS_DATA() + GetElementPtrInst(const GetElementPtrInst &GEPI); /// Constructors - Create a getelementptr instruction with a base pointer an @@ -1307,6 +1224,10 @@ "Invalid operand types for FCmp instruction"); } + BEGIN_VALUE_SUBCLASS_DATA(FCmpInst) + ADD_VALUE_SUBCLASS_OPTIONALDATA() + END_VALUE_SUBCLASS_DATA() + protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; @@ -1399,9 +1320,9 @@ //===----------------------------------------------------------------------===// /// This class represents a function call, abstracting a target -/// machine's calling convention. This class uses low bit of the SubClassData -/// field to indicate whether or not this is a tail call. The rest of the bits -/// hold the calling convention of the call. +/// machine's calling convention. This class uses 2 bits of the +/// ValueSubClassData to indicate whether or not this is a tail call. The rest +/// of the bits hold the calling convention of the call. /// class CallInst : public CallBase { CallInst(const CallInst &CI); @@ -1632,37 +1553,43 @@ BasicBlock *InsertAtEnd); // Note that 'musttail' implies 'tail'. - enum TailCallKind { + enum TailCallKind : unsigned { TCK_None = 0, TCK_Tail = 1, TCK_MustTail = 2, TCK_NoTail = 3 }; + +private: + BEGIN_VALUE_SUBCLASS_DATA(CallInst) + ADD_VALUE_SUBCLASS_BITFIELD(TailCallKind, 2, TailCallKind) + ADD_VALUE_SUBCLASS_OPTIONALDATA() + END_VALUE_SUBCLASS_DATA() + +public: TailCallKind getTailCallKind() const { - return TailCallKind(getSubclassDataFromInstruction() & 3); + return ValueSubclassData().TailCallKind; } bool isTailCall() const { - unsigned Kind = getSubclassDataFromInstruction() & 3; + TailCallKind Kind = ValueSubclassData().TailCallKind; return Kind == TCK_Tail || Kind == TCK_MustTail; } bool isMustTailCall() const { - return (getSubclassDataFromInstruction() & 3) == TCK_MustTail; + return ValueSubclassData().TailCallKind == TCK_MustTail; } bool isNoTailCall() const { - return (getSubclassDataFromInstruction() & 3) == TCK_NoTail; + return ValueSubclassData().TailCallKind == TCK_NoTail; } void setTailCall(bool isTC = true) { - setInstructionSubclassData((getSubclassDataFromInstruction() & ~3) | - unsigned(isTC ? TCK_Tail : TCK_None)); + ValueSubclassData().TailCallKind = isTC ? TCK_Tail : TCK_None; } void setTailCallKind(TailCallKind TCK) { - setInstructionSubclassData((getSubclassDataFromInstruction() & ~3) | - unsigned(TCK)); + ValueSubclassData().TailCallKind = TCK; } /// Return true if the call can return twice @@ -1681,13 +1608,6 @@ /// Updates profile metadata by scaling it by \p S / \p T. void updateProfWeight(uint64_t S, uint64_t T); - -private: - // Shadow Instruction::setInstructionSubclassData with a private forwarding - // method so that subclasses cannot accidentally use it. - void setInstructionSubclassData(unsigned short D) { - Instruction::setInstructionSubclassData(D); - } }; CallInst::CallInst(FunctionType *Ty, Value *Func, ArrayRef Args, @@ -1719,6 +1639,10 @@ /// This class represents the LLVM 'select' instruction. /// class SelectInst : public Instruction { + BEGIN_VALUE_SUBCLASS_DATA(SelectInst) + ADD_VALUE_SUBCLASS_OPTIONALDATA() + END_VALUE_SUBCLASS_DATA() + SelectInst(Value *C, Value *S1, Value *S2, const Twine &NameStr, Instruction *InsertBefore) : Instruction(S1->getType(), Instruction::Select, @@ -2554,6 +2478,10 @@ /// the number actually in use. unsigned ReservedSpace; + BEGIN_VALUE_SUBCLASS_DATA(PHINode) + ADD_VALUE_SUBCLASS_OPTIONALDATA() + END_VALUE_SUBCLASS_DATA() + PHINode(const PHINode &PN); explicit PHINode(Type *Ty, unsigned NumReservedValues, @@ -2791,14 +2719,17 @@ /// necessary to generate correct exception handling. The landingpad instruction /// cannot be moved from the top of a landing pad block, which itself is /// accessible only from the 'unwind' edge of an invoke. This uses the -/// SubclassData field in Value to store whether or not the landingpad is a -/// cleanup. +/// ValueSubclassData to store whether or not the landingpad is a cleanup. /// class LandingPadInst : public Instruction { /// The number of operands actually allocated. NumOperands is /// the number actually in use. unsigned ReservedSpace; + BEGIN_VALUE_SUBCLASS_DATA(LandingPadInst) + ADD_VALUE_SUBCLASS_BITFIELD(bool, 1, IsCleanup) + END_VALUE_SUBCLASS_DATA() + LandingPadInst(const LandingPadInst &LP); public: @@ -2839,13 +2770,10 @@ /// Return 'true' if this landingpad instruction is a /// cleanup. I.e., it should be run when unwinding even if its landing pad /// doesn't catch the exception. - bool isCleanup() const { return getSubclassDataFromInstruction() & 1; } + bool isCleanup() const { return ValueSubclassData().IsCleanup; } /// Indicate that this landingpad instruction is a cleanup. - void setCleanup(bool V) { - setInstructionSubclassData((getSubclassDataFromInstruction() & ~1) | - (V ? 1 : 0)); - } + void setCleanup(bool V) { ValueSubclassData().IsCleanup = V; } /// Add a catch or filter clause to the landing pad. void addClause(Constant *ClauseVal); @@ -3656,7 +3584,7 @@ // InvokeInst Class //===----------------------------------------------------------------------===// -/// Invoke instruction. The SubclassData field is used to hold the +/// Invoke instruction. The ValueSubclassData is used to hold the /// calling convention of the call. /// class InvokeInst : public CallBase { @@ -3882,14 +3810,6 @@ static bool classof(const Value *V) { return isa(V) && classof(cast(V)); } - -private: - - // Shadow Instruction::setInstructionSubclassData with a private forwarding - // method so that subclasses cannot accidentally use it. - void setInstructionSubclassData(unsigned short D) { - Instruction::setInstructionSubclassData(D); - } }; InvokeInst::InvokeInst(FunctionType *Ty, Value *Func, BasicBlock *IfNormal, @@ -3917,7 +3837,7 @@ //===----------------------------------------------------------------------===// /// CallBr instruction, tracking function calls that may not return control but -/// instead transfer it to a third location. The SubclassData field is used to +/// instead transfer it to a third location. The ValueSubclassData is used to /// hold the calling convention of the call. /// class CallBrInst : public CallBase { @@ -4122,14 +4042,6 @@ static bool classof(const Value *V) { return isa(V) && classof(cast(V)); } - -private: - - // Shadow Instruction::setInstructionSubclassData with a private forwarding - // method so that subclasses cannot accidentally use it. - void setInstructionSubclassData(unsigned short D) { - Instruction::setInstructionSubclassData(D); - } }; CallBrInst::CallBrInst(FunctionType *Ty, Value *Func, BasicBlock *DefaultDest, @@ -4223,6 +4135,10 @@ /// the number actually in use. unsigned ReservedSpace; + BEGIN_VALUE_SUBCLASS_DATA(CatchSwitchInst) + ADD_VALUE_SUBCLASS_BITFIELD(bool, 1, HasUnwindDest) + END_VALUE_SUBCLASS_DATA() + // Operand[0] = Outer scope // Operand[1] = Unwind block destination // Operand[n] = BasicBlock to go to on match @@ -4280,7 +4196,7 @@ void setParentPad(Value *ParentPad) { setOperand(0, ParentPad); } // Accessor Methods for CatchSwitch stmt - bool hasUnwindDest() const { return getSubclassDataFromInstruction() & 1; } + bool hasUnwindDest() const { return ValueSubclassData().HasUnwindDest; } bool unwindsToCaller() const { return !hasUnwindDest(); } BasicBlock *getUnwindDest() const { if (hasUnwindDest()) @@ -4566,7 +4482,10 @@ //===----------------------------------------------------------------------===// class CleanupReturnInst : public Instruction { -private: + BEGIN_VALUE_SUBCLASS_DATA(CleanupReturnInst) + ADD_VALUE_SUBCLASS_BITFIELD(bool, 1, HasUnwindDest) + END_VALUE_SUBCLASS_DATA() + CleanupReturnInst(const CleanupReturnInst &RI); CleanupReturnInst(Value *CleanupPad, BasicBlock *UnwindBB, unsigned Values, Instruction *InsertBefore = nullptr); @@ -4606,7 +4525,7 @@ /// Provide fast operand accessors DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); - bool hasUnwindDest() const { return getSubclassDataFromInstruction() & 1; } + bool hasUnwindDest() const { return ValueSubclassData().HasUnwindDest; } bool unwindsToCaller() const { return !hasUnwindDest(); } /// Convenience accessor. @@ -4647,12 +4566,6 @@ assert(Idx == 0); setUnwindDest(B); } - - // Shadow Instruction::setInstructionSubclassData with a private forwarding - // method so that subclasses cannot accidentally use it. - void setInstructionSubclassData(unsigned short D) { - Instruction::setInstructionSubclassData(D); - } }; template <> Index: llvm/include/llvm/IR/Operator.h =================================================================== --- llvm/include/llvm/IR/Operator.h +++ llvm/include/llvm/IR/Operator.h @@ -28,6 +28,15 @@ /// This is a utility class that provides an abstraction for the common /// functionality between Instructions and ConstantExprs. class Operator : public User { +protected: + BEGIN_VALUE_SUBCLASS_DATA(Operator) + ADD_VALUE_SUBCLASS_BITFIELD(unsigned, 1, Skip0) + ADD_VALUE_SUBCLASS_BITFIELD(unsigned, + SubclassOptionalDataMinBitOffset - + (bit_offsetof() + 1), + Skip1) + END_VALUE_SUBCLASS_DATA() + public: // The Operator class is intended to be used as a utility, and is never itself // instantiated. @@ -64,6 +73,11 @@ /// Mul, and Shl. It does not include SDiv, despite that operator having the /// potential for overflow. class OverflowingBinaryOperator : public Operator { + BEGIN_VALUE_SUBCLASS_DATA(OverflowingBinaryOperator) + ADD_VALUE_SUBCLASS_BITFIELD(bool, 1, HasNoUnsignedWrap) + ADD_VALUE_SUBCLASS_BITFIELD(bool, 1, HasNoSignedWrap) + END_VALUE_SUBCLASS_DATA() + public: enum { NoUnsignedWrap = (1 << 0), @@ -75,26 +89,20 @@ friend class ConstantExpr; void setHasNoUnsignedWrap(bool B) { - SubclassOptionalData = - (SubclassOptionalData & ~NoUnsignedWrap) | (B * NoUnsignedWrap); - } - void setHasNoSignedWrap(bool B) { - SubclassOptionalData = - (SubclassOptionalData & ~NoSignedWrap) | (B * NoSignedWrap); + ValueSubclassData().HasNoUnsignedWrap = B; } + void setHasNoSignedWrap(bool B) { ValueSubclassData().HasNoSignedWrap = B; } public: /// Test whether this operation is known to never /// undergo unsigned overflow, aka the nuw property. bool hasNoUnsignedWrap() const { - return SubclassOptionalData & NoUnsignedWrap; + return ValueSubclassData().HasNoUnsignedWrap; } /// Test whether this operation is known to never /// undergo signed overflow, aka the nsw property. - bool hasNoSignedWrap() const { - return (SubclassOptionalData & NoSignedWrap) != 0; - } + bool hasNoSignedWrap() const { return ValueSubclassData().HasNoSignedWrap; } static bool classof(const Instruction *I) { return I->getOpcode() == Instruction::Add || @@ -117,6 +125,10 @@ /// A udiv or sdiv instruction, which can be marked as "exact", /// indicating that no bits are destroyed. class PossiblyExactOperator : public Operator { + BEGIN_VALUE_SUBCLASS_DATA(PossiblyExactOperator) + ADD_VALUE_SUBCLASS_BITFIELD(bool, 1, IsExact) + END_VALUE_SUBCLASS_DATA() + public: enum { IsExact = (1 << 0) @@ -126,15 +138,11 @@ friend class Instruction; friend class ConstantExpr; - void setIsExact(bool B) { - SubclassOptionalData = (SubclassOptionalData & ~IsExact) | (B * IsExact); - } + void setIsExact(bool B) { ValueSubclassData().IsExact = B; } public: /// Test whether this division is known to be exact, with zero remainder. - bool isExact() const { - return SubclassOptionalData & IsExact; - } + bool isExact() const { return ValueSubclassData().IsExact; } static bool isPossiblyExactOpcode(unsigned OpC) { return OpC == Instruction::SDiv || @@ -171,9 +179,9 @@ } public: - // This is how the bits are used in Value::SubclassOptionalData so they - // should fit there too. - // WARNING: We're out of space. SubclassOptionalData only has 7 bits. New + // This is how the bits are used in Instruction::OptionalData and + // ConstantExpr::OptionalData so they should fit there too. + // WARNING: We're out of space. OptionalData only has 7 bits. New // functionality will require a change in how this information is stored. enum { AllowReassoc = (1 << 0), @@ -238,12 +246,39 @@ void operator&=(const FastMathFlags &OtherFlags) { Flags &= OtherFlags.Flags; } + + bool operator==(const FastMathFlags &OtherFlags) const { + return Flags == OtherFlags.Flags; + } + + bool operator!=(const FastMathFlags &OtherFlags) const { + return Flags != OtherFlags.Flags; + } + + bool operator<(const FastMathFlags &OtherFlags) const { + return Flags < OtherFlags.Flags; + } + + bool operator<=(const FastMathFlags &OtherFlags) const { + return Flags <= OtherFlags.Flags; + } + + bool operator>(const FastMathFlags &OtherFlags) const { + return Flags > OtherFlags.Flags; + } + + bool operator>=(const FastMathFlags &OtherFlags) const { + return Flags >= OtherFlags.Flags; + } }; /// Utility class for floating point operations which can have /// information about relaxed accuracy requirements attached to them. class FPMathOperator : public Operator { -private: + BEGIN_VALUE_SUBCLASS_DATA(FPMathOperator) + ADD_VALUE_SUBCLASS_BITFIELD(unsigned, 7, Flags) + END_VALUE_SUBCLASS_DATA() + friend class Instruction; /// 'Fast' means all bits are set. @@ -258,110 +293,112 @@ } void setHasAllowReassoc(bool B) { - SubclassOptionalData = - (SubclassOptionalData & ~FastMathFlags::AllowReassoc) | - (B * FastMathFlags::AllowReassoc); + ValueSubclassData().Flags = + (ValueSubclassData().Flags & ~FastMathFlags::AllowReassoc) | + (B * FastMathFlags::AllowReassoc); } void setHasNoNaNs(bool B) { - SubclassOptionalData = - (SubclassOptionalData & ~FastMathFlags::NoNaNs) | - (B * FastMathFlags::NoNaNs); + ValueSubclassData().Flags = + (ValueSubclassData().Flags & ~FastMathFlags::NoNaNs) | + (B * FastMathFlags::NoNaNs); } void setHasNoInfs(bool B) { - SubclassOptionalData = - (SubclassOptionalData & ~FastMathFlags::NoInfs) | - (B * FastMathFlags::NoInfs); + ValueSubclassData().Flags = + (ValueSubclassData().Flags & ~FastMathFlags::NoInfs) | + (B * FastMathFlags::NoInfs); } void setHasNoSignedZeros(bool B) { - SubclassOptionalData = - (SubclassOptionalData & ~FastMathFlags::NoSignedZeros) | - (B * FastMathFlags::NoSignedZeros); + ValueSubclassData().Flags = + (ValueSubclassData().Flags & ~FastMathFlags::NoSignedZeros) | + (B * FastMathFlags::NoSignedZeros); } void setHasAllowReciprocal(bool B) { - SubclassOptionalData = - (SubclassOptionalData & ~FastMathFlags::AllowReciprocal) | - (B * FastMathFlags::AllowReciprocal); + ValueSubclassData().Flags = + (ValueSubclassData().Flags & ~FastMathFlags::AllowReciprocal) | + (B * FastMathFlags::AllowReciprocal); } void setHasAllowContract(bool B) { - SubclassOptionalData = - (SubclassOptionalData & ~FastMathFlags::AllowContract) | + ValueSubclassData().Flags = + (ValueSubclassData().Flags & ~FastMathFlags::AllowContract) | (B * FastMathFlags::AllowContract); } void setHasApproxFunc(bool B) { - SubclassOptionalData = - (SubclassOptionalData & ~FastMathFlags::ApproxFunc) | + ValueSubclassData().Flags = + (ValueSubclassData().Flags & ~FastMathFlags::ApproxFunc) | (B * FastMathFlags::ApproxFunc); } /// Convenience function for setting multiple fast-math flags. /// FMF is a mask of the bits to set. void setFastMathFlags(FastMathFlags FMF) { - SubclassOptionalData |= FMF.Flags; + ValueSubclassData().Flags |= FMF.Flags; } /// Convenience function for copying all fast-math flags. /// All values in FMF are transferred to this operator. void copyFastMathFlags(FastMathFlags FMF) { - SubclassOptionalData = FMF.Flags; + ValueSubclassData().Flags = FMF.Flags; } public: /// Test if this operation allows all non-strict floating-point transforms. bool isFast() const { - return ((SubclassOptionalData & FastMathFlags::AllowReassoc) != 0 && - (SubclassOptionalData & FastMathFlags::NoNaNs) != 0 && - (SubclassOptionalData & FastMathFlags::NoInfs) != 0 && - (SubclassOptionalData & FastMathFlags::NoSignedZeros) != 0 && - (SubclassOptionalData & FastMathFlags::AllowReciprocal) != 0 && - (SubclassOptionalData & FastMathFlags::AllowContract) != 0 && - (SubclassOptionalData & FastMathFlags::ApproxFunc) != 0); + const unsigned AllowAllMask = + FastMathFlags::AllowReassoc | + FastMathFlags::NoNaNs | + FastMathFlags::NoInfs | + FastMathFlags::NoSignedZeros | + FastMathFlags::AllowReciprocal | + FastMathFlags::AllowContract | + FastMathFlags::ApproxFunc; + return (ValueSubclassData().Flags & AllowAllMask) == AllowAllMask; } /// Test if this operation may be simplified with reassociative transforms. bool hasAllowReassoc() const { - return (SubclassOptionalData & FastMathFlags::AllowReassoc) != 0; + return (ValueSubclassData().Flags & FastMathFlags::AllowReassoc) != 0; } /// Test if this operation's arguments and results are assumed not-NaN. bool hasNoNaNs() const { - return (SubclassOptionalData & FastMathFlags::NoNaNs) != 0; + return (ValueSubclassData().Flags & FastMathFlags::NoNaNs) != 0; } /// Test if this operation's arguments and results are assumed not-infinite. bool hasNoInfs() const { - return (SubclassOptionalData & FastMathFlags::NoInfs) != 0; + return (ValueSubclassData().Flags & FastMathFlags::NoInfs) != 0; } /// Test if this operation can ignore the sign of zero. bool hasNoSignedZeros() const { - return (SubclassOptionalData & FastMathFlags::NoSignedZeros) != 0; + return (ValueSubclassData().Flags & FastMathFlags::NoSignedZeros) != 0; } /// Test if this operation can use reciprocal multiply instead of division. bool hasAllowReciprocal() const { - return (SubclassOptionalData & FastMathFlags::AllowReciprocal) != 0; + return (ValueSubclassData().Flags & FastMathFlags::AllowReciprocal) != 0; } /// Test if this operation can be floating-point contracted (FMA). bool hasAllowContract() const { - return (SubclassOptionalData & FastMathFlags::AllowContract) != 0; + return (ValueSubclassData().Flags & FastMathFlags::AllowContract) != 0; } /// Test if this operation allows approximations of math library functions or /// intrinsics. bool hasApproxFunc() const { - return (SubclassOptionalData & FastMathFlags::ApproxFunc) != 0; + return (ValueSubclassData().Flags & FastMathFlags::ApproxFunc) != 0; } /// Convenience function for getting all the fast-math flags FastMathFlags getFastMathFlags() const { - return FastMathFlags(SubclassOptionalData); + return FastMathFlags(ValueSubclassData().Flags); } /// Get the maximum error permitted by this operation in ULPs. An accuracy of @@ -455,27 +492,28 @@ friend class GetElementPtrInst; friend class ConstantExpr; + BEGIN_VALUE_SUBCLASS_DATA(GEPOperator) + ADD_VALUE_SUBCLASS_BITFIELD(bool, 1, IsInBounds) + ADD_VALUE_SUBCLASS_BITFIELD(unsigned, 6, InRangeIndex) + END_VALUE_SUBCLASS_DATA() + enum { IsInBounds = (1 << 0), // InRangeIndex: bits 1-6 }; - void setIsInBounds(bool B) { - SubclassOptionalData = - (SubclassOptionalData & ~IsInBounds) | (B * IsInBounds); - } + void setIsInBounds(bool B) { ValueSubclassData().IsInBounds = B; } public: /// Test whether this is an inbounds GEP, as defined by LangRef.html. - bool isInBounds() const { - return SubclassOptionalData & IsInBounds; - } + bool isInBounds() const { return ValueSubclassData().IsInBounds; } /// Returns the offset of the index with an inrange attachment, or None if /// none. Optional getInRangeIndex() const { - if (SubclassOptionalData >> 1 == 0) return None; - return (SubclassOptionalData >> 1) - 1; + unsigned InRangeIndex = ValueSubclassData().InRangeIndex; + if (InRangeIndex == 0) return None; + return InRangeIndex - 1; } inline op_iterator idx_begin() { return op_begin()+1; } Index: llvm/include/llvm/IR/Type.h =================================================================== --- llvm/include/llvm/IR/Type.h +++ llvm/include/llvm/IR/Type.h @@ -17,6 +17,7 @@ #include "llvm/ADT/APFloat.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SubclassData.h" #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" @@ -80,25 +81,17 @@ /// This refers to the LLVMContext in which this type was uniqued. LLVMContext &Context; - TypeID ID : 8; // The current base type of this type. - unsigned SubclassData : 24; // Space for subclasses to store data. - // Note that this should be synchronized with - // MAX_INT_BITS value in IntegerType class. + BEGIN_PACKED_BITFIELDS(32) + ADD_PACKED_BITFIELD(TypeID, 8, ID) // The current base type of this type. + END_PACKED_BITFIELDS(); protected: friend class LLVMContextImpl; - explicit Type(LLVMContext &C, TypeID tid) - : Context(C), ID(tid), SubclassData(0) {} + explicit Type(LLVMContext &C, TypeID tid) : Context(C) { ID = tid; } ~Type() = default; - unsigned getSubclassData() const { return SubclassData; } - - void setSubclassData(unsigned val) { - SubclassData = val; - // Ensure we don't have any accidental truncation. - assert(getSubclassData() == val && "Subclass data too large for field"); - } + DECLARE_SUBCLASS_DATA(Type) /// Keeps track of how many Type*'s there are in the ContainedTys list. unsigned NumContainedTys = 0; @@ -493,6 +486,15 @@ return reinterpret_cast(const_cast(Tys)); } +#define BEGIN_TYPE_SUBCLASS_DATA(Class) \ + BEGIN_SUBCLASS_DATA(Type, Class) + +#define ADD_TYPE_SUBCLASS_BITFIELD(Ty, Bits, Name) \ + ADD_SUBCLASS_BITFIELD(Type, Ty, Bits, Name) + +#define END_TYPE_SUBCLASS_DATA() \ + END_SUBCLASS_DATA(Type) + } // end namespace llvm #endif // LLVM_IR_TYPE_H Index: llvm/include/llvm/IR/User.h =================================================================== --- llvm/include/llvm/IR/User.h +++ llvm/include/llvm/IR/User.h @@ -49,6 +49,17 @@ allocateFixedOperandUser(size_t, unsigned, unsigned); protected: + BEGIN_VALUE_SUBCLASS_DATA(User) + ADD_VALUE_SUBCLASS_BITFIELD(bool, -1, HasDescriptor) + ADD_VALUE_SUBCLASS_BITFIELD(bool, -1, HasHungOffUses) + ADD_VALUE_SUBCLASS_BITFIELD(unsigned, -30, NumOperands) + END_VALUE_SUBCLASS_DATA() + + static constexpr unsigned SubclassOptionalDataMaxBitSize = 7; + static constexpr unsigned SubclassOptionalDataMinBitOffset = + bit_offsetof() - + SubclassOptionalDataMaxBitSize; + /// Allocate a User with an operand pointer co-allocated. /// /// This is used for subclasses which need to allocate a variable number @@ -70,16 +81,14 @@ /// This is used for subclasses which have a fixed number of operands. void *operator new(size_t Size, unsigned Us, unsigned DescBytes); - User(Type *ty, unsigned vty, Use *, unsigned NumOps) - : Value(ty, vty) { - assert(NumOps < (1u << NumUserOperandsBits) && "Too many operands"); - NumUserOperands = NumOps; - // If we have hung off uses, then the operand list should initially be - // null. - assert((!HasHungOffUses || !getOperandList()) && - "Error in initializing hung off uses for User"); + User(Type* ty, unsigned vty, Use*, unsigned NumOps); + + void setNumOperands(unsigned NumOps) { + ValueSubclassData().NumOperands = NumOps; } + bool hasHungOffUses() const { return ValueSubclassData().HasHungOffUses; } + /// Allocate the array of Uses, followed by a pointer /// (with bottom bit set) to the User. /// \param IsPhi identifies callers which are phi nodes and which need @@ -101,8 +110,8 @@ /// Placement delete - required by std, called if the ctor throws. void operator delete(void *Usr, unsigned) { // Note: If a subclass manipulates the information which is required to calculate the - // Usr memory pointer, e.g. NumUserOperands, the operator delete of that subclass has - // to restore the changed information to the original value, since the dtor of that class + // Usr memory pointer, e.g. SubclassData1, the operator delete of that subclass has to + // restore the changed information to the original value, since the dtor of that class // is not called if the ctor fails. User::operator delete(Usr); @@ -113,8 +122,8 @@ /// Placement delete - required by std, called if the ctor throws. void operator delete(void *Usr, unsigned, unsigned) { // Note: If a subclass manipulates the information which is required to calculate the - // Usr memory pointer, e.g. NumUserOperands, the operator delete of that subclass has - // to restore the changed information to the original value, since the dtor of that class + // Usr memory pointer, e.g. SubclassData1, the operator delete of that subclass has to + // restore the changed information to the original value, since the dtor of that class // is not called if the ctor fails. User::operator delete(Usr); @@ -145,34 +154,34 @@ Use *&getHungOffOperands() { return *(reinterpret_cast(this) - 1); } const Use *getIntrusiveOperands() const { - return reinterpret_cast(this) - NumUserOperands; + return reinterpret_cast(this) - getNumOperands(); } Use *getIntrusiveOperands() { - return reinterpret_cast(this) - NumUserOperands; + return reinterpret_cast(this) - getNumOperands(); } void setOperandList(Use *NewList) { - assert(HasHungOffUses && + assert(hasHungOffUses() && "Setting operand list only required for hung off uses"); getHungOffOperands() = NewList; } public: const Use *getOperandList() const { - return HasHungOffUses ? getHungOffOperands() : getIntrusiveOperands(); + return hasHungOffUses() ? getHungOffOperands() : getIntrusiveOperands(); } Use *getOperandList() { return const_cast(static_cast(this)->getOperandList()); } Value *getOperand(unsigned i) const { - assert(i < NumUserOperands && "getOperand() out of range!"); + assert(i < getNumOperands() && "getOperand() out of range!"); return getOperandList()[i]; } void setOperand(unsigned i, Value *Val) { - assert(i < NumUserOperands && "setOperand() out of range!"); + assert(i < getNumOperands() && "setOperand() out of range!"); assert((!isa((const Value*)this) || isa((const Value*)this)) && "Cannot mutate a constant with setOperand!"); @@ -180,15 +189,15 @@ } const Use &getOperandUse(unsigned i) const { - assert(i < NumUserOperands && "getOperandUse() out of range!"); + assert(i < getNumOperands() && "getOperandUse() out of range!"); return getOperandList()[i]; } Use &getOperandUse(unsigned i) { - assert(i < NumUserOperands && "getOperandUse() out of range!"); + assert(i < getNumOperands() && "getOperandUse() out of range!"); return getOperandList()[i]; } - unsigned getNumOperands() const { return NumUserOperands; } + unsigned getNumOperands() const { return ValueSubclassData().NumOperands; } /// Returns the descriptor co-allocated with this User instance. ArrayRef getDescriptor() const; @@ -206,16 +215,15 @@ /// 1 operand before delete. void setGlobalVariableNumOperands(unsigned NumOps) { assert(NumOps <= 1 && "GlobalVariable can only have 0 or 1 operands"); - NumUserOperands = NumOps; + setNumOperands(NumOps); } /// Subclasses with hung off uses need to manage the operand count /// themselves. In these instances, the operand count isn't used to find the /// OperandList, so there's no issue in having the operand count change. void setNumHungOffUseOperands(unsigned NumOps) { - assert(HasHungOffUses && "Must have hung off uses to use this method"); - assert(NumOps < (1u << NumUserOperandsBits) && "Too many operands"); - NumUserOperands = NumOps; + assert(hasHungOffUses() && "Must have hung off uses to use this method"); + setNumOperands(NumOps); } // --------------------------------------------------------------------------- @@ -229,10 +237,10 @@ op_iterator op_begin() { return getOperandList(); } const_op_iterator op_begin() const { return getOperandList(); } op_iterator op_end() { - return getOperandList() + NumUserOperands; + return getOperandList() + getNumOperands(); } const_op_iterator op_end() const { - return getOperandList() + NumUserOperands; + return getOperandList() + getNumOperands(); } op_range operands() { return op_range(op_begin(), op_end()); @@ -329,6 +337,15 @@ } }; +#define ADD_VALUE_SUBCLASS_OPTIONALDATA() \ + ADD_VALUE_SUBCLASS_BITFIELD(unsigned, -int(SubclassOptionalDataMaxBitSize), \ + OptionalData) \ + NEXT_OPTIONAL_DATA; \ + static_assert(SubclassOptionalDataMinBitOffset == \ + bit_offsetof(), \ + "Invalid offset of subclass OptionalData!"); \ + typedef NEXT_OPTIONAL_DATA + } // end namespace llvm #endif // LLVM_IR_USER_H Index: llvm/include/llvm/IR/Value.h =================================================================== --- llvm/include/llvm/IR/Value.h +++ llvm/include/llvm/IR/Value.h @@ -15,6 +15,7 @@ #include "llvm-c/Types.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SubclassData.h" #include "llvm/ADT/iterator_range.h" #include "llvm/IR/Use.h" #include "llvm/Support/Alignment.h" @@ -80,26 +81,18 @@ friend class ValueAsMetadata; // Allow access to IsUsedByMD. friend class ValueHandleBase; - const unsigned char SubclassID; // Subclass identifier (for isa/dyn_cast) - unsigned char HasValueHandle : 1; // Has a ValueHandle pointing to this? + BEGIN_PACKED_BITFIELDS(64) + // Subclass identifier (for isa/dyn_cast) + ADD_PACKED_BITFIELD(unsigned, 8, SubclassID) + // Has a ValueHandle pointing to this? + ADD_PACKED_BITFIELD(bool, 1, HasValueHandle) + ADD_PACKED_BITFIELD(bool, 1, HasName) + ADD_PACKED_BITFIELD(bool, 1, IsUsedByMD) + END_PACKED_BITFIELDS(); protected: - /// Hold subclass data that can be dropped. - /// - /// This member is similar to SubclassData, however it is for holding - /// information which may be used to aid optimization, but which may be - /// cleared to zero without affecting conservative interpretation. - unsigned char SubclassOptionalData : 7; + DECLARE_SUBCLASS_DATA(Value) -private: - /// Hold arbitrary subclass data. - /// - /// This member is defined by this class, but is not used for anything. - /// Subclasses can use it to hold whatever state they find useful. This - /// field is initialized to zero by the ctor. - unsigned short SubclassData; - -protected: /// The number of operands in the subclass. /// /// This member is defined by this class, but not used for anything. @@ -112,14 +105,7 @@ /// /// Note, this should *NOT* be used directly by any class other than User. /// User uses this value to find the Use list. - enum : unsigned { NumUserOperandsBits = 28 }; - unsigned NumUserOperands : NumUserOperandsBits; - - // Use the same type as the bitfield above so that MSVC will pack them. - unsigned IsUsedByMD : 1; - unsigned HasName : 1; - unsigned HasHungOffUses : 1; - unsigned HasDescriptor : 1; + private: template // UseT == 'Use' or 'const Use' @@ -203,7 +189,7 @@ }; protected: - Value(Type *Ty, unsigned scid); + Value(Type *Ty, unsigned scid, uint64_t PreservedSubclassDataMask = 0); /// Value's destructor should be virtual by design, but that would require /// that Value and all of its subclasses have a vtable that effectively @@ -485,23 +471,6 @@ return SubclassID; } - /// Return the raw optional flags value contained in this value. - /// - /// This should only be used when testing two Values for equivalence. - unsigned getRawSubclassOptionalData() const { - return SubclassOptionalData; - } - - /// Clear the optional flags contained in this value. - void clearSubclassOptionalData() { - SubclassOptionalData = 0; - } - - /// Check the optional flags for equality. - bool hasSameSubclassOptionalData(const Value *V) const { - return SubclassOptionalData == V->SubclassOptionalData; - } - /// Return true if there is a value handle associated with this value. bool hasValueHandle() const { return HasValueHandle; } @@ -709,10 +678,6 @@ return Merged; } - -protected: - unsigned short getSubclassDataFromValue() const { return SubclassData; } - void setValueSubclassData(unsigned short D) { SubclassData = D; } }; struct ValueDeleter { void operator()(Value *V) { V->deleteValue(); } }; @@ -922,6 +887,15 @@ return reinterpret_cast(const_cast(Vals)); } +#define BEGIN_VALUE_SUBCLASS_DATA(Class) \ + BEGIN_SUBCLASS_DATA(Value, Class) + +#define ADD_VALUE_SUBCLASS_BITFIELD(Type, Bits, Name) \ + ADD_SUBCLASS_BITFIELD(Value, Type, Bits, Name) + +#define END_VALUE_SUBCLASS_DATA() \ + END_SUBCLASS_DATA(Value) + } // end namespace llvm #endif // LLVM_IR_VALUE_H Index: llvm/include/llvm/Support/AtomicOrdering.h =================================================================== --- llvm/include/llvm/Support/AtomicOrdering.h +++ llvm/include/llvm/Support/AtomicOrdering.h @@ -53,7 +53,7 @@ /// /// not_atomic-->unordered-->relaxed-->release--------------->acq_rel-->seq_cst /// \-->consume-->acquire--/ -enum class AtomicOrdering { +enum class AtomicOrdering : unsigned { NotAtomic = 0, Unordered = 1, Monotonic = 2, // Equivalent to C++'s relaxed. Index: llvm/include/llvm/Support/type_traits.h =================================================================== --- llvm/include/llvm/Support/type_traits.h +++ llvm/include/llvm/Support/type_traits.h @@ -14,6 +14,7 @@ #define LLVM_SUPPORT_TYPE_TRAITS_H #include "llvm/Support/Compiler.h" +#include #include #include @@ -39,6 +40,21 @@ std::is_convertible::value); }; +template struct smallest_integral { + using type = typename std::conditional< + BitCount <= 8, typename std::conditional::type, + typename std::conditional< + BitCount <= 16, + typename std::conditional::type, + typename std::conditional< + BitCount <= 32, + typename std::conditional::type, + typename std::conditional< + BitCount <= 64, + typename std::conditional::type, + void>::type>::type>::type>::type; +}; + /// If T is a pointer, just return it. If it is not, return T&. template struct add_lvalue_reference_if_not_pointer { using type = T &; }; Index: llvm/include/llvm/Transforms/Utils/FunctionComparator.h =================================================================== --- llvm/include/llvm/Transforms/Utils/FunctionComparator.h +++ llvm/include/llvm/Transforms/Utils/FunctionComparator.h @@ -257,7 +257,7 @@ /// 1. Operations opcodes. Compared as numbers. /// 2. Number of operands. /// 3. Operation types. Compared with cmpType method. - /// 4. Compare operation subclass optional data as stream of bytes: + /// 4. Compare operator data as stream of bytes: /// just convert it to integers and call cmpNumbers. /// 5. Compare in operation operand types with cmpType in /// most significant operand first order. @@ -329,6 +329,7 @@ private: int cmpOrderings(AtomicOrdering L, AtomicOrdering R) const; + int cmpFastMathFlags(FastMathFlags L, FastMathFlags R) const; int cmpInlineAsm(const InlineAsm *L, const InlineAsm *R) const; int cmpAttrs(const AttributeList L, const AttributeList R) const; int cmpRangeMetadata(const MDNode *L, const MDNode *R) const; Index: llvm/lib/IR/Constants.cpp =================================================================== --- llvm/lib/IR/Constants.cpp +++ llvm/lib/IR/Constants.cpp @@ -1332,8 +1332,8 @@ OnlyIfReducedTy); default: assert(getNumOperands() == 2 && "Must be binary operator?"); - return ConstantExpr::get(getOpcode(), Ops[0], Ops[1], SubclassOptionalData, - OnlyIfReducedTy); + return ConstantExpr::get(getOpcode(), Ops[0], Ops[1], + ValueSubclassData().OptionalData, OnlyIfReducedTy); } } @@ -2115,11 +2115,11 @@ ArgVec.push_back(Idx); } - unsigned SubClassOptionalData = InBounds ? GEPOperator::IsInBounds : 0; + unsigned OptionalData = InBounds ? GEPOperator::IsInBounds : 0; if (InRangeIndex && *InRangeIndex < 63) - SubClassOptionalData |= (*InRangeIndex + 1) << 1; + OptionalData |= (*InRangeIndex + 1) << 1; const ConstantExprKeyType Key(Instruction::GetElementPtr, ArgVec, 0, - SubClassOptionalData, None, Ty); + OptionalData, None, Ty); LLVMContextImpl *pImpl = C->getContext().pImpl; return pImpl->ExprConstants.getOrCreate(ReqTy, Key); @@ -3098,13 +3098,14 @@ BinaryOperator::Create((Instruction::BinaryOps)getOpcode(), Ops[0], Ops[1]); if (isa(BO)) { - BO->setHasNoUnsignedWrap(SubclassOptionalData & + BO->setHasNoUnsignedWrap(ValueSubclassData().OptionalData & OverflowingBinaryOperator::NoUnsignedWrap); - BO->setHasNoSignedWrap(SubclassOptionalData & + BO->setHasNoSignedWrap(ValueSubclassData().OptionalData & OverflowingBinaryOperator::NoSignedWrap); } if (isa(BO)) - BO->setIsExact(SubclassOptionalData & PossiblyExactOperator::IsExact); + BO->setIsExact(ValueSubclassData().OptionalData & + PossiblyExactOperator::IsExact); return BO; } } Index: llvm/lib/IR/ConstantsContext.h =================================================================== --- llvm/lib/IR/ConstantsContext.h +++ llvm/lib/IR/ConstantsContext.h @@ -66,7 +66,7 @@ : ConstantExpr(C1->getType(), Opcode, &Op<0>(), 2) { Op<0>() = C1; Op<1>() = C2; - SubclassOptionalData = Flags; + ValueSubclassData().OptionalData = Flags; } // allocate space for exactly two operands @@ -244,7 +244,7 @@ Type *DestTy, unsigned Flags) { GetElementPtrConstantExpr *Result = new (IdxList.size() + 1) GetElementPtrConstantExpr(SrcElementTy, C, IdxList, DestTy); - Result->SubclassOptionalData = Flags; + Result->ValueSubclassData().OptionalData = Flags; return Result; } @@ -478,7 +478,7 @@ ConstantExprKeyType(ArrayRef Operands, const ConstantExpr *CE) : Opcode(CE->getOpcode()), - SubclassOptionalData(CE->getRawSubclassOptionalData()), + SubclassOptionalData(CE->ValueSubclassData().OptionalData), SubclassData(CE->isCompare() ? CE->getPredicate() : 0), Ops(Operands), Indexes(CE->hasIndices() ? CE->getIndices() : ArrayRef()), ExplicitTy(nullptr) {} @@ -486,7 +486,7 @@ ConstantExprKeyType(const ConstantExpr *CE, SmallVectorImpl &Storage) : Opcode(CE->getOpcode()), - SubclassOptionalData(CE->getRawSubclassOptionalData()), + SubclassOptionalData(CE->ValueSubclassData().OptionalData), SubclassData(CE->isCompare() ? CE->getPredicate() : 0), Indexes(CE->hasIndices() ? CE->getIndices() : ArrayRef()), ExplicitTy(nullptr) { @@ -505,7 +505,7 @@ bool operator==(const ConstantExpr *CE) const { if (Opcode != CE->getOpcode()) return false; - if (SubclassOptionalData != CE->getRawSubclassOptionalData()) + if (SubclassOptionalData != CE->ValueSubclassData().OptionalData) return false; if (Ops.size() != CE->getNumOperands()) return false; Index: llvm/lib/IR/Function.cpp =================================================================== --- llvm/lib/IR/Function.cpp +++ llvm/lib/IR/Function.cpp @@ -265,7 +265,6 @@ NumArgs(Ty->getNumParams()) { assert(FunctionType::isValidReturnType(getReturnType()) && "invalid return type"); - setGlobalObjectSubClassData(0); // We only need a symbol table for a function if the context keeps value names if (!getContext().shouldDiscardValueNames()) @@ -273,7 +272,7 @@ // If the function has arguments, mark them as lazily built. if (Ty->getNumParams()) - setValueSubclassData(1); // Set the "has lazy arguments" bit. + ValueSubclassData().HasLazyArguments = true; if (ParentModule) ParentModule->getFunctionList().push_back(this); @@ -310,9 +309,7 @@ } // Clear the lazy arguments bit. - unsigned SDC = getSubclassDataFromValue(); - SDC &= ~(1 << 0); - const_cast(this)->setValueSubclassData(SDC); + const_cast(this)->ValueSubclassData().HasLazyArguments = false; assert(!hasLazyArguments()); } @@ -338,7 +335,7 @@ [](const Argument &A) { return A.use_empty(); }) && "Expected arguments to be unused in declaration"); clearArguments(); - setValueSubclassData(getSubclassDataFromValue() | (1 << 0)); + ValueSubclassData().HasLazyArguments = true; } // Nothing to steal if Src has lazy arguments. @@ -361,9 +358,8 @@ A.setName(Name); } - setValueSubclassData(getSubclassDataFromValue() & ~(1 << 0)); - assert(!hasLazyArguments()); - Src.setValueSubclassData(Src.getSubclassDataFromValue() | (1 << 0)); + ValueSubclassData().HasLazyArguments = false; + Src.ValueSubclassData().HasLazyArguments = true; } // dropAllReferences() - This function causes all the subinstructions to "let @@ -389,7 +385,9 @@ if (getNumOperands()) { User::dropAllReferences(); setNumHungOffUseOperands(0); - setValueSubclassData(getSubclassDataFromValue() & ~0xe); + ValueSubclassData().HasPrefixData = false; + ValueSubclassData().HasPrologueData = false; + ValueSubclassData().HasPersonalityFn = false; } // Metadata is stored in a side-table. @@ -499,7 +497,7 @@ } void Function::setGC(std::string Str) { - setValueSubclassDataBit(14, !Str.empty()); + ValueSubclassData().HasGC = !Str.empty(); getContext().setGC(*this, std::move(Str)); } @@ -507,7 +505,7 @@ if (!hasGC()) return; getContext().deleteGC(*this); - setValueSubclassDataBit(14, false); + ValueSubclassData().HasGC = false; } /// Copy all additional attributes (those not needed to create a Function) from @@ -1488,7 +1486,7 @@ void Function::setPersonalityFn(Constant *Fn) { setHungoffOperand<0>(Fn); - setValueSubclassDataBit(3, Fn != nullptr); + ValueSubclassData().HasPersonalityFn = Fn != nullptr; } Constant *Function::getPrefixData() const { @@ -1498,7 +1496,7 @@ void Function::setPrefixData(Constant *PrefixData) { setHungoffOperand<1>(PrefixData); - setValueSubclassDataBit(1, PrefixData != nullptr); + ValueSubclassData().HasPrefixData = PrefixData != nullptr; } Constant *Function::getPrologueData() const { @@ -1508,7 +1506,7 @@ void Function::setPrologueData(Constant *PrologueData) { setHungoffOperand<2>(PrologueData); - setValueSubclassDataBit(2, PrologueData != nullptr); + ValueSubclassData().HasPrologueData = PrologueData != nullptr; } void Function::allocHungoffUselist() { @@ -1537,14 +1535,6 @@ } } -void Function::setValueSubclassDataBit(unsigned Bit, bool On) { - assert(Bit < 16 && "SubclassData contains only 16 bits"); - if (On) - setValueSubclassData(getSubclassDataFromValue() | (1 << Bit)); - else - setValueSubclassData(getSubclassDataFromValue() & ~(1 << Bit)); -} - void Function::setEntryCount(ProfileCount Count, const DenseSet *S) { assert(Count.hasValue()); Index: llvm/lib/IR/Globals.cpp =================================================================== --- llvm/lib/IR/Globals.cpp +++ llvm/lib/IR/Globals.cpp @@ -120,9 +120,7 @@ void GlobalObject::setAlignment(MaybeAlign Align) { assert((!Align || Align <= MaximumAlignment) && "Alignment is greater than MaximumAlignment!"); - unsigned AlignmentData = encode(Align); - unsigned OldData = getGlobalValueSubClassData(); - setGlobalValueSubClassData((OldData & ~AlignmentMask) | AlignmentData); + GlobalValueSubclassData().EncodedAlignment = encode(Align); assert(MaybeAlign(getAlignment()) == Align && "Alignment representation error!"); } @@ -223,9 +221,9 @@ S = getContext().pImpl->Saver.save(S); getContext().pImpl->GlobalObjectSections[this] = S; - // Update the HasSectionHashEntryBit. Setting the section to the empty string - // means this global no longer has a section. - setGlobalObjectFlag(HasSectionHashEntryBit, !S.empty()); + // Update HasSectionHashEntry. Setting the section to the empty string means + // this global no longer has a section. + GlobalValueSubclassData().HasSectionHashEntry = !S.empty(); } bool GlobalValue::isDeclaration() const { Index: llvm/lib/IR/Instruction.cpp =================================================================== --- llvm/lib/IR/Instruction.cpp +++ llvm/lib/IR/Instruction.cpp @@ -11,10 +11,10 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/Instruction.h" -#include "llvm/IR/IntrinsicInst.h" -#include "llvm/ADT/DenseSet.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/InstVisitor.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Operator.h" #include "llvm/IR/Type.h" @@ -439,8 +439,24 @@ } bool Instruction::isIdenticalTo(const Instruction *I) const { - return isIdenticalToWhenDefined(I) && - SubclassOptionalData == I->SubclassOptionalData; + if (!isIdenticalToWhenDefined(I)) + return false; + + if (auto *OBO = dyn_cast(this)) + return OBO->hasNoUnsignedWrap() == I->hasNoUnsignedWrap() && + OBO->hasNoSignedWrap() == I->hasNoSignedWrap(); + + if (auto *PEO = dyn_cast(this)) + return PEO->isExact() == I->isExact(); + + if (auto *FPMO = dyn_cast(this)) + return FPMO->getFastMathFlags() == I->getFastMathFlags(); + + if (auto *GEPO = dyn_cast(this)) + return GEPO->isInBounds() == cast(I)->isInBounds() && + GEPO->getInRangeIndex() == cast(I)->getInRangeIndex(); + + return false; } bool Instruction::isIdenticalToWhenDefined(const Instruction *I) const { @@ -740,7 +756,6 @@ #undef HANDLE_INST } - New->SubclassOptionalData = SubclassOptionalData; New->copyMetadata(*this); return New; } Index: llvm/lib/IR/Instructions.cpp =================================================================== --- llvm/lib/IR/Instructions.cpp +++ llvm/lib/IR/Instructions.cpp @@ -109,7 +109,7 @@ allocHungoffUses(PN.getNumOperands()); std::copy(PN.op_begin(), PN.op_end(), op_begin()); std::copy(PN.block_begin(), PN.block_end(), block_begin()); - SubclassOptionalData = PN.SubclassOptionalData; + ValueSubclassData().OptionalData = PN.ValueSubclassData().OptionalData; } // removeIncomingValue - Remove an incoming value. This is useful if a @@ -443,7 +443,7 @@ std::copy(CI.op_begin(), CI.op_end(), op_begin()); std::copy(CI.bundle_op_info_begin(), CI.bundle_op_info_end(), bundle_op_info_begin()); - SubclassOptionalData = CI.SubclassOptionalData; + ValueSubclassData().OptionalData = CI.ValueSubclassData().OptionalData; } CallInst *CallInst::Create(CallInst *CI, ArrayRef OpB, @@ -454,7 +454,8 @@ Args, OpB, CI->getName(), InsertPt); NewCI->setTailCallKind(CI->getTailCallKind()); NewCI->setCallingConv(CI->getCallingConv()); - NewCI->SubclassOptionalData = CI->SubclassOptionalData; + NewCI->ValueSubclassData().OptionalData = + CI->ValueSubclassData().OptionalData; NewCI->setAttributes(CI->getAttributes()); NewCI->setDebugLoc(CI->getDebugLoc()); return NewCI; @@ -754,7 +755,6 @@ std::copy(II.op_begin(), II.op_end(), op_begin()); std::copy(II.bundle_op_info_begin(), II.bundle_op_info_end(), bundle_op_info_begin()); - SubclassOptionalData = II.SubclassOptionalData; } InvokeInst *InvokeInst::Create(InvokeInst *II, ArrayRef OpB, @@ -765,7 +765,6 @@ II->getNormalDest(), II->getUnwindDest(), Args, OpB, II->getName(), InsertPt); NewII->setCallingConv(II->getCallingConv()); - NewII->SubclassOptionalData = II->SubclassOptionalData; NewII->setAttributes(II->getAttributes()); NewII->setDebugLoc(II->getDebugLoc()); return NewII; @@ -836,7 +835,6 @@ std::copy(CBI.op_begin(), CBI.op_end(), op_begin()); std::copy(CBI.bundle_op_info_begin(), CBI.bundle_op_info_end(), bundle_op_info_begin()); - SubclassOptionalData = CBI.SubclassOptionalData; NumIndirectDests = CBI.NumIndirectDests; } @@ -850,7 +848,6 @@ CBI->getIndirectDests(), Args, OpB, CBI->getName(), InsertPt); NewCBI->setCallingConv(CBI->getCallingConv()); - NewCBI->SubclassOptionalData = CBI->SubclassOptionalData; NewCBI->setAttributes(CBI->getAttributes()); NewCBI->setDebugLoc(CBI->getDebugLoc()); NewCBI->NumIndirectDests = CBI->NumIndirectDests; @@ -867,7 +864,6 @@ RI.getNumOperands()) { if (RI.getNumOperands()) Op<0>() = RI.Op<0>(); - SubclassOptionalData = RI.SubclassOptionalData; } ReturnInst::ReturnInst(LLVMContext &C, Value *retVal, Instruction *InsertBefore) @@ -921,19 +917,15 @@ OperandTraits::op_end(this) - CRI.getNumOperands(), CRI.getNumOperands()) { - setInstructionSubclassData(CRI.getSubclassDataFromInstruction()); - Op<0>() = CRI.Op<0>(); - if (CRI.hasUnwindDest()) - Op<1>() = CRI.Op<1>(); + init(CRI.getCleanupPad(), CRI.getUnwindDest()); } void CleanupReturnInst::init(Value *CleanupPad, BasicBlock *UnwindBB) { - if (UnwindBB) - setInstructionSubclassData(getSubclassDataFromInstruction() | 1); - Op<0>() = CleanupPad; - if (UnwindBB) + if (UnwindBB) { + ValueSubclassData().HasUnwindDest = true; Op<1>() = UnwindBB; + } } CleanupReturnInst::CleanupReturnInst(Value *CleanupPad, BasicBlock *UnwindBB, @@ -1033,7 +1025,7 @@ Op<0>() = ParentPad; if (UnwindDest) { - setInstructionSubclassData(getSubclassDataFromInstruction() | 1); + ValueSubclassData().HasUnwindDest = true; setUnwindDest(UnwindDest); } } @@ -1178,7 +1170,6 @@ Op<-3>() = BI.Op<-3>(); Op<-2>() = BI.Op<-2>(); } - SubclassOptionalData = BI.SubclassOptionalData; } void BranchInst::swapSuccessors() { @@ -1249,8 +1240,7 @@ void AllocaInst::setAlignment(MaybeAlign Align) { assert((!Align || *Align <= MaximumAlignment) && "Alignment is greater than MaximumAlignment!"); - setInstructionSubclassData((getSubclassDataFromInstruction() & ~31) | - encode(Align)); + ValueSubclassData().EncodedAlignment = encode(Align); if (Align) assert(getAlignment() == Align->value() && "Alignment representation error!"); @@ -1340,8 +1330,7 @@ void LoadInst::setAlignment(MaybeAlign Align) { assert((!Align || *Align <= MaximumAlignment) && "Alignment is greater than MaximumAlignment!"); - setInstructionSubclassData((getSubclassDataFromInstruction() & ~(31 << 1)) | - (encode(Align) << 1)); + ValueSubclassData().EncodedAlignment = encode(Align); assert(getAlign() == Align && "Alignment representation error!"); } @@ -1415,8 +1404,7 @@ void StoreInst::setAlignment(MaybeAlign Alignment) { assert((!Alignment || *Alignment <= MaximumAlignment) && "Alignment is greater than MaximumAlignment!"); - setInstructionSubclassData((getSubclassDataFromInstruction() & ~(31 << 1)) | - (encode(Alignment) << 1)); + ValueSubclassData().EncodedAlignment = encode(Alignment); assert(getAlign() == Alignment && "Alignment representation error!"); } @@ -1603,7 +1591,7 @@ SourceElementType(GEPI.SourceElementType), ResultElementType(GEPI.ResultElementType) { std::copy(GEPI.op_begin(), GEPI.op_end(), op_begin()); - SubclassOptionalData = GEPI.SubclassOptionalData; + ValueSubclassData().OptionalData = GEPI.ValueSubclassData().OptionalData; } /// getIndexedType - Returns the type of the element that would be accessed with @@ -2121,7 +2109,6 @@ Indices(IVI.Indices) { Op<0>() = IVI.getOperand(0); Op<1>() = IVI.getOperand(1); - SubclassOptionalData = IVI.SubclassOptionalData; } //===----------------------------------------------------------------------===// @@ -2141,9 +2128,7 @@ ExtractValueInst::ExtractValueInst(const ExtractValueInst &EVI) : UnaryInstruction(EVI.getType(), ExtractValue, EVI.getOperand(0)), - Indices(EVI.Indices) { - SubclassOptionalData = EVI.SubclassOptionalData; -} + Indices(EVI.Indices) {} // getIndexedType - Returns the type of the element that would be extracted // with an extractvalue instruction with the specified parameters. @@ -3827,7 +3812,6 @@ OL[i] = InOL[i]; OL[i+1] = InOL[i+1]; } - SubclassOptionalData = SI.SubclassOptionalData; } /// addCase - Add an entry to the switch instruction... @@ -4052,7 +4036,6 @@ const Use *InOL = IBI.getOperandList(); for (unsigned i = 0, E = IBI.getNumOperands(); i != E; ++i) OL[i] = InOL[i]; - SubclassOptionalData = IBI.SubclassOptionalData; } /// addDestination - Add a destination. Index: llvm/lib/IR/Type.cpp =================================================================== --- llvm/lib/IR/Type.cpp +++ llvm/lib/IR/Type.cpp @@ -283,7 +283,7 @@ : Type(Result->getContext(), FunctionTyID) { Type **SubTys = reinterpret_cast(this+1); assert(isValidReturnType(Result) && "invalid return type for function"); - setSubclassData(IsVarArgs); + TypeSubclassData().IsVarArgs = IsVarArgs; SubTys[0] = Result; @@ -359,7 +359,7 @@ // The struct type was not found. Allocate one and update AnonStructTypes // in-place. ST = new (Context.pImpl->Alloc) StructType(Context); - ST->setSubclassData(SCDB_IsLiteral); // Literal struct. + ST->TypeSubclassData().IsLiteral = true; // Literal struct. ST->setBody(ETypes, isPacked); *Insertion.first = ST; } else { @@ -373,9 +373,8 @@ void StructType::setBody(ArrayRef Elements, bool isPacked) { assert(isOpaque() && "Struct body already set!"); - setSubclassData(getSubclassData() | SCDB_HasBody); - if (isPacked) - setSubclassData(getSubclassData() | SCDB_Packed); + TypeSubclassData().HasBody = true; + TypeSubclassData().Packed = isPacked; NumContainedTys = Elements.size(); @@ -478,7 +477,7 @@ } bool StructType::isSized(SmallPtrSetImpl *Visited) const { - if ((getSubclassData() & SCDB_IsSized) != 0) + if (TypeSubclassData().IsSized) return true; if (isOpaque()) return false; @@ -496,8 +495,7 @@ // Here we cheat a bit and cast away const-ness. The goal is to memoize when // we find a sized type, as types can only move from opaque to sized, not the // other way. - const_cast(this)->setSubclassData( - getSubclassData() | SCDB_IsSized); + const_cast(this)->TypeSubclassData().IsSized = true; return true; } @@ -653,7 +651,7 @@ : Type(E->getContext(), PointerTyID), PointeeTy(E) { ContainedTys = &PointeeTy; NumContainedTys = 1; - setSubclassData(AddrSpace); + TypeSubclassData().AddressSpace = AddrSpace; } PointerType *Type::getPointerTo(unsigned addrs) const { Index: llvm/lib/IR/User.cpp =================================================================== --- llvm/lib/IR/User.cpp +++ llvm/lib/IR/User.cpp @@ -17,6 +17,19 @@ // User Class //===----------------------------------------------------------------------===// +User::User(Type *ty, unsigned vty, Use *, unsigned NumOps) + : Value(ty, vty, + (bit_maskof(ValueSubclassData().HasDescriptor) | + bit_maskof(ValueSubclassData().HasHungOffUses) | + bit_maskof(ValueSubclassData().NumOperands))) { + setNumOperands(NumOps); + + // If we have hung off uses, then the operand list should initially be + // null. + assert((!hasHungOffUses() || !getOperandList()) && + "Error in initializing hung off uses for User"); +} + void User::replaceUsesOfWith(Value *From, Value *To) { if (From == To) return; // Duh what? @@ -37,7 +50,7 @@ //===----------------------------------------------------------------------===// void User::allocHungoffUses(unsigned N, bool IsPhi) { - assert(HasHungOffUses && "alloc must have hung off uses"); + assert(hasHungOffUses() && "alloc must have hung off uses"); static_assert(alignof(Use) >= alignof(Use::UserRef), "Alignment is insufficient for 'hung-off-uses' pieces"); @@ -56,7 +69,7 @@ } void User::growHungoffUses(unsigned NewNumUses, bool IsPhi) { - assert(HasHungOffUses && "realloc must have hung off uses"); + assert(hasHungOffUses() && "realloc must have hung off uses"); unsigned OldNumUses = getNumOperands(); @@ -95,8 +108,8 @@ } MutableArrayRef User::getDescriptor() { - assert(HasDescriptor && "Don't call otherwise!"); - assert(!HasHungOffUses && "Invariant!"); + assert(ValueSubclassData().HasDescriptor && "Don't call otherwise!"); + assert(!hasHungOffUses() && "Invariant!"); auto *DI = reinterpret_cast(getIntrusiveOperands()) - 1; assert(DI->SizeInBytes != 0 && "Should not have had a descriptor otherwise!"); @@ -111,8 +124,6 @@ void *User::allocateFixedOperandUser(size_t Size, unsigned Us, unsigned DescBytes) { - assert(Us < (1u << NumUserOperandsBits) && "Too many operands"); - static_assert(sizeof(DescriptorInfo) % sizeof(void *) == 0, "Required below"); unsigned DescBytesToAllocate = @@ -125,9 +136,9 @@ Use *Start = reinterpret_cast(Storage + DescBytesToAllocate); Use *End = Start + Us; User *Obj = reinterpret_cast(End); - Obj->NumUserOperands = Us; - Obj->HasHungOffUses = false; - Obj->HasDescriptor = DescBytes != 0; + Obj->setNumOperands(Us); + Obj->ValueSubclassData().HasHungOffUses = false; + Obj->ValueSubclassData().HasDescriptor = DescBytes != 0; Use::initTags(Start, End); if (DescBytes != 0) { @@ -151,9 +162,9 @@ void *Storage = ::operator new(Size + sizeof(Use *)); Use **HungOffOperandList = static_cast(Storage); User *Obj = reinterpret_cast(HungOffOperandList + 1); - Obj->NumUserOperands = 0; - Obj->HasHungOffUses = true; - Obj->HasDescriptor = false; + Obj->setNumOperands(0); + Obj->ValueSubclassData().HasHungOffUses = true; + Obj->ValueSubclassData().HasDescriptor = false; *HungOffOperandList = nullptr; return Obj; } @@ -168,24 +179,24 @@ // Hung off uses use a single Use* before the User, while other subclasses // use a Use[] allocated prior to the user. User *Obj = static_cast(Usr); - if (Obj->HasHungOffUses) { - assert(!Obj->HasDescriptor && "not supported!"); + if (Obj->hasHungOffUses()) { + assert(!Obj->ValueSubclassData().HasDescriptor && "not supported!"); Use **HungOffOperandList = static_cast(Usr) - 1; // drop the hung off uses. - Use::zap(*HungOffOperandList, *HungOffOperandList + Obj->NumUserOperands, + Use::zap(*HungOffOperandList, *HungOffOperandList + Obj->getNumOperands(), /* Delete */ true); ::operator delete(HungOffOperandList); - } else if (Obj->HasDescriptor) { - Use *UseBegin = static_cast(Usr) - Obj->NumUserOperands; - Use::zap(UseBegin, UseBegin + Obj->NumUserOperands, /* Delete */ false); + } else if (Obj->ValueSubclassData().HasDescriptor) { + Use *UseBegin = static_cast(Usr) - Obj->getNumOperands(); + Use::zap(UseBegin, UseBegin + Obj->getNumOperands(), /* Delete */ false); auto *DI = reinterpret_cast(UseBegin) - 1; uint8_t *Storage = reinterpret_cast(DI) - DI->SizeInBytes; ::operator delete(Storage); } else { - Use *Storage = static_cast(Usr) - Obj->NumUserOperands; - Use::zap(Storage, Storage + Obj->NumUserOperands, + Use *Storage = static_cast(Usr) - Obj->getNumOperands(); + Use::zap(Storage, Storage + Obj->getNumOperands(), /* Delete */ false); ::operator delete(Storage); } Index: llvm/lib/IR/Value.cpp =================================================================== --- llvm/lib/IR/Value.cpp +++ llvm/lib/IR/Value.cpp @@ -50,10 +50,12 @@ return Ty; } -Value::Value(Type *ty, unsigned scid) - : VTy(checkType(ty)), UseList(nullptr), SubclassID(scid), - HasValueHandle(0), SubclassOptionalData(0), SubclassData(0), - NumUserOperands(0), IsUsedByMD(false), HasName(false) { +Value::Value(Type *ty, unsigned scid, uint64_t PreservedSubclassDataMask) + : VTy(checkType(ty)), UseList(nullptr), + PackedBitfieldsData(PackedBitfieldsData & bit_maskof(SubclassData) & + PreservedSubclassDataMask) { + SubclassID = scid; + static_assert(ConstantFirstVal == 0, "!(SubclassID < ConstantFirstVal)"); // FIXME: Why isn't this in the subclass gunk?? // Note, we cannot call isa before the CallInst has been @@ -198,7 +200,7 @@ void Value::setValueName(ValueName *VN) { LLVMContext &Ctx = getContext(); - assert(HasName == Ctx.pImpl->ValueNames.count(this) && + assert(HasName == !!Ctx.pImpl->ValueNames.count(this) && "HasName bit out of sync!"); if (!VN) { Index: llvm/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -248,19 +248,15 @@ return OBO && OBO->hasNoSignedWrap(); } -/// Conservatively clears subclassOptionalData after a reassociation or -/// commutation. We preserve fast-math flags when applicable as they can be -/// preserved. +/// Conservatively clears OptionalData after a reassociation or commutation. +/// We preserve fast-math flags when applicable as they can be preserved. static void ClearSubclassDataAfterReassociation(BinaryOperator &I) { - FPMathOperator *FPMO = dyn_cast(&I); - if (!FPMO) { - I.clearSubclassOptionalData(); - return; + if (isa(I)) + I.setIsExact(false); + else if (isa(I)) { + I.setHasNoUnsignedWrap(false); + I.setHasNoSignedWrap(false); } - - FastMathFlags FMF = I.getFastMathFlags(); - I.clearSubclassOptionalData(); - I.setFastMathFlags(FMF); } /// Combine constant operands of associative operations either before or after a Index: llvm/lib/Transforms/Scalar/Reassociate.cpp =================================================================== --- llvm/lib/Transforms/Scalar/Reassociate.cpp +++ llvm/lib/Transforms/Scalar/Reassociate.cpp @@ -781,13 +781,15 @@ // expression tree is dominated by all of Ops. if (ExpressionChanged) do { - // Preserve FastMathFlags. - if (isa(I)) { - FastMathFlags Flags = I->getFastMathFlags(); - ExpressionChanged->clearSubclassOptionalData(); - ExpressionChanged->setFastMathFlags(Flags); - } else - ExpressionChanged->clearSubclassOptionalData(); + // Preserve FastMathFlags, clear others. + if (isa(I)) + ExpressionChanged->copyFastMathFlags(I); + else if (isa(I)) + ExpressionChanged->setIsExact(false); + else if (isa(I)) { + ExpressionChanged->setHasNoUnsignedWrap(false); + ExpressionChanged->setHasNoSignedWrap(false); + } if (ExpressionChanged == I) break; Index: llvm/lib/Transforms/Utils/FunctionComparator.cpp =================================================================== --- llvm/lib/Transforms/Utils/FunctionComparator.cpp +++ llvm/lib/Transforms/Utils/FunctionComparator.cpp @@ -63,6 +63,13 @@ return 0; } +int FunctionComparator::cmpFastMathFlags(FastMathFlags L, + FastMathFlags R) const { + if (L < R) return -1; + if (L > R) return 1; + return 0; +} + int FunctionComparator::cmpAPInts(const APInt &L, const APInt &R) const { if (int Res = cmpNumbers(L.getBitWidth(), R.getBitWidth())) return Res; @@ -500,7 +507,7 @@ // Differences from Instruction::isSameOperationAs: // * replace type comparison with calls to cmpTypes. - // * we test for I->getRawSubclassOptionalData (nuw/nsw/tail) at the top. + // * we test for OptionalData (nuw/nsw/tail) at the top. // * because of the above, we don't test for the tail bit on calls later on. if (int Res = cmpNumbers(L->getOpcode(), R->getOpcode())) return Res; @@ -520,9 +527,20 @@ if (int Res = cmpTypes(L->getType(), R->getType())) return Res; - if (int Res = cmpNumbers(L->getRawSubclassOptionalData(), - R->getRawSubclassOptionalData())) - return Res; + // Compare OptionalData. + if (isa(L)) { + if (int Res = cmpNumbers(L->hasNoUnsignedWrap(), R->hasNoUnsignedWrap())) + return Res; + if (int Res = cmpNumbers(L->hasNoSignedWrap(), R->hasNoSignedWrap())) + return Res; + } else if (isa(L)) { + if (int Res = cmpNumbers(L->isExact(), R->isExact())) + return Res; + } else if (isa(L)) { + if (int Res = + cmpFastMathFlags(L->getFastMathFlags(), R->getFastMathFlags())) + return Res; + } // We have two instructions of identical opcode and #operands. Check to see // if all operands are the same type