Skip to content

Commit 4048990

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 eb70253 commit 4048990

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
@@ -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
@@ -382,7 +391,7 @@ class DataLayout {
382391
unsigned getIndexTypeSizeInBits(Type *Ty) const;
383392

384393
unsigned getPointerTypeSize(Type *Ty) const {
385-
return getPointerTypeSizeInBits(Ty) / 8;
394+
return getPointerTypeSizeInBits(Ty) / ByteWidth;
386395
}
387396

388397
/// Size examples:
@@ -420,7 +429,7 @@ class DataLayout {
420429
/// For example, returns 5 for i36 and 10 for x86_fp80.
421430
TypeSize getTypeStoreSize(Type *Ty) const {
422431
TypeSize StoreSizeInBits = getTypeStoreSizeInBits(Ty);
423-
return {StoreSizeInBits.getKnownMinValue() / 8,
432+
return {StoreSizeInBits.getKnownMinValue() / ByteWidth,
424433
StoreSizeInBits.isScalable()};
425434
}
426435

@@ -434,7 +443,7 @@ class DataLayout {
434443
TypeSize getTypeStoreSizeInBits(Type *Ty) const {
435444
TypeSize BaseSize = getTypeSizeInBits(Ty);
436445
uint64_t AlignedSizeInBits =
437-
alignToPowerOf2(BaseSize.getKnownMinValue(), 8);
446+
alignToPowerOf2(BaseSize.getKnownMinValue(), ByteWidth);
438447
return {AlignedSizeInBits, BaseSize.isScalable()};
439448
}
440449

@@ -468,7 +477,7 @@ class DataLayout {
468477
/// This is the amount that alloca reserves for this type. For example,
469478
/// returns 96 or 128 for x86_fp80, depending on alignment.
470479
TypeSize getTypeAllocSizeInBits(Type *Ty) const {
471-
return 8 * getTypeAllocSize(Ty);
480+
return getTypeAllocSize(Ty) * ByteWidth;
472481
}
473482

474483
/// Returns the minimum ABI-required alignment for the specified type.
@@ -567,13 +576,14 @@ inline LLVMTargetDataRef wrap(const DataLayout *P) {
567576
class StructLayout final : public TrailingObjects<StructLayout, TypeSize> {
568577
TypeSize StructSize;
569578
Align StructAlignment;
579+
unsigned ByteWidth;
570580
unsigned IsPadded : 1;
571581
unsigned NumElements : 31;
572582

573583
public:
574584
TypeSize getSizeInBytes() const { return StructSize; }
575585

576-
TypeSize getSizeInBits() const { return 8 * StructSize; }
586+
TypeSize getSizeInBits() const { return StructSize * ByteWidth; }
577587

578588
Align getAlignment() const { return StructAlignment; }
579589

@@ -599,7 +609,7 @@ class StructLayout final : public TrailingObjects<StructLayout, TypeSize> {
599609
}
600610

601611
TypeSize getElementOffsetInBits(unsigned Idx) const {
602-
return getElementOffset(Idx) * 8;
612+
return getElementOffset(Idx) * ByteWidth;
603613
}
604614

605615
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();
@@ -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,7 +786,7 @@ 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::getPointerTypeSizeInBits(Type *Ty) const {
@@ -748,7 +797,7 @@ unsigned DataLayout::getPointerTypeSizeInBits(Type *Ty) const {
748797
}
749798

750799
unsigned DataLayout::getIndexSize(unsigned AS) const {
751-
return divideCeil(getPointerSpec(AS).IndexBitWidth, 8);
800+
return divideCeil(getPointerSpec(AS).IndexBitWidth, ByteWidth);
752801
}
753802

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

0 commit comments

Comments
 (0)