Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions llvm/docs/Extensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,21 @@ hexadecimal format instead of decimal if desired.
.section .data
.float 0x1c2.2ap3

``.prefalign`` directive
------------------------

The ``.prefalign`` directive sets the preferred alignment for a section,
and enables the section's final alignment to be set in a way that is
dependent on the section size (currently only supported with ELF).

If the section size is less than the section's minimum alignment as
determined using ``.align`` family directives, the section's alignment
will be equal to its minimum alignment. Otherwise, if the section size is
between the minimum alignment and the preferred alignment, the section's
alignment will be equal to the power of 2 greater than or equal to the
section size. Otherwise, the section's alignment will be equal to the
preferred alignment.

Machine-specific Assembly Syntax
================================

Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/MC/MCAsmInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,9 @@ class LLVM_ABI MCAsmInfo {
// most targets, so defaults to true.
bool HasFunctionAlignment = true;

// True if the target respects .prefalign directives.
bool HasPreferredAlignment = false;

/// True if the target has .type and .size directives, this is true for most
/// ELF targets. Defaults to true.
bool HasDotTypeDotSizeDirective = true;
Expand Down Expand Up @@ -603,6 +606,7 @@ class LLVM_ABI MCAsmInfo {
}

bool hasFunctionAlignment() const { return HasFunctionAlignment; }
bool hasPreferredAlignment() const { return HasPreferredAlignment; }
bool hasDotTypeDotSizeDirective() const { return HasDotTypeDotSizeDirective; }
bool hasSingleParameterDotFile() const { return HasSingleParameterDotFile; }
bool hasIdentDirective() const { return HasIdentDirective; }
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/MC/MCObjectStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ class MCObjectStreamer : public MCStreamer {
unsigned MaxBytesToEmit = 0) override;
void emitCodeAlignment(Align ByteAlignment, const MCSubtargetInfo *STI,
unsigned MaxBytesToEmit = 0) override;
void emitPrefAlign(Align Alignment) override;
void emitValueToOffset(const MCExpr *Offset, unsigned char Value,
SMLoc Loc) override;
void emitDwarfLocDirective(unsigned FileNo, unsigned Line, unsigned Column,
Expand Down
14 changes: 14 additions & 0 deletions llvm/include/llvm/MC/MCSection.h
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,7 @@ class LLVM_ABI MCSection {
MCSymbol *End = nullptr;
/// The alignment requirement of this section.
Align Alignment;
MaybeAlign PreferredAlignment;
/// The section index in the assemblers section list.
unsigned Ordinal = 0;
// If not -1u, the first linker-relaxable fragment's order within the
Expand Down Expand Up @@ -610,6 +611,19 @@ class LLVM_ABI MCSection {
Alignment = MinAlignment;
}

Align getPreferredAlignment() const {
if (!PreferredAlignment || Alignment > *PreferredAlignment)
return Alignment;
return *PreferredAlignment;
}

void ensurePreferredAlignment(Align PrefAlign) {
if (!PreferredAlignment || PrefAlign > *PreferredAlignment)
PreferredAlignment = PrefAlign;
}

Align getAlignmentForObjectFile(uint64_t Size) const;

unsigned getOrdinal() const { return Ordinal; }
void setOrdinal(unsigned Value) { Ordinal = Value; }

Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/MC/MCStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,8 @@ class LLVM_ABI MCStreamer {
virtual void emitCodeAlignment(Align Alignment, const MCSubtargetInfo *STI,
unsigned MaxBytesToEmit = 0);

virtual void emitPrefAlign(Align A);

/// Emit some number of copies of \p Value until the byte offset \p
/// Offset is reached.
///
Expand Down
8 changes: 4 additions & 4 deletions llvm/lib/MC/ELFObjectWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -912,10 +912,10 @@ void ELFWriter::writeSectionHeader(uint32_t GroupSymbolIndex, uint64_t Offset,
sh_link = Sym->getSection().getOrdinal();
}

writeSectionHeaderEntry(StrTabBuilder.getOffset(Section.getName()),
Section.getType(), Section.getFlags(), 0, Offset,
Size, sh_link, sh_info, Section.getAlign(),
Section.getEntrySize());
writeSectionHeaderEntry(
StrTabBuilder.getOffset(Section.getName()), Section.getType(),
Section.getFlags(), 0, Offset, Size, sh_link, sh_info,
Section.getAlignmentForObjectFile(Size), Section.getEntrySize());
}

void ELFWriter::writeSectionHeaders() {
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/MC/MCAsmInfoELF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ bool MCAsmInfoELF::useCodeAlign(const MCSection &Sec) const {

MCAsmInfoELF::MCAsmInfoELF() {
HasIdentDirective = true;
HasPreferredAlignment = true;
WeakRefDirective = "\t.weak\t";
PrivateGlobalPrefix = ".L";
PrivateLabelPrefix = ".L";
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/MC/MCAsmStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ class MCAsmStreamer final : public MCStreamer {

void emitCodeAlignment(Align Alignment, const MCSubtargetInfo *STI,
unsigned MaxBytesToEmit = 0) override;
void emitPrefAlign(Align Alignment) override;

void emitValueToOffset(const MCExpr *Offset,
unsigned char Value,
Expand Down Expand Up @@ -1540,6 +1541,11 @@ void MCAsmStreamer::emitCodeAlignment(Align Alignment,
emitAlignmentDirective(Alignment.value(), std::nullopt, 1, MaxBytesToEmit);
}

void MCAsmStreamer::emitPrefAlign(Align Alignment) {
OS << "\t.prefalign\t" << Alignment.value();
EmitEOL();
}

void MCAsmStreamer::emitValueToOffset(const MCExpr *Offset,
unsigned char Value,
SMLoc Loc) {
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/MC/MCObjectStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,10 @@ void MCObjectStreamer::emitCodeAlignment(Align Alignment,
F->STI = STI;
}

void MCObjectStreamer::emitPrefAlign(Align Alignment) {
getCurrentSectionOnly()->ensurePreferredAlignment(Alignment);
}

void MCObjectStreamer::emitValueToOffset(const MCExpr *Offset,
unsigned char Value,
SMLoc Loc) {
Expand Down
20 changes: 20 additions & 0 deletions llvm/lib/MC/MCParser/AsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ class AsmParser : public MCAsmParser {
DK_P2ALIGN,
DK_P2ALIGNW,
DK_P2ALIGNL,
DK_PREFALIGN,
DK_ORG,
DK_FILL,
DK_ENDR,
Expand Down Expand Up @@ -565,6 +566,7 @@ class AsmParser : public MCAsmParser {
bool parseDirectiveOrg(); // ".org"
// ".align{,32}", ".p2align{,w,l}"
bool parseDirectiveAlign(bool IsPow2, uint8_t ValueSize);
bool parseDirectivePrefAlign();

// ".file", ".line", ".loc", ".loc_label", ".stabs"
bool parseDirectiveFile(SMLoc DirectiveLoc);
Expand Down Expand Up @@ -2002,6 +2004,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info,
return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/2);
case DK_P2ALIGNL:
return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/4);
case DK_PREFALIGN:
return parseDirectivePrefAlign();
case DK_ORG:
return parseDirectiveOrg();
case DK_FILL:
Expand Down Expand Up @@ -3427,6 +3431,21 @@ bool AsmParser::parseDirectiveAlign(bool IsPow2, uint8_t ValueSize) {
return ReturnVal;
}

bool AsmParser::parseDirectivePrefAlign() {
SMLoc AlignmentLoc = getLexer().getLoc();
int64_t Alignment;
if (checkForValidSection() || parseAbsoluteExpression(Alignment))
return true;
if (parseEOL())
return true;

if (!isPowerOf2_64(Alignment))
return Error(AlignmentLoc, "alignment must be a power of 2");
getStreamer().emitPrefAlign(Align(Alignment));

return false;
}

/// parseDirectiveFile
/// ::= .file filename
/// ::= .file number [directory] filename [md5 checksum] [source source-text]
Expand Down Expand Up @@ -5365,6 +5384,7 @@ void AsmParser::initializeDirectiveKindMap() {
DirectiveKindMap[".p2align"] = DK_P2ALIGN;
DirectiveKindMap[".p2alignw"] = DK_P2ALIGNW;
DirectiveKindMap[".p2alignl"] = DK_P2ALIGNL;
DirectiveKindMap[".prefalign"] = DK_PREFALIGN;
DirectiveKindMap[".org"] = DK_ORG;
DirectiveKindMap[".fill"] = DK_FILL;
DirectiveKindMap[".zero"] = DK_ZERO;
Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/MC/MCSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ MCSymbol *MCSection::getEndSymbol(MCContext &Ctx) {
return End;
}

Align MCSection::getAlignmentForObjectFile(uint64_t Size) const {
if (Size < getAlign().value())
return getAlign();

if (Size < getPreferredAlignment().value())
return Align(NextPowerOf2(Size - 1));

return getPreferredAlignment();
}

bool MCSection::hasEnded() const { return End && End->isInSection(); }

#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/MC/MCStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1339,6 +1339,7 @@ void MCStreamer::emitFill(const MCExpr &NumBytes, uint64_t Value, SMLoc Loc) {}
void MCStreamer::emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr,
SMLoc Loc) {}
void MCStreamer::emitValueToAlignment(Align, int64_t, uint8_t, unsigned) {}
void MCStreamer::emitPrefAlign(Align A) {}
void MCStreamer::emitCodeAlignment(Align Alignment, const MCSubtargetInfo *STI,
unsigned MaxBytesToEmit) {}
void MCStreamer::emitValueToOffset(const MCExpr *Offset, unsigned char Value,
Expand Down
5 changes: 5 additions & 0 deletions llvm/test/MC/ELF/prefalign-errors.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// RUN: not llvm-mc -filetype=asm -triple x86_64-pc-linux-gnu %s -o - 2>&1 | FileCheck %s

.section .text.f1,"ax",@progbits
// CHECK: error: alignment must be a power of 2
.prefalign 3
104 changes: 104 additions & 0 deletions llvm/test/MC/ELF/prefalign.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// RUN: llvm-mc -filetype=asm -triple x86_64-pc-linux-gnu %s -o - | FileCheck --check-prefix=ASM %s
// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readelf -SW - | FileCheck --check-prefix=OBJ %s

// Minimum alignment >= preferred alignment, no effect on sh_addralign.
// ASM: .section .text.f1lt
// ASM: .p2align 2
// ASM: .prefalign 2
// OBJ: .text.f1lt PROGBITS 0000000000000000 000040 000003 00 AX 0 0 4
.section .text.f1lt,"ax",@progbits
.p2align 2
.prefalign 2
.rept 3
nop
.endr

// ASM: .section .text.f1eq
// ASM: .p2align 2
// ASM: .prefalign 2
// OBJ: .text.f1eq PROGBITS 0000000000000000 000044 000004 00 AX 0 0 4
.section .text.f1eq,"ax",@progbits
.p2align 2
.prefalign 2
.rept 4
nop
.endr

// ASM: .section .text.f1gt
// ASM: .p2align 2
// ASM: .prefalign 2
// OBJ: .text.f1gt PROGBITS 0000000000000000 000048 000005 00 AX 0 0 4
.section .text.f1gt,"ax",@progbits
.p2align 2
.prefalign 2
.rept 5
nop
.endr

// Minimum alignment < preferred alignment, sh_addralign influenced by section size.
// Use maximum of all .prefalign directives.
// ASM: .section .text.f2lt
// ASM: .p2align 2
// ASM: .prefalign 8
// ASM: .prefalign 16
// ASM: .prefalign 8
// OBJ: .text.f2lt PROGBITS 0000000000000000 000050 000003 00 AX 0 0 4
.section .text.f2lt,"ax",@progbits
.p2align 2
.prefalign 8
.prefalign 16
.prefalign 8
.rept 3
nop
.endr

// ASM: .section .text.f2between1
// OBJ: .text.f2between1 PROGBITS 0000000000000000 000054 000008 00 AX 0 0 8
.section .text.f2between1,"ax",@progbits
.p2align 2
.prefalign 8
.prefalign 16
.prefalign 8
.rept 8
nop
.endr

// OBJ: .text.f2between2 PROGBITS 0000000000000000 00005c 000009 00 AX 0 0 16
.section .text.f2between2,"ax",@progbits
.p2align 2
.prefalign 8
.prefalign 16
.prefalign 8
.rept 9
nop
.endr

// OBJ: .text.f2between3 PROGBITS 0000000000000000 000068 000010 00 AX 0 0 16
.section .text.f2between3,"ax",@progbits
.p2align 2
.prefalign 8
.prefalign 16
.prefalign 8
.rept 16
nop
.endr

// OBJ: .text.f2gt1 PROGBITS 0000000000000000 000078 000011 00 AX 0 0 16
.section .text.f2gt1,"ax",@progbits
.p2align 2
.prefalign 8
.prefalign 16
.prefalign 8
.rept 17
nop
.endr

// OBJ: .text.f2gt2 PROGBITS 0000000000000000 00008c 000021 00 AX 0 0 16
.section .text.f2gt2,"ax",@progbits
.p2align 2
.prefalign 8
.prefalign 16
.prefalign 8
.rept 33
nop
.endr
Loading