diff --git a/llvm/include/llvm/IR/DataLayout.h b/llvm/include/llvm/IR/DataLayout.h index 54458201af0b3..7e3345d8747c5 100644 --- a/llvm/include/llvm/IR/DataLayout.h +++ b/llvm/include/llvm/IR/DataLayout.h @@ -105,6 +105,9 @@ class DataLayout { private: bool BigEndian = false; + /// The size of a byte in bits. + unsigned ByteWidth = 8; + unsigned AllocaAddrSpace = 0; unsigned ProgramAddrSpace = 0; unsigned DefaultGlobalsAddrSpace = 0; @@ -166,6 +169,9 @@ class DataLayout { /// Internal helper method that returns requested alignment for type. Align getAlignment(Type *Ty, bool abi_or_pref) const; + /// Attempts to parse a byte specification ('b'). + Error parseByteSpec(StringRef Spec); + /// Attempts to parse primitive specification ('i', 'f', or 'v'). Error parsePrimitiveSpec(StringRef Spec); @@ -207,6 +213,9 @@ class DataLayout { bool isLittleEndian() const { return !BigEndian; } bool isBigEndian() const { return BigEndian; } + /// Returns the size of a byte, in bits. + unsigned getByteWidth() const { return ByteWidth; } + /// Returns the string representation of the DataLayout. /// /// This representation is in the same format accepted by the string @@ -518,7 +527,7 @@ class DataLayout { } unsigned getPointerTypeSize(Type *Ty) const { - return getPointerTypeSizeInBits(Ty) / 8; + return getPointerTypeSizeInBits(Ty) / ByteWidth; } /// Size examples: @@ -556,7 +565,7 @@ class DataLayout { /// For example, returns 5 for i36 and 10 for x86_fp80. TypeSize getTypeStoreSize(Type *Ty) const { TypeSize StoreSizeInBits = getTypeStoreSizeInBits(Ty); - return {StoreSizeInBits.getKnownMinValue() / 8, + return {StoreSizeInBits.getKnownMinValue() / ByteWidth, StoreSizeInBits.isScalable()}; } @@ -570,7 +579,7 @@ class DataLayout { TypeSize getTypeStoreSizeInBits(Type *Ty) const { TypeSize BaseSize = getTypeSizeInBits(Ty); uint64_t AlignedSizeInBits = - alignToPowerOf2(BaseSize.getKnownMinValue(), 8); + alignToPowerOf2(BaseSize.getKnownMinValue(), ByteWidth); return {AlignedSizeInBits, BaseSize.isScalable()}; } @@ -601,7 +610,7 @@ class DataLayout { /// This is the amount that alloca reserves for this type. For example, /// returns 96 or 128 for x86_fp80, depending on alignment. TypeSize getTypeAllocSizeInBits(Type *Ty) const { - return 8 * getTypeAllocSize(Ty); + return getTypeAllocSize(Ty) * ByteWidth; } /// Returns the minimum ABI-required alignment for the specified type. @@ -714,13 +723,14 @@ class StructLayout final : private TrailingObjects { TypeSize StructSize; Align StructAlignment; + unsigned ByteWidth; unsigned IsPadded : 1; unsigned NumElements : 31; public: TypeSize getSizeInBytes() const { return StructSize; } - TypeSize getSizeInBits() const { return 8 * StructSize; } + TypeSize getSizeInBits() const { return StructSize * ByteWidth; } Align getAlignment() const { return StructAlignment; } @@ -746,7 +756,7 @@ class StructLayout final : private TrailingObjects { } TypeSize getElementOffsetInBits(unsigned Idx) const { - return getElementOffset(Idx) * 8; + return getElementOffset(Idx) * ByteWidth; } private: diff --git a/llvm/lib/IR/DataLayout.cpp b/llvm/lib/IR/DataLayout.cpp index 49e1f898ca594..7022067259c43 100644 --- a/llvm/lib/IR/DataLayout.cpp +++ b/llvm/lib/IR/DataLayout.cpp @@ -46,7 +46,7 @@ using namespace llvm; //===----------------------------------------------------------------------===// StructLayout::StructLayout(StructType *ST, const DataLayout &DL) - : StructSize(TypeSize::getFixed(0)) { + : StructSize(TypeSize::getFixed(0)), ByteWidth(DL.getByteWidth()) { assert(!ST->isOpaque() && "Cannot get layout of opaque structs"); IsPadded = false; NumElements = ST->getNumElements(); @@ -214,6 +214,7 @@ DataLayout &DataLayout::operator=(const DataLayout &Other) { LayoutMap = nullptr; StringRepresentation = Other.StringRepresentation; BigEndian = Other.BigEndian; + ByteWidth = Other.ByteWidth; AllocaAddrSpace = Other.AllocaAddrSpace; ProgramAddrSpace = Other.ProgramAddrSpace; DefaultGlobalsAddrSpace = Other.DefaultGlobalsAddrSpace; @@ -233,7 +234,7 @@ DataLayout &DataLayout::operator=(const DataLayout &Other) { bool DataLayout::operator==(const DataLayout &Other) const { // NOTE: StringRepresentation might differ, it is not canonicalized. - return BigEndian == Other.BigEndian && + return BigEndian == Other.BigEndian && ByteWidth == Other.ByteWidth && AllocaAddrSpace == Other.AllocaAddrSpace && ProgramAddrSpace == Other.ProgramAddrSpace && DefaultGlobalsAddrSpace == Other.DefaultGlobalsAddrSpace && @@ -295,7 +296,7 @@ static Error parseSize(StringRef Str, unsigned &BitWidth, /// - the value is not a multiple of the byte width; /// - the value converted to byte amount is not not a power of two. static Error parseAlignment(StringRef Str, Align &Alignment, StringRef Name, - bool AllowZero = false) { + unsigned ByteWidth, bool AllowZero = false) { if (Str.empty()) return createStringError(Name + " alignment component cannot be empty"); @@ -310,7 +311,6 @@ static Error parseAlignment(StringRef Str, Align &Alignment, StringRef Name, return Error::success(); } - constexpr unsigned ByteWidth = 8; if (Value % ByteWidth || !isPowerOf2_32(Value / ByteWidth)) return createStringError( Name + " alignment must be a power of two times the byte width"); @@ -319,6 +319,36 @@ static Error parseAlignment(StringRef Str, Align &Alignment, StringRef Name, return Error::success(); } +Error DataLayout::parseByteSpec(StringRef Spec) { + // b: + assert(Spec.front() == 'b'); + StringRef Rest = Spec.drop_front(); + if (!Rest.consume_front(":") || Rest.empty()) + return createSpecFormatError("b:"); + + if (Error Err = parseSize(Rest, ByteWidth)) + return Err; + + if (ByteWidth != 8 && ByteWidth != 16 && ByteWidth != 32) + return createStringError("unsupported byte width"); + + // The default specs are for targets with 8-bit bytes. If the explicitly + // specified byte width is different from 8, reset the default values. + if (ByteWidth != 8) { + // Byte-sized integers must be one byte aligned. It's hard to guess + // reasonable defaults for other types, so just don't provide them + // and expect the target to do it. + IntSpecs.assign({PrimitiveSpec{ByteWidth, Align(1), Align(1)}}); + FloatSpecs.clear(); + VectorSpecs.clear(); + PointerSpecs.clear(); + StructABIAlignment = Align(1); + StructPrefAlignment = Align(1); + } + + return Error::success(); +} + Error DataLayout::parsePrimitiveSpec(StringRef Spec) { // [ifv]:[:] SmallVector Components; @@ -336,7 +366,7 @@ Error DataLayout::parsePrimitiveSpec(StringRef Spec) { // ABI alignment. Align ABIAlign; - if (Error Err = parseAlignment(Components[1], ABIAlign, "ABI")) + if (Error Err = parseAlignment(Components[1], ABIAlign, "ABI", ByteWidth)) return Err; if (Specifier == 'i' && BitWidth == 8 && ABIAlign != 1) @@ -345,7 +375,8 @@ Error DataLayout::parsePrimitiveSpec(StringRef Spec) { // Preferred alignment. Optional, defaults to the ABI alignment. Align PrefAlign = ABIAlign; if (Components.size() > 2) - if (Error Err = parseAlignment(Components[2], PrefAlign, "preferred")) + if (Error Err = + parseAlignment(Components[2], PrefAlign, "preferred", ByteWidth)) return Err; if (PrefAlign < ABIAlign) @@ -376,14 +407,15 @@ Error DataLayout::parseAggregateSpec(StringRef Spec) { // ABI alignment. Required. Can be zero, meaning use one byte alignment. Align ABIAlign; - if (Error Err = - parseAlignment(Components[1], ABIAlign, "ABI", /*AllowZero=*/true)) + if (Error Err = parseAlignment(Components[1], ABIAlign, "ABI", ByteWidth, + /*AllowZero=*/true)) return Err; // Preferred alignment. Optional, defaults to the ABI alignment. Align PrefAlign = ABIAlign; if (Components.size() > 2) - if (Error Err = parseAlignment(Components[2], PrefAlign, "preferred")) + if (Error Err = + parseAlignment(Components[2], PrefAlign, "preferred", ByteWidth)) return Err; if (PrefAlign < ABIAlign) @@ -437,14 +469,15 @@ Error DataLayout::parsePointerSpec(StringRef Spec) { // ABI alignment. Required, cannot be zero. Align ABIAlign; - if (Error Err = parseAlignment(Components[2], ABIAlign, "ABI")) + if (Error Err = parseAlignment(Components[2], ABIAlign, "ABI", ByteWidth)) return Err; // Preferred alignment. Optional, defaults to the ABI alignment. // Cannot be zero. Align PrefAlign = ABIAlign; if (Components.size() > 3) - if (Error Err = parseAlignment(Components[3], PrefAlign, "preferred")) + if (Error Err = + parseAlignment(Components[3], PrefAlign, "preferred", ByteWidth)) return Err; if (PrefAlign < ABIAlign) @@ -528,7 +561,7 @@ Error DataLayout::parseSpecification( if (Rest.empty()) return createSpecFormatError("S"); Align Alignment; - if (Error Err = parseAlignment(Rest, Alignment, "stack natural")) + if (Error Err = parseAlignment(Rest, Alignment, "stack natural", ByteWidth)) return Err; StackNaturalAlign = Alignment; break; @@ -551,7 +584,7 @@ Error DataLayout::parseSpecification( Twine(Type) + "'"); } Align Alignment; - if (Error Err = parseAlignment(Rest, Alignment, "ABI")) + if (Error Err = parseAlignment(Rest, Alignment, "ABI", ByteWidth)) return Err; FunctionPtrAlign = Alignment; break; @@ -623,10 +656,25 @@ Error DataLayout::parseLayoutString(StringRef LayoutString) { // Split the data layout string into specifications separated by '-' and // parse each specification individually, updating internal data structures. - SmallVector NonIntegralAddressSpaces; - for (StringRef Spec : split(LayoutString, '-')) { + SmallVector Specs; + LayoutString.split(Specs, '-'); + + // On the first pass, diagnose empty specifications and parse the byte + // specification if there is one. The latter is necessary because other + // specifications may need the byte width for validation and to convert + // bit alignments to byte alignments. + for (StringRef Spec : Specs) { if (Spec.empty()) return createStringError("empty specification is not allowed"); + if (Spec.front() == 'b') + if (Error Err = parseByteSpec(Spec)) + return Err; + } + + SmallVector NonIntegralAddressSpaces; + for (StringRef Spec : split(LayoutString, '-')) { + if (Spec.front() == 'b') + continue; if (Error Err = parseSpecification(Spec, NonIntegralAddressSpaces)) return Err; } @@ -674,6 +722,7 @@ void DataLayout::setPrimitiveSpec(char Specifier, uint32_t BitWidth, const DataLayout::PointerSpec & DataLayout::getPointerSpec(uint32_t AddrSpace) const { + assert(!PointerSpecs.empty() && "No pointer specs are defined"); if (AddrSpace != 0) { auto I = lower_bound(PointerSpecs, AddrSpace, LessPointerAddrSpace()); if (I != PointerSpecs.end() && I->AddrSpace == AddrSpace) @@ -752,7 +801,7 @@ Align DataLayout::getPointerPrefAlignment(unsigned AS) const { } unsigned DataLayout::getPointerSize(unsigned AS) const { - return divideCeil(getPointerSpec(AS).BitWidth, 8); + return divideCeil(getPointerSpec(AS).BitWidth, ByteWidth); } unsigned DataLayout::getPointerTypeSizeInBits(Type *Ty) const { @@ -763,7 +812,7 @@ unsigned DataLayout::getPointerTypeSizeInBits(Type *Ty) const { } unsigned DataLayout::getIndexSize(unsigned AS) const { - return divideCeil(getPointerSpec(AS).IndexBitWidth, 8); + return divideCeil(getPointerSpec(AS).IndexBitWidth, ByteWidth); } unsigned DataLayout::getIndexTypeSizeInBits(Type *Ty) const { @@ -827,7 +876,7 @@ Align DataLayout::getAlignment(Type *Ty, bool abi_or_pref) const { // approximation of reality, and if the user wanted something less // less conservative, they should have specified it explicitly in the data // layout. - return Align(PowerOf2Ceil(BitWidth / 8)); + return Align(PowerOf2Ceil(BitWidth / ByteWidth)); } case Type::FixedVectorTyID: case Type::ScalableVectorTyID: {