Skip to content

Commit 3539d10

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 13bb328 commit 3539d10

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
@@ -96,6 +96,9 @@ class DataLayout {
9696
private:
9797
bool BigEndian = false;
9898

99+
/// The size of a byte in bits.
100+
unsigned ByteWidth = 8;
101+
99102
unsigned AllocaAddrSpace = 0;
100103
unsigned ProgramAddrSpace = 0;
101104
unsigned DefaultGlobalsAddrSpace = 0;
@@ -157,6 +160,9 @@ class DataLayout {
157160
/// Internal helper method that returns requested alignment for type.
158161
Align getAlignment(Type *Ty, bool abi_or_pref) const;
159162

163+
/// Attempts to parse a byte specification ('b').
164+
Error parseByteSpec(StringRef Spec);
165+
160166
/// Attempts to parse primitive specification ('i', 'f', or 'v').
161167
Error parsePrimitiveSpec(StringRef Spec);
162168

@@ -198,6 +204,9 @@ class DataLayout {
198204
bool isLittleEndian() const { return !BigEndian; }
199205
bool isBigEndian() const { return BigEndian; }
200206

207+
/// Returns the size of a byte, in bits.
208+
unsigned getByteWidth() const { return ByteWidth; }
209+
201210
/// Returns the string representation of the DataLayout.
202211
///
203212
/// This representation is in the same format accepted by the string
@@ -429,7 +438,7 @@ class DataLayout {
429438
}
430439

431440
unsigned getPointerTypeSize(Type *Ty) const {
432-
return getPointerTypeSizeInBits(Ty) / 8;
441+
return getPointerTypeSizeInBits(Ty) / ByteWidth;
433442
}
434443

435444
/// Size examples:
@@ -467,7 +476,7 @@ class DataLayout {
467476
/// For example, returns 5 for i36 and 10 for x86_fp80.
468477
TypeSize getTypeStoreSize(Type *Ty) const {
469478
TypeSize StoreSizeInBits = getTypeStoreSizeInBits(Ty);
470-
return {StoreSizeInBits.getKnownMinValue() / 8,
479+
return {StoreSizeInBits.getKnownMinValue() / ByteWidth,
471480
StoreSizeInBits.isScalable()};
472481
}
473482

@@ -481,7 +490,7 @@ class DataLayout {
481490
TypeSize getTypeStoreSizeInBits(Type *Ty) const {
482491
TypeSize BaseSize = getTypeSizeInBits(Ty);
483492
uint64_t AlignedSizeInBits =
484-
alignToPowerOf2(BaseSize.getKnownMinValue(), 8);
493+
alignToPowerOf2(BaseSize.getKnownMinValue(), ByteWidth);
485494
return {AlignedSizeInBits, BaseSize.isScalable()};
486495
}
487496

@@ -515,7 +524,7 @@ class DataLayout {
515524
/// This is the amount that alloca reserves for this type. For example,
516525
/// returns 96 or 128 for x86_fp80, depending on alignment.
517526
TypeSize getTypeAllocSizeInBits(Type *Ty) const {
518-
return 8 * getTypeAllocSize(Ty);
527+
return getTypeAllocSize(Ty) * ByteWidth;
519528
}
520529

521530
/// Returns the minimum ABI-required alignment for the specified type.
@@ -628,13 +637,14 @@ class StructLayout final : private TrailingObjects<StructLayout, TypeSize> {
628637

629638
TypeSize StructSize;
630639
Align StructAlignment;
640+
unsigned ByteWidth;
631641
unsigned IsPadded : 1;
632642
unsigned NumElements : 31;
633643

634644
public:
635645
TypeSize getSizeInBytes() const { return StructSize; }
636646

637-
TypeSize getSizeInBits() const { return 8 * StructSize; }
647+
TypeSize getSizeInBits() const { return StructSize * ByteWidth; }
638648

639649
Align getAlignment() const { return StructAlignment; }
640650

@@ -660,7 +670,7 @@ class StructLayout final : private TrailingObjects<StructLayout, TypeSize> {
660670
}
661671

662672
TypeSize getElementOffsetInBits(unsigned Idx) const {
663-
return getElementOffset(Idx) * 8;
673+
return getElementOffset(Idx) * ByteWidth;
664674
}
665675

666676
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();
@@ -226,6 +226,7 @@ DataLayout &DataLayout::operator=(const DataLayout &Other) {
226226
LayoutMap = nullptr;
227227
StringRepresentation = Other.StringRepresentation;
228228
BigEndian = Other.BigEndian;
229+
ByteWidth = Other.ByteWidth;
229230
AllocaAddrSpace = Other.AllocaAddrSpace;
230231
ProgramAddrSpace = Other.ProgramAddrSpace;
231232
DefaultGlobalsAddrSpace = Other.DefaultGlobalsAddrSpace;
@@ -245,7 +246,7 @@ DataLayout &DataLayout::operator=(const DataLayout &Other) {
245246

246247
bool DataLayout::operator==(const DataLayout &Other) const {
247248
// NOTE: StringRepresentation might differ, it is not canonicalized.
248-
return BigEndian == Other.BigEndian &&
249+
return BigEndian == Other.BigEndian && ByteWidth == Other.ByteWidth &&
249250
AllocaAddrSpace == Other.AllocaAddrSpace &&
250251
ProgramAddrSpace == Other.ProgramAddrSpace &&
251252
DefaultGlobalsAddrSpace == Other.DefaultGlobalsAddrSpace &&
@@ -307,7 +308,7 @@ static Error parseSize(StringRef Str, unsigned &BitWidth,
307308
/// - the value is not a multiple of the byte width;
308309
/// - the value converted to byte amount is not not a power of two.
309310
static Error parseAlignment(StringRef Str, Align &Alignment, StringRef Name,
310-
bool AllowZero = false) {
311+
unsigned ByteWidth, bool AllowZero = false) {
311312
if (Str.empty())
312313
return createStringError(Name + " alignment component cannot be empty");
313314

@@ -322,7 +323,6 @@ static Error parseAlignment(StringRef Str, Align &Alignment, StringRef Name,
322323
return Error::success();
323324
}
324325

325-
constexpr unsigned ByteWidth = 8;
326326
if (Value % ByteWidth || !isPowerOf2_32(Value / ByteWidth))
327327
return createStringError(
328328
Name + " alignment must be a power of two times the byte width");
@@ -331,6 +331,36 @@ static Error parseAlignment(StringRef Str, Align &Alignment, StringRef Name,
331331
return Error::success();
332332
}
333333

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

349379
// ABI alignment.
350380
Align ABIAlign;
351-
if (Error Err = parseAlignment(Components[1], ABIAlign, "ABI"))
381+
if (Error Err = parseAlignment(Components[1], ABIAlign, "ABI", ByteWidth))
352382
return Err;
353383

354384
if (Specifier == 'i' && BitWidth == 8 && ABIAlign != 1)
@@ -357,7 +387,8 @@ Error DataLayout::parsePrimitiveSpec(StringRef Spec) {
357387
// Preferred alignment. Optional, defaults to the ABI alignment.
358388
Align PrefAlign = ABIAlign;
359389
if (Components.size() > 2)
360-
if (Error Err = parseAlignment(Components[2], PrefAlign, "preferred"))
390+
if (Error Err =
391+
parseAlignment(Components[2], PrefAlign, "preferred", ByteWidth))
361392
return Err;
362393

363394
if (PrefAlign < ABIAlign)
@@ -388,14 +419,15 @@ Error DataLayout::parseAggregateSpec(StringRef Spec) {
388419

389420
// ABI alignment. Required. Can be zero, meaning use one byte alignment.
390421
Align ABIAlign;
391-
if (Error Err =
392-
parseAlignment(Components[1], ABIAlign, "ABI", /*AllowZero=*/true))
422+
if (Error Err = parseAlignment(Components[1], ABIAlign, "ABI", ByteWidth,
423+
/*AllowZero=*/true))
393424
return Err;
394425

395426
// Preferred alignment. Optional, defaults to the ABI alignment.
396427
Align PrefAlign = ABIAlign;
397428
if (Components.size() > 2)
398-
if (Error Err = parseAlignment(Components[2], PrefAlign, "preferred"))
429+
if (Error Err =
430+
parseAlignment(Components[2], PrefAlign, "preferred", ByteWidth))
399431
return Err;
400432

401433
if (PrefAlign < ABIAlign)
@@ -429,14 +461,15 @@ Error DataLayout::parsePointerSpec(StringRef Spec) {
429461

430462
// ABI alignment. Required, cannot be zero.
431463
Align ABIAlign;
432-
if (Error Err = parseAlignment(Components[2], ABIAlign, "ABI"))
464+
if (Error Err = parseAlignment(Components[2], ABIAlign, "ABI", ByteWidth))
433465
return Err;
434466

435467
// Preferred alignment. Optional, defaults to the ABI alignment.
436468
// Cannot be zero.
437469
Align PrefAlign = ABIAlign;
438470
if (Components.size() > 3)
439-
if (Error Err = parseAlignment(Components[3], PrefAlign, "preferred"))
471+
if (Error Err =
472+
parseAlignment(Components[3], PrefAlign, "preferred", ByteWidth))
440473
return Err;
441474

442475
if (PrefAlign < ABIAlign)
@@ -520,7 +553,7 @@ Error DataLayout::parseSpecification(
520553
if (Rest.empty())
521554
return createSpecFormatError("S<size>");
522555
Align Alignment;
523-
if (Error Err = parseAlignment(Rest, Alignment, "stack natural"))
556+
if (Error Err = parseAlignment(Rest, Alignment, "stack natural", ByteWidth))
524557
return Err;
525558
StackNaturalAlign = Alignment;
526559
break;
@@ -543,7 +576,7 @@ Error DataLayout::parseSpecification(
543576
Twine(Type) + "'");
544577
}
545578
Align Alignment;
546-
if (Error Err = parseAlignment(Rest, Alignment, "ABI"))
579+
if (Error Err = parseAlignment(Rest, Alignment, "ABI", ByteWidth))
547580
return Err;
548581
FunctionPtrAlign = Alignment;
549582
break;
@@ -615,10 +648,25 @@ Error DataLayout::parseLayoutString(StringRef LayoutString) {
615648

616649
// Split the data layout string into specifications separated by '-' and
617650
// parse each specification individually, updating internal data structures.
618-
SmallVector<unsigned, 8> NonIntegralAddressSpaces;
619-
for (StringRef Spec : split(LayoutString, '-')) {
651+
SmallVector<StringRef, 16> Specs;
652+
LayoutString.split(Specs, '-');
653+
654+
// On the first pass, diagnose empty specifications and parse the byte
655+
// specification if there is one. The latter is necessary because other
656+
// specifications may need the byte width for validation and to convert
657+
// bit alignments to byte alignments.
658+
for (StringRef Spec : Specs) {
620659
if (Spec.empty())
621660
return createStringError("empty specification is not allowed");
661+
if (Spec.front() == 'b')
662+
if (Error Err = parseByteSpec(Spec))
663+
return Err;
664+
}
665+
666+
SmallVector<unsigned, 8> NonIntegralAddressSpaces;
667+
for (StringRef Spec : split(LayoutString, '-')) {
668+
if (Spec.front() == 'b')
669+
continue;
622670
if (Error Err = parseSpecification(Spec, NonIntegralAddressSpaces))
623671
return Err;
624672
}
@@ -666,6 +714,7 @@ void DataLayout::setPrimitiveSpec(char Specifier, uint32_t BitWidth,
666714

667715
const DataLayout::PointerSpec &
668716
DataLayout::getPointerSpec(uint32_t AddrSpace) const {
717+
assert(!PointerSpecs.empty() && "No pointer specs are defined");
669718
if (AddrSpace != 0) {
670719
auto I = lower_bound(PointerSpecs, AddrSpace, LessPointerAddrSpace());
671720
if (I != PointerSpecs.end() && I->AddrSpace == AddrSpace)
@@ -736,7 +785,7 @@ Align DataLayout::getPointerPrefAlignment(unsigned AS) const {
736785
}
737786

738787
unsigned DataLayout::getPointerSize(unsigned AS) const {
739-
return divideCeil(getPointerSpec(AS).BitWidth, 8);
788+
return divideCeil(getPointerSpec(AS).BitWidth, ByteWidth);
740789
}
741790

742791
unsigned DataLayout::getPointerTypeSizeInBits(Type *Ty) const {
@@ -747,7 +796,7 @@ unsigned DataLayout::getPointerTypeSizeInBits(Type *Ty) const {
747796
}
748797

749798
unsigned DataLayout::getIndexSize(unsigned AS) const {
750-
return divideCeil(getPointerSpec(AS).IndexBitWidth, 8);
799+
return divideCeil(getPointerSpec(AS).IndexBitWidth, ByteWidth);
751800
}
752801

753802
unsigned DataLayout::getIndexTypeSizeInBits(Type *Ty) const {
@@ -811,7 +860,7 @@ Align DataLayout::getAlignment(Type *Ty, bool abi_or_pref) const {
811860
// approximation of reality, and if the user wanted something less
812861
// less conservative, they should have specified it explicitly in the data
813862
// layout.
814-
return Align(PowerOf2Ceil(BitWidth / 8));
863+
return Align(PowerOf2Ceil(BitWidth / ByteWidth));
815864
}
816865
case Type::FixedVectorTyID:
817866
case Type::ScalableVectorTyID: {

0 commit comments

Comments
 (0)