Skip to content

Commit 98c3676

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 b9f4afa commit 98c3676

File tree

2 files changed

+85
-26
lines changed

2 files changed

+85
-26
lines changed

llvm/include/llvm/IR/DataLayout.h

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ class DataLayout {
9191
private:
9292
bool BigEndian = false;
9393

94+
/// The size of a byte in bits.
95+
unsigned ByteWidth = 8;
96+
9497
unsigned AllocaAddrSpace = 0;
9598
unsigned ProgramAddrSpace = 0;
9699
unsigned DefaultGlobalsAddrSpace = 0;
@@ -155,6 +158,9 @@ class DataLayout {
155158
/// Internal helper method that returns requested alignment for type.
156159
Align getAlignment(Type *Ty, bool abi_or_pref) const;
157160

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

@@ -195,6 +201,9 @@ class DataLayout {
195201
bool isLittleEndian() const { return !BigEndian; }
196202
bool isBigEndian() const { return BigEndian; }
197203

204+
/// Returns the size of a byte, in bits.
205+
unsigned getByteWidth() const { return ByteWidth; }
206+
198207
/// Returns the string representation of the DataLayout.
199208
///
200209
/// This representation is in the same format accepted by the string
@@ -364,7 +373,7 @@ class DataLayout {
364373

365374
/// Returns the maximum index size over all address spaces.
366375
unsigned getMaxIndexSizeInBits() const {
367-
return getMaxIndexSize() * 8;
376+
return getMaxIndexSize() * ByteWidth;
368377
}
369378

370379
/// Size in bits of index used for address calculation in getelementptr.
@@ -384,7 +393,7 @@ class DataLayout {
384393
unsigned getIndexTypeSizeInBits(Type *Ty) const;
385394

386395
unsigned getPointerTypeSize(Type *Ty) const {
387-
return getPointerTypeSizeInBits(Ty) / 8;
396+
return getPointerTypeSizeInBits(Ty) / ByteWidth;
388397
}
389398

390399
/// Size examples:
@@ -422,7 +431,8 @@ class DataLayout {
422431
/// For example, returns 5 for i36 and 10 for x86_fp80.
423432
TypeSize getTypeStoreSize(Type *Ty) const {
424433
TypeSize BaseSize = getTypeSizeInBits(Ty);
425-
return {divideCeil(BaseSize.getKnownMinValue(), 8), BaseSize.isScalable()};
434+
return {divideCeil(BaseSize.getKnownMinValue(), ByteWidth),
435+
BaseSize.isScalable()};
426436
}
427437

428438
/// Returns the maximum number of bits that may be overwritten by
@@ -433,7 +443,7 @@ class DataLayout {
433443
///
434444
/// For example, returns 40 for i36 and 80 for x86_fp80.
435445
TypeSize getTypeStoreSizeInBits(Type *Ty) const {
436-
return 8 * getTypeStoreSize(Ty);
446+
return getTypeStoreSize(Ty) * ByteWidth;
437447
}
438448

439449
/// Returns true if no extra padding bits are needed when storing the
@@ -466,7 +476,7 @@ class DataLayout {
466476
/// This is the amount that alloca reserves for this type. For example,
467477
/// returns 96 or 128 for x86_fp80, depending on alignment.
468478
TypeSize getTypeAllocSizeInBits(Type *Ty) const {
469-
return 8 * getTypeAllocSize(Ty);
479+
return getTypeAllocSize(Ty) * ByteWidth;
470480
}
471481

472482
/// Returns the minimum ABI-required alignment for the specified type.
@@ -565,13 +575,14 @@ inline LLVMTargetDataRef wrap(const DataLayout *P) {
565575
class StructLayout final : public TrailingObjects<StructLayout, TypeSize> {
566576
TypeSize StructSize;
567577
Align StructAlignment;
578+
unsigned ByteWidth;
568579
unsigned IsPadded : 1;
569580
unsigned NumElements : 31;
570581

571582
public:
572583
TypeSize getSizeInBytes() const { return StructSize; }
573584

574-
TypeSize getSizeInBits() const { return 8 * StructSize; }
585+
TypeSize getSizeInBits() const { return StructSize * ByteWidth; }
575586

576587
Align getAlignment() const { return StructAlignment; }
577588

@@ -597,7 +608,7 @@ class StructLayout final : public TrailingObjects<StructLayout, TypeSize> {
597608
}
598609

599610
TypeSize getElementOffsetInBits(unsigned Idx) const {
600-
return getElementOffset(Idx) * 8;
611+
return getElementOffset(Idx) * ByteWidth;
601612
}
602613

603614
private:

llvm/lib/IR/DataLayout.cpp

Lines changed: 67 additions & 19 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();
@@ -225,6 +225,7 @@ DataLayout &DataLayout::operator=(const DataLayout &Other) {
225225
LayoutMap = nullptr;
226226
StringRepresentation = Other.StringRepresentation;
227227
BigEndian = Other.BigEndian;
228+
ByteWidth = Other.ByteWidth;
228229
AllocaAddrSpace = Other.AllocaAddrSpace;
229230
ProgramAddrSpace = Other.ProgramAddrSpace;
230231
DefaultGlobalsAddrSpace = Other.DefaultGlobalsAddrSpace;
@@ -246,7 +247,7 @@ DataLayout &DataLayout::operator=(const DataLayout &Other) {
246247
bool DataLayout::operator==(const DataLayout &Other) const {
247248
// NOTE: StringRepresentation might differ, it is not canonicalized.
248249
// FIXME: NonIntegralAddressSpaces isn't compared.
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)
@@ -519,7 +552,7 @@ Error DataLayout::parseSpecification(StringRef Spec) {
519552
if (Rest.empty())
520553
return createSpecFormatError("S<size>");
521554
Align Alignment;
522-
if (Error Err = parseAlignment(Rest, Alignment, "stack natural"))
555+
if (Error Err = parseAlignment(Rest, Alignment, "stack natural", ByteWidth))
523556
return Err;
524557
StackNaturalAlign = Alignment;
525558
break;
@@ -542,7 +575,7 @@ Error DataLayout::parseSpecification(StringRef Spec) {
542575
Twine(Type) + "'");
543576
}
544577
Align Alignment;
545-
if (Error Err = parseAlignment(Rest, Alignment, "ABI"))
578+
if (Error Err = parseAlignment(Rest, Alignment, "ABI", ByteWidth))
546579
return Err;
547580
FunctionPtrAlign = Alignment;
548581
break;
@@ -614,9 +647,24 @@ Error DataLayout::parseLayoutString(StringRef LayoutString) {
614647

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

655703
const DataLayout::PointerSpec &
656704
DataLayout::getPointerSpec(uint32_t AddrSpace) const {
705+
assert(!PointerSpecs.empty() && "No pointer specs are defined");
657706
if (AddrSpace != 0) {
658707
auto I = lower_bound(PointerSpecs, AddrSpace, LessPointerAddrSpace());
659708
if (I != PointerSpecs.end() && I->AddrSpace == AddrSpace)
@@ -723,14 +772,13 @@ Align DataLayout::getPointerPrefAlignment(unsigned AS) const {
723772
}
724773

725774
unsigned DataLayout::getPointerSize(unsigned AS) const {
726-
return divideCeil(getPointerSpec(AS).BitWidth, 8);
775+
return divideCeil(getPointerSpec(AS).BitWidth, ByteWidth);
727776
}
728777

729778
unsigned DataLayout::getMaxIndexSize() const {
730779
unsigned MaxIndexSize = 0;
731780
for (const PointerSpec &Spec : PointerSpecs)
732-
MaxIndexSize =
733-
std::max(MaxIndexSize, (unsigned)divideCeil(Spec.BitWidth, 8));
781+
MaxIndexSize = std::max(MaxIndexSize, divideCeil(Spec.BitWidth, ByteWidth));
734782

735783
return MaxIndexSize;
736784
}
@@ -743,7 +791,7 @@ unsigned DataLayout::getPointerTypeSizeInBits(Type *Ty) const {
743791
}
744792

745793
unsigned DataLayout::getIndexSize(unsigned AS) const {
746-
return divideCeil(getPointerSpec(AS).IndexBitWidth, 8);
794+
return divideCeil(getPointerSpec(AS).IndexBitWidth, ByteWidth);
747795
}
748796

749797
unsigned DataLayout::getIndexTypeSizeInBits(Type *Ty) const {
@@ -807,7 +855,7 @@ Align DataLayout::getAlignment(Type *Ty, bool abi_or_pref) const {
807855
// approximation of reality, and if the user wanted something less
808856
// less conservative, they should have specified it explicitly in the data
809857
// layout.
810-
return Align(PowerOf2Ceil(BitWidth / 8));
858+
return Align(PowerOf2Ceil(getTypeStoreSize(Ty).getFixedValue()));
811859
}
812860
case Type::FixedVectorTyID:
813861
case Type::ScalableVectorTyID: {

0 commit comments

Comments
 (0)