Skip to content

Commit 31ee84f

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 597ccb8 commit 31ee84f

File tree

2 files changed

+85
-27
lines changed

2 files changed

+85
-27
lines changed

llvm/include/llvm/IR/DataLayout.h

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ class DataLayout {
9595
private:
9696
bool BigEndian = false;
9797

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

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

@@ -197,6 +203,9 @@ class DataLayout {
197203
bool isLittleEndian() const { return !BigEndian; }
198204
bool isBigEndian() const { return BigEndian; }
199205

206+
/// Returns the size of a byte, in bits.
207+
unsigned getByteWidth() const { return ByteWidth; }
208+
200209
/// Returns the string representation of the DataLayout.
201210
///
202211
/// This representation is in the same format accepted by the string
@@ -370,7 +379,7 @@ class DataLayout {
370379

371380
/// Returns the maximum index size over all address spaces.
372381
unsigned getMaxIndexSizeInBits() const {
373-
return getMaxIndexSize() * 8;
382+
return getMaxIndexSize() * ByteWidth;
374383
}
375384

376385
/// Size in bits of index used for address calculation in getelementptr.
@@ -390,7 +399,7 @@ class DataLayout {
390399
unsigned getIndexTypeSizeInBits(Type *Ty) const;
391400

392401
unsigned getPointerTypeSize(Type *Ty) const {
393-
return getPointerTypeSizeInBits(Ty) / 8;
402+
return getPointerTypeSizeInBits(Ty) / ByteWidth;
394403
}
395404

396405
/// Size examples:
@@ -428,7 +437,7 @@ class DataLayout {
428437
/// For example, returns 5 for i36 and 10 for x86_fp80.
429438
TypeSize getTypeStoreSize(Type *Ty) const {
430439
TypeSize StoreSizeInBits = getTypeStoreSizeInBits(Ty);
431-
return {StoreSizeInBits.getKnownMinValue() / 8,
440+
return {StoreSizeInBits.getKnownMinValue() / ByteWidth,
432441
StoreSizeInBits.isScalable()};
433442
}
434443

@@ -442,7 +451,7 @@ class DataLayout {
442451
TypeSize getTypeStoreSizeInBits(Type *Ty) const {
443452
TypeSize BaseSize = getTypeSizeInBits(Ty);
444453
uint64_t AlignedSizeInBits =
445-
alignToPowerOf2(BaseSize.getKnownMinValue(), 8);
454+
alignToPowerOf2(BaseSize.getKnownMinValue(), ByteWidth);
446455
return {AlignedSizeInBits, BaseSize.isScalable()};
447456
}
448457

@@ -476,7 +485,7 @@ class DataLayout {
476485
/// This is the amount that alloca reserves for this type. For example,
477486
/// returns 96 or 128 for x86_fp80, depending on alignment.
478487
TypeSize getTypeAllocSizeInBits(Type *Ty) const {
479-
return 8 * getTypeAllocSize(Ty);
488+
return getTypeAllocSize(Ty) * ByteWidth;
480489
}
481490

482491
/// Returns the minimum ABI-required alignment for the specified type.
@@ -575,13 +584,14 @@ inline LLVMTargetDataRef wrap(const DataLayout *P) {
575584
class StructLayout final : public TrailingObjects<StructLayout, TypeSize> {
576585
TypeSize StructSize;
577586
Align StructAlignment;
587+
unsigned ByteWidth;
578588
unsigned IsPadded : 1;
579589
unsigned NumElements : 31;
580590

581591
public:
582592
TypeSize getSizeInBytes() const { return StructSize; }
583593

584-
TypeSize getSizeInBits() const { return 8 * StructSize; }
594+
TypeSize getSizeInBits() const { return StructSize * ByteWidth; }
585595

586596
Align getAlignment() const { return StructAlignment; }
587597

@@ -607,7 +617,7 @@ class StructLayout final : public TrailingObjects<StructLayout, TypeSize> {
607617
}
608618

609619
TypeSize getElementOffsetInBits(unsigned Idx) const {
610-
return getElementOffset(Idx) * 8;
620+
return getElementOffset(Idx) * ByteWidth;
611621
}
612622

613623
private:

llvm/lib/IR/DataLayout.cpp

Lines changed: 68 additions & 20 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();
@@ -227,6 +227,7 @@ DataLayout &DataLayout::operator=(const DataLayout &Other) {
227227
LayoutMap = nullptr;
228228
StringRepresentation = Other.StringRepresentation;
229229
BigEndian = Other.BigEndian;
230+
ByteWidth = Other.ByteWidth;
230231
AllocaAddrSpace = Other.AllocaAddrSpace;
231232
ProgramAddrSpace = Other.ProgramAddrSpace;
232233
DefaultGlobalsAddrSpace = Other.DefaultGlobalsAddrSpace;
@@ -246,7 +247,7 @@ DataLayout &DataLayout::operator=(const DataLayout &Other) {
246247

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

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

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

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

350380
// ABI alignment.
351381
Align ABIAlign;
352-
if (Error Err = parseAlignment(Components[1], ABIAlign, "ABI"))
382+
if (Error Err = parseAlignment(Components[1], ABIAlign, "ABI", ByteWidth))
353383
return Err;
354384

355385
if (Specifier == 'i' && BitWidth == 8 && ABIAlign != 1)
@@ -358,7 +388,8 @@ Error DataLayout::parsePrimitiveSpec(StringRef Spec) {
358388
// Preferred alignment. Optional, defaults to the ABI alignment.
359389
Align PrefAlign = ABIAlign;
360390
if (Components.size() > 2)
361-
if (Error Err = parseAlignment(Components[2], PrefAlign, "preferred"))
391+
if (Error Err =
392+
parseAlignment(Components[2], PrefAlign, "preferred", ByteWidth))
362393
return Err;
363394

364395
if (PrefAlign < ABIAlign)
@@ -389,14 +420,15 @@ Error DataLayout::parseAggregateSpec(StringRef Spec) {
389420

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

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

402434
if (PrefAlign < ABIAlign)
@@ -430,14 +462,15 @@ Error DataLayout::parsePointerSpec(StringRef Spec) {
430462

431463
// ABI alignment. Required, cannot be zero.
432464
Align ABIAlign;
433-
if (Error Err = parseAlignment(Components[2], ABIAlign, "ABI"))
465+
if (Error Err = parseAlignment(Components[2], ABIAlign, "ABI", ByteWidth))
434466
return Err;
435467

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

443476
if (PrefAlign < ABIAlign)
@@ -521,7 +554,7 @@ Error DataLayout::parseSpecification(
521554
if (Rest.empty())
522555
return createSpecFormatError("S<size>");
523556
Align Alignment;
524-
if (Error Err = parseAlignment(Rest, Alignment, "stack natural"))
557+
if (Error Err = parseAlignment(Rest, Alignment, "stack natural", ByteWidth))
525558
return Err;
526559
StackNaturalAlign = Alignment;
527560
break;
@@ -544,7 +577,7 @@ Error DataLayout::parseSpecification(
544577
Twine(Type) + "'");
545578
}
546579
Align Alignment;
547-
if (Error Err = parseAlignment(Rest, Alignment, "ABI"))
580+
if (Error Err = parseAlignment(Rest, Alignment, "ABI", ByteWidth))
548581
return Err;
549582
FunctionPtrAlign = Alignment;
550583
break;
@@ -616,10 +649,25 @@ Error DataLayout::parseLayoutString(StringRef LayoutString) {
616649

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

668716
const DataLayout::PointerSpec &
669717
DataLayout::getPointerSpec(uint32_t AddrSpace) const {
718+
assert(!PointerSpecs.empty() && "No pointer specs are defined");
670719
if (AddrSpace != 0) {
671720
auto I = lower_bound(PointerSpecs, AddrSpace, LessPointerAddrSpace());
672721
if (I != PointerSpecs.end() && I->AddrSpace == AddrSpace)
@@ -737,14 +786,13 @@ Align DataLayout::getPointerPrefAlignment(unsigned AS) const {
737786
}
738787

739788
unsigned DataLayout::getPointerSize(unsigned AS) const {
740-
return divideCeil(getPointerSpec(AS).BitWidth, 8);
789+
return divideCeil(getPointerSpec(AS).BitWidth, ByteWidth);
741790
}
742791

743792
unsigned DataLayout::getMaxIndexSize() const {
744793
unsigned MaxIndexSize = 0;
745794
for (const PointerSpec &Spec : PointerSpecs)
746-
MaxIndexSize =
747-
std::max(MaxIndexSize, (unsigned)divideCeil(Spec.BitWidth, 8));
795+
MaxIndexSize = std::max(MaxIndexSize, divideCeil(Spec.BitWidth, ByteWidth));
748796

749797
return MaxIndexSize;
750798
}
@@ -757,7 +805,7 @@ unsigned DataLayout::getPointerTypeSizeInBits(Type *Ty) const {
757805
}
758806

759807
unsigned DataLayout::getIndexSize(unsigned AS) const {
760-
return divideCeil(getPointerSpec(AS).IndexBitWidth, 8);
808+
return divideCeil(getPointerSpec(AS).IndexBitWidth, ByteWidth);
761809
}
762810

763811
unsigned DataLayout::getIndexTypeSizeInBits(Type *Ty) const {
@@ -821,7 +869,7 @@ Align DataLayout::getAlignment(Type *Ty, bool abi_or_pref) const {
821869
// approximation of reality, and if the user wanted something less
822870
// less conservative, they should have specified it explicitly in the data
823871
// layout.
824-
return Align(PowerOf2Ceil(BitWidth / 8));
872+
return Align(PowerOf2Ceil(BitWidth / ByteWidth));
825873
}
826874
case Type::FixedVectorTyID:
827875
case Type::ScalableVectorTyID: {

0 commit comments

Comments
 (0)