Skip to content

Commit 670e94d

Browse files
committed
[DataLayout] Add byte specification
This patch adds byte specification to data layout string. The specification is `b:<size>`, where `<size>` is the size of a byte in bits (later referred to as "byte width"). Limitations: * The only values allowed for byte width are 8, 16, and 32. 16-bit bytes are popular, and my downstream target has 32-bit bytes. These are the widths I'm going to add tests for in follow-up patches, so this restriction only exists because other widths are untested. * It is assumed that bytes are the same in all address spaces. Supporting different byte widths in different address spaces would require adding an address space argument to all DataLayout methods that query ABI / preferred alignments because they return *byte* alignments, and those will be different for different address spaces. This is too much effort, but it can be done in the future if the need arises, the specification reserves address space number before ':'.
1 parent af456df commit 670e94d

File tree

2 files changed

+83
-24
lines changed

2 files changed

+83
-24
lines changed

llvm/include/llvm/IR/DataLayout.h

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ class DataLayout {
105105
private:
106106
bool BigEndian = false;
107107

108+
/// The size of a byte in bits.
109+
unsigned ByteWidth = 8;
110+
108111
unsigned AllocaAddrSpace = 0;
109112
unsigned ProgramAddrSpace = 0;
110113
unsigned DefaultGlobalsAddrSpace = 0;
@@ -166,6 +169,9 @@ class DataLayout {
166169
/// Internal helper method that returns requested alignment for type.
167170
Align getAlignment(Type *Ty, bool abi_or_pref) const;
168171

172+
/// Attempts to parse a byte specification ('b').
173+
Error parseByteSpec(StringRef Spec);
174+
169175
/// Attempts to parse primitive specification ('i', 'f', or 'v').
170176
Error parsePrimitiveSpec(StringRef Spec);
171177

@@ -207,6 +213,9 @@ class DataLayout {
207213
bool isLittleEndian() const { return !BigEndian; }
208214
bool isBigEndian() const { return BigEndian; }
209215

216+
/// Returns the size of a byte, in bits.
217+
unsigned getByteWidth() const { return ByteWidth; }
218+
210219
/// Returns the string representation of the DataLayout.
211220
///
212221
/// This representation is in the same format accepted by the string
@@ -518,7 +527,7 @@ class DataLayout {
518527
}
519528

520529
unsigned getPointerTypeSize(Type *Ty) const {
521-
return getPointerTypeSizeInBits(Ty) / 8;
530+
return getPointerTypeSizeInBits(Ty) / ByteWidth;
522531
}
523532

524533
/// Size examples:
@@ -556,7 +565,7 @@ class DataLayout {
556565
/// For example, returns 5 for i36 and 10 for x86_fp80.
557566
TypeSize getTypeStoreSize(Type *Ty) const {
558567
TypeSize StoreSizeInBits = getTypeStoreSizeInBits(Ty);
559-
return {StoreSizeInBits.getKnownMinValue() / 8,
568+
return {StoreSizeInBits.getKnownMinValue() / ByteWidth,
560569
StoreSizeInBits.isScalable()};
561570
}
562571

@@ -570,7 +579,7 @@ class DataLayout {
570579
TypeSize getTypeStoreSizeInBits(Type *Ty) const {
571580
TypeSize BaseSize = getTypeSizeInBits(Ty);
572581
uint64_t AlignedSizeInBits =
573-
alignToPowerOf2(BaseSize.getKnownMinValue(), 8);
582+
alignToPowerOf2(BaseSize.getKnownMinValue(), ByteWidth);
574583
return {AlignedSizeInBits, BaseSize.isScalable()};
575584
}
576585

@@ -601,7 +610,7 @@ class DataLayout {
601610
/// This is the amount that alloca reserves for this type. For example,
602611
/// returns 96 or 128 for x86_fp80, depending on alignment.
603612
TypeSize getTypeAllocSizeInBits(Type *Ty) const {
604-
return 8 * getTypeAllocSize(Ty);
613+
return getTypeAllocSize(Ty) * ByteWidth;
605614
}
606615

607616
/// Returns the minimum ABI-required alignment for the specified type.
@@ -714,13 +723,14 @@ class StructLayout final : private TrailingObjects<StructLayout, TypeSize> {
714723

715724
TypeSize StructSize;
716725
Align StructAlignment;
726+
unsigned ByteWidth;
717727
unsigned IsPadded : 1;
718728
unsigned NumElements : 31;
719729

720730
public:
721731
TypeSize getSizeInBytes() const { return StructSize; }
722732

723-
TypeSize getSizeInBits() const { return 8 * StructSize; }
733+
TypeSize getSizeInBits() const { return StructSize * ByteWidth; }
724734

725735
Align getAlignment() const { return StructAlignment; }
726736

@@ -746,7 +756,7 @@ class StructLayout final : private TrailingObjects<StructLayout, TypeSize> {
746756
}
747757

748758
TypeSize getElementOffsetInBits(unsigned Idx) const {
749-
return getElementOffset(Idx) * 8;
759+
return getElementOffset(Idx) * ByteWidth;
750760
}
751761

752762
private:

llvm/lib/IR/DataLayout.cpp

Lines changed: 67 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ using namespace llvm;
4646
//===----------------------------------------------------------------------===//
4747

4848
StructLayout::StructLayout(StructType *ST, const DataLayout &DL)
49-
: StructSize(TypeSize::getFixed(0)) {
49+
: StructSize(TypeSize::getFixed(0)), ByteWidth(DL.getByteWidth()) {
5050
assert(!ST->isOpaque() && "Cannot get layout of opaque structs");
5151
IsPadded = false;
5252
NumElements = ST->getNumElements();
@@ -214,6 +214,7 @@ DataLayout &DataLayout::operator=(const DataLayout &Other) {
214214
LayoutMap = nullptr;
215215
StringRepresentation = Other.StringRepresentation;
216216
BigEndian = Other.BigEndian;
217+
ByteWidth = Other.ByteWidth;
217218
AllocaAddrSpace = Other.AllocaAddrSpace;
218219
ProgramAddrSpace = Other.ProgramAddrSpace;
219220
DefaultGlobalsAddrSpace = Other.DefaultGlobalsAddrSpace;
@@ -233,7 +234,7 @@ DataLayout &DataLayout::operator=(const DataLayout &Other) {
233234

234235
bool DataLayout::operator==(const DataLayout &Other) const {
235236
// NOTE: StringRepresentation might differ, it is not canonicalized.
236-
return BigEndian == Other.BigEndian &&
237+
return BigEndian == Other.BigEndian && ByteWidth == Other.ByteWidth &&
237238
AllocaAddrSpace == Other.AllocaAddrSpace &&
238239
ProgramAddrSpace == Other.ProgramAddrSpace &&
239240
DefaultGlobalsAddrSpace == Other.DefaultGlobalsAddrSpace &&
@@ -295,7 +296,7 @@ static Error parseSize(StringRef Str, unsigned &BitWidth,
295296
/// - the value is not a multiple of the byte width;
296297
/// - the value converted to byte amount is not not a power of two.
297298
static Error parseAlignment(StringRef Str, Align &Alignment, StringRef Name,
298-
bool AllowZero = false) {
299+
unsigned ByteWidth, bool AllowZero = false) {
299300
if (Str.empty())
300301
return createStringError(Name + " alignment component cannot be empty");
301302

@@ -310,7 +311,6 @@ static Error parseAlignment(StringRef Str, Align &Alignment, StringRef Name,
310311
return Error::success();
311312
}
312313

313-
constexpr unsigned ByteWidth = 8;
314314
if (Value % ByteWidth || !isPowerOf2_32(Value / ByteWidth))
315315
return createStringError(
316316
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,
319319
return Error::success();
320320
}
321321

322+
Error DataLayout::parseByteSpec(StringRef Spec) {
323+
// b:<size>
324+
assert(Spec.front() == 'b');
325+
StringRef Rest = Spec.drop_front();
326+
if (!Rest.consume_front(":") || Rest.empty())
327+
return createSpecFormatError("b:<size>");
328+
329+
if (Error Err = parseSize(Rest, ByteWidth))
330+
return Err;
331+
332+
if (ByteWidth != 8 && ByteWidth != 16 && ByteWidth != 32)
333+
return createStringError("unsupported byte width");
334+
335+
// The default specs are for targets with 8-bit bytes. If the explicitly
336+
// specified byte width is different from 8, reset the default values.
337+
if (ByteWidth != 8) {
338+
// Byte-sized integers must be one byte aligned. It's hard to guess
339+
// reasonable defaults for other types, so just don't provide them
340+
// and expect the target to do it.
341+
IntSpecs.assign({PrimitiveSpec{ByteWidth, Align(1), Align(1)}});
342+
FloatSpecs.clear();
343+
VectorSpecs.clear();
344+
PointerSpecs.clear();
345+
StructABIAlignment = Align(1);
346+
StructPrefAlignment = Align(1);
347+
}
348+
349+
return Error::success();
350+
}
351+
322352
Error DataLayout::parsePrimitiveSpec(StringRef Spec) {
323353
// [ifv]<size>:<abi>[:<pref>]
324354
SmallVector<StringRef, 3> Components;
@@ -336,7 +366,7 @@ Error DataLayout::parsePrimitiveSpec(StringRef Spec) {
336366

337367
// ABI alignment.
338368
Align ABIAlign;
339-
if (Error Err = parseAlignment(Components[1], ABIAlign, "ABI"))
369+
if (Error Err = parseAlignment(Components[1], ABIAlign, "ABI", ByteWidth))
340370
return Err;
341371

342372
if (Specifier == 'i' && BitWidth == 8 && ABIAlign != 1)
@@ -345,7 +375,8 @@ Error DataLayout::parsePrimitiveSpec(StringRef Spec) {
345375
// Preferred alignment. Optional, defaults to the ABI alignment.
346376
Align PrefAlign = ABIAlign;
347377
if (Components.size() > 2)
348-
if (Error Err = parseAlignment(Components[2], PrefAlign, "preferred"))
378+
if (Error Err =
379+
parseAlignment(Components[2], PrefAlign, "preferred", ByteWidth))
349380
return Err;
350381

351382
if (PrefAlign < ABIAlign)
@@ -376,14 +407,15 @@ Error DataLayout::parseAggregateSpec(StringRef Spec) {
376407

377408
// ABI alignment. Required. Can be zero, meaning use one byte alignment.
378409
Align ABIAlign;
379-
if (Error Err =
380-
parseAlignment(Components[1], ABIAlign, "ABI", /*AllowZero=*/true))
410+
if (Error Err = parseAlignment(Components[1], ABIAlign, "ABI", ByteWidth,
411+
/*AllowZero=*/true))
381412
return Err;
382413

383414
// Preferred alignment. Optional, defaults to the ABI alignment.
384415
Align PrefAlign = ABIAlign;
385416
if (Components.size() > 2)
386-
if (Error Err = parseAlignment(Components[2], PrefAlign, "preferred"))
417+
if (Error Err =
418+
parseAlignment(Components[2], PrefAlign, "preferred", ByteWidth))
387419
return Err;
388420

389421
if (PrefAlign < ABIAlign)
@@ -437,14 +469,15 @@ Error DataLayout::parsePointerSpec(StringRef Spec) {
437469

438470
// ABI alignment. Required, cannot be zero.
439471
Align ABIAlign;
440-
if (Error Err = parseAlignment(Components[2], ABIAlign, "ABI"))
472+
if (Error Err = parseAlignment(Components[2], ABIAlign, "ABI", ByteWidth))
441473
return Err;
442474

443475
// Preferred alignment. Optional, defaults to the ABI alignment.
444476
// Cannot be zero.
445477
Align PrefAlign = ABIAlign;
446478
if (Components.size() > 3)
447-
if (Error Err = parseAlignment(Components[3], PrefAlign, "preferred"))
479+
if (Error Err =
480+
parseAlignment(Components[3], PrefAlign, "preferred", ByteWidth))
448481
return Err;
449482

450483
if (PrefAlign < ABIAlign)
@@ -528,7 +561,7 @@ Error DataLayout::parseSpecification(
528561
if (Rest.empty())
529562
return createSpecFormatError("S<size>");
530563
Align Alignment;
531-
if (Error Err = parseAlignment(Rest, Alignment, "stack natural"))
564+
if (Error Err = parseAlignment(Rest, Alignment, "stack natural", ByteWidth))
532565
return Err;
533566
StackNaturalAlign = Alignment;
534567
break;
@@ -551,7 +584,7 @@ Error DataLayout::parseSpecification(
551584
Twine(Type) + "'");
552585
}
553586
Align Alignment;
554-
if (Error Err = parseAlignment(Rest, Alignment, "ABI"))
587+
if (Error Err = parseAlignment(Rest, Alignment, "ABI", ByteWidth))
555588
return Err;
556589
FunctionPtrAlign = Alignment;
557590
break;
@@ -623,10 +656,25 @@ Error DataLayout::parseLayoutString(StringRef LayoutString) {
623656

624657
// Split the data layout string into specifications separated by '-' and
625658
// parse each specification individually, updating internal data structures.
626-
SmallVector<unsigned, 8> NonIntegralAddressSpaces;
627-
for (StringRef Spec : split(LayoutString, '-')) {
659+
SmallVector<StringRef, 16> Specs;
660+
LayoutString.split(Specs, '-');
661+
662+
// On the first pass, diagnose empty specifications and parse the byte
663+
// specification if there is one. The latter is necessary because other
664+
// specifications may need the byte width for validation and to convert
665+
// bit alignments to byte alignments.
666+
for (StringRef Spec : Specs) {
628667
if (Spec.empty())
629668
return createStringError("empty specification is not allowed");
669+
if (Spec.front() == 'b')
670+
if (Error Err = parseByteSpec(Spec))
671+
return Err;
672+
}
673+
674+
SmallVector<unsigned, 8> NonIntegralAddressSpaces;
675+
for (StringRef Spec : split(LayoutString, '-')) {
676+
if (Spec.front() == 'b')
677+
continue;
630678
if (Error Err = parseSpecification(Spec, NonIntegralAddressSpaces))
631679
return Err;
632680
}
@@ -674,6 +722,7 @@ void DataLayout::setPrimitiveSpec(char Specifier, uint32_t BitWidth,
674722

675723
const DataLayout::PointerSpec &
676724
DataLayout::getPointerSpec(uint32_t AddrSpace) const {
725+
assert(!PointerSpecs.empty() && "No pointer specs are defined");
677726
if (AddrSpace != 0) {
678727
auto I = lower_bound(PointerSpecs, AddrSpace, LessPointerAddrSpace());
679728
if (I != PointerSpecs.end() && I->AddrSpace == AddrSpace)
@@ -752,7 +801,7 @@ Align DataLayout::getPointerPrefAlignment(unsigned AS) const {
752801
}
753802

754803
unsigned DataLayout::getPointerSize(unsigned AS) const {
755-
return divideCeil(getPointerSpec(AS).BitWidth, 8);
804+
return divideCeil(getPointerSpec(AS).BitWidth, ByteWidth);
756805
}
757806

758807
unsigned DataLayout::getPointerTypeSizeInBits(Type *Ty) const {
@@ -763,7 +812,7 @@ unsigned DataLayout::getPointerTypeSizeInBits(Type *Ty) const {
763812
}
764813

765814
unsigned DataLayout::getIndexSize(unsigned AS) const {
766-
return divideCeil(getPointerSpec(AS).IndexBitWidth, 8);
815+
return divideCeil(getPointerSpec(AS).IndexBitWidth, ByteWidth);
767816
}
768817

769818
unsigned DataLayout::getIndexTypeSizeInBits(Type *Ty) const {
@@ -827,7 +876,7 @@ Align DataLayout::getAlignment(Type *Ty, bool abi_or_pref) const {
827876
// approximation of reality, and if the user wanted something less
828877
// less conservative, they should have specified it explicitly in the data
829878
// layout.
830-
return Align(PowerOf2Ceil(BitWidth / 8));
879+
return Align(PowerOf2Ceil(BitWidth / ByteWidth));
831880
}
832881
case Type::FixedVectorTyID:
833882
case Type::ScalableVectorTyID: {

0 commit comments

Comments
 (0)