Skip to content

MC: Refine ALIGN relocation conditions #150816

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 3 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
13 changes: 7 additions & 6 deletions llvm/include/llvm/MC/MCSection.h
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,10 @@ class LLVM_ABI MCSection {
Align Alignment;
/// The section index in the assemblers section list.
unsigned Ordinal = 0;
// If not -1u, the first linker-relaxable fragment's order within the
// subsection. When present, the offset between two locations crossing this
// fragment may not be fully resolved.
unsigned FirstLinkerRelaxable = -1u;

/// Whether this section has had instructions emitted into it.
bool HasInstructions : 1;
Expand All @@ -576,10 +580,6 @@ class LLVM_ABI MCSection {
bool IsText : 1;
bool IsBss : 1;

/// Whether the section contains linker-relaxable fragments. If true, the
/// offset between two locations may not be fully resolved.
bool LinkerRelaxable : 1;

MCFragment DummyFragment;

// Mapping from subsection number to fragment list. At layout time, the
Expand Down Expand Up @@ -634,8 +634,9 @@ class LLVM_ABI MCSection {
bool isRegistered() const { return IsRegistered; }
void setIsRegistered(bool Value) { IsRegistered = Value; }

bool isLinkerRelaxable() const { return LinkerRelaxable; }
void setLinkerRelaxable() { LinkerRelaxable = true; }
unsigned firstLinkerRelaxable() const { return FirstLinkerRelaxable; }
bool isLinkerRelaxable() const { return FirstLinkerRelaxable != -1u; }
void setFirstLinkerRelaxable(unsigned Order) { FirstLinkerRelaxable = Order; }

MCFragment &getDummyFragment() { return DummyFragment; }

Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/MC/MCObjectStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ void MCObjectStreamer::emitInstToData(const MCInst &Inst,
// MCAssembler::relaxAlign.
auto *Sec = F->getParent();
if (!Sec->isLinkerRelaxable())
Sec->setLinkerRelaxable();
Sec->setFirstLinkerRelaxable(F->getLayoutOrder());
// Do not add data after a linker-relaxable instruction. The difference
// between a new label and a label at or before the linker-relaxable
// instruction cannot be resolved at assemble-time.
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/MC/MCSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ using namespace llvm;

MCSection::MCSection(StringRef Name, bool IsText, bool IsBss, MCSymbol *Begin)
: Begin(Begin), HasInstructions(false), IsRegistered(false), IsText(IsText),
IsBss(IsBss), LinkerRelaxable(false), Name(Name) {
IsBss(IsBss), Name(Name) {
DummyFragment.setParent(this);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,8 @@ bool LoongArchAsmBackend::relaxAlign(MCFragment &F, unsigned &Size) {
MCFixup::create(0, Expr, FirstLiteralRelocationKind + ELF::R_LARCH_ALIGN);
F.setVarFixups({Fixup});
F.setLinkerRelaxable();
F.getParent()->setLinkerRelaxable();
if (!F.getParent()->isLinkerRelaxable())
Copy link
Member Author

@MaskRay MaskRay Jul 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I made minimum changes to keep LoongArch tests passing but I do not intend to apply the ALIGN optimization (first behavior in the description).

Up to a LoongArch contributor to replace if (!F.getSubtargetInfo()->hasFeature(LoongArch::FeatureRelax)) with
if (F.getLayoutOrder() <= Sec->firstLinkerRelaxable()) and a few tests @SixWeining @MQ-mengqing

Note: The RISC-V alignment tests are poorly organized, so please avoid following their example. You can create a more effective structure within the LoongArch/Relocations directory.

F.getParent()->setFirstLinkerRelaxable(F.getLayoutOrder());
return true;
}

Expand Down
17 changes: 12 additions & 5 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,11 +306,19 @@ void RISCVAsmBackend::relaxInstruction(MCInst &Inst,
// If conditions are met, compute the padding size and create a fixup encoding
// the padding size in the addend.
bool RISCVAsmBackend::relaxAlign(MCFragment &F, unsigned &Size) {
// Use default handling unless linker relaxation is enabled and the alignment
// is larger than the nop size.
const MCSubtargetInfo *STI = F.getSubtargetInfo();
if (!STI->hasFeature(RISCV::FeatureRelax))
// Alignments before the first linker-relaxable instruction have fixed sizes
// and do not require relocations. Alignments after a linker-relaxable
// instruction require a relocation, even if the STI specifies norelax.
//
// firstLinkerRelaxable is the layout order within the subsection, which may
// be smaller than the section's order. Therefore, alignments in a
// lower-numbered subsection may be unnecessarily treated as linker-relaxable.
auto *Sec = F.getParent();
if (F.getLayoutOrder() <= Sec->firstLinkerRelaxable())
return false;

// Use default handling unless the alignment is larger than the nop size.
const MCSubtargetInfo *STI = F.getSubtargetInfo();
unsigned MinNopLen = STI->hasFeature(RISCV::FeatureStdExtZca) ? 2 : 4;
if (F.getAlignment() <= MinNopLen)
return false;
Expand All @@ -321,7 +329,6 @@ bool RISCVAsmBackend::relaxAlign(MCFragment &F, unsigned &Size) {
MCFixup::create(0, Expr, FirstLiteralRelocationKind + ELF::R_RISCV_ALIGN);
F.setVarFixups({Fixup});
F.setLinkerRelaxable();
F.getParent()->setLinkerRelaxable();
return true;
}

Expand Down
50 changes: 50 additions & 0 deletions llvm/test/MC/RISCV/Relocations/align-after-relax.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax %s --defsym LATE=1 -o %t1
# RUN: llvm-objdump -dr --no-show-raw-insn -M no-aliases %t1 | FileCheck %s

# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax %s -o %t0
# RUN: llvm-objdump -dr --no-show-raw-insn -M no-aliases %t0 | FileCheck %s --check-prefix=CHECK0

# CHECK: 6: c.nop
# CHECK-EMPTY:
# CHECK: 10: auipc ra, 0x0
# CHECK-NEXT: R_RISCV_CALL_PLT foo
# CHECK-NEXT: R_RISCV_RELAX *ABS*
# CHECK: 20: c.nop
# CHECK-NEXT: R_RISCV_ALIGN *ABS*+0x6

## Alignment directives in a lower-numbered subsection may be conservatively treated as linker-relaxable.
# CHECK0: 6: c.nop
# CHECK0-NEXT: R_RISCV_ALIGN *ABS*+0x6
# CHECK0: 20: c.nop
# CHECK0-NEXT: R_RISCV_ALIGN *ABS*+0x6

.text 2
.option push
.option norelax
## R_RISCV_ALIGN is required even if norelax, because it is after a linker-relaxable instruction.
.balign 8
l2:
.word 0x12345678
.option pop

.text 1
.space 4
.ifdef LATE
.space 0
.endif
call foo
.ifdef LATE
.space 8
.else
.space 4
.endif

.text 0
_start:
.space 6
.option push
.option norelax
.balign 8
l0:
.word 0x12345678
.option pop
23 changes: 18 additions & 5 deletions llvm/test/MC/RISCV/align-option-relax.s
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=-relax < %s \
# RUN: | llvm-readobj -r - | FileCheck %s

# Check that .option relax overrides -mno-relax and enables R_RISCV_ALIGN
# relocations.
# CHECK: R_RISCV_ALIGN
.option relax
.align 4
## .option relax overrides -mno-relax and enables R_RISCV_ALIGN/R_RISCV_RELAX relocations.
# CHECK: .rela.text
# CHECK: R_RISCV_CALL_PLT
# CHECK-NEXT: R_RISCV_RELAX
# CHECK-NEXT: R_RISCV_ALIGN
.option relax
call foo
.align 4

## Alignments before the first linker-relaxable instruction do not need relocations.
# CHECK-NOT: .rela.text1
.section .text1,"ax"
.align 4
nop

# CHECK: .rela.text2
.section .text2,"ax"
call foo
35 changes: 13 additions & 22 deletions llvm/test/MC/RISCV/align.s
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,17 @@
# type for .align N directive when linker relaxation enabled.
# Linker could satisfy alignment by removing NOPs after linker relaxation.

# The first R_RISCV_ALIGN come from
# MCELFStreamer::InitSections() emitCodeAlignment(getTextSectionAligntment()).
# C-OR-ZCA-EXT-RELAX-RELOC: R_RISCV_ALIGN - 0x2
# C-OR-ZCA-EXT-RELAX-INST: c.nop
test:
## Start with a linker-relaxable instruction so that the following alignment can be relaxable.
call foo
# NORELAX-RELOC: R_RISCV_CALL_PLT
# C-OR-ZCA-EXT-NORELAX-RELOC: R_RISCV_CALL_PLT

.p2align 2
# If the +c extension is enabled, the text section will be 2-byte aligned, so
# one c.nop instruction is sufficient.
# C-OR-ZCA-EXT-RELAX-RELOC-NOT: R_RISCV_ALIGN - 0x2
# C-OR-ZCA-EXT-RELAX-INST-NOT: c.nop
# C-OR-ZCA-EXT-RELAX-RELOC: R_RISCV_ALIGN - 0x2
# C-OR-ZCA-EXT-RELAX-INST: c.nop
bne zero, a0, .LBB0_2
mv a0, zero
.p2align 3
Expand Down Expand Up @@ -136,16 +137,8 @@ data2:
add a0, a0, a1

## Branches crossing the linker-relaxable R_RISCV_ALIGN need relocations.
# RELAX-RELOC: .rela.text3 {
# RELAX-RELOC-NEXT: 0x4 R_RISCV_BRANCH .Ltmp[[#]] 0x0
# RELAX-RELOC-NEXT: 0x8 R_RISCV_ALIGN - 0x4
# RELAX-RELOC-NEXT: 0xC R_RISCV_BRANCH .Ltmp[[#]] 0x0
# RELAX-RELOC-NEXT: }
# C-OR-ZCA-EXT-RELAX-RELOC: .rela.text3 {
# C-OR-ZCA-EXT-RELAX-RELOC-NEXT: 0x4 R_RISCV_BRANCH .Ltmp[[#]] 0x0
# C-OR-ZCA-EXT-RELAX-RELOC-NEXT: 0x8 R_RISCV_ALIGN - 0x4
# C-OR-ZCA-EXT-RELAX-RELOC-NEXT: 0xC R_RISCV_BRANCH .Ltmp[[#]] 0x0
# C-OR-ZCA-EXT-RELAX-RELOC-NEXT: }
# RELAX-RELOC-NOT: .rela.text3 {
# C-OR-ZCA-EXT-RELAX-RELOC-NOT: .rela.text3 {
.section .text3, "ax"
bnez t1, 1f
bnez t2, 2f
Expand All @@ -157,14 +150,15 @@ data2:

## .text3 with a call at the start
# NORELAX-RELOC: .rela.text3a
# C-OR-ZCA-EXT-NORELAX-RELOC: .rela.text3a
# RELAX-RELOC: .rela.text3a {
# RELAX-RELOC-NEXT: 0x0 R_RISCV_CALL_PLT foo 0x0
# RELAX-RELOC-NEXT: 0x0 R_RISCV_RELAX - 0x0
# RELAX-RELOC-NEXT: 0xC R_RISCV_BRANCH .Ltmp[[#]] 0x0
# RELAX-RELOC-NEXT: 0x10 R_RISCV_ALIGN - 0x4
# RELAX-RELOC-NEXT: 0x14 R_RISCV_BRANCH .Ltmp[[#]] 0x0
# RELAX-RELOC-NEXT: }
# C-OR-ZCA-EXT-NORELAX-RELOC: .rela.text3a
# C-OR-ZCA-EXT-RELAX-RELOC: .rela.text3a
.section .text3a, "ax"
call foo
bnez t1, 1f
Expand All @@ -177,11 +171,8 @@ bnez t1, 2b

## .text3 with a call at the end
# RELAX-RELOC: .rela.text3b {
# RELAX-RELOC-NEXT: 0x4 R_RISCV_BRANCH .Ltmp[[#]] 0x0
# RELAX-RELOC-NEXT: 0x8 R_RISCV_ALIGN - 0x4
# RELAX-RELOC-NEXT: 0xC R_RISCV_BRANCH .Ltmp[[#]] 0x0
# RELAX-RELOC-NEXT: 0x14 R_RISCV_CALL_PLT foo 0x0
# RELAX-RELOC-NEXT: 0x14 R_RISCV_RELAX - 0x0
# RELAX-RELOC-NEXT: 0x10 R_RISCV_CALL_PLT foo 0x0
# RELAX-RELOC-NEXT: 0x10 R_RISCV_RELAX - 0x0
# RELAX-RELOC-NEXT: }
.section .text3b, "ax"
bnez t1, 1f
Expand Down
28 changes: 15 additions & 13 deletions llvm/test/MC/RISCV/cfi-advance.s
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

# NORELAX: Relocation section '.rela.text1' at offset {{.*}} contains 1 entries:
# NORELAX-NEXT: Offset Info Type Sym. Value Symbol's Name + Addend
# NORELAX-NEXT: 00000000 00000313 R_RISCV_CALL_PLT 00000004 .L0 + 0
# NORELAX-NEXT: 00000000 00000313 R_RISCV_CALL_PLT 00000008 .L0 + 0
# NORELAX-EMPTY:
# RELAX: Relocation section '.rela.text1' at offset {{.*}} contains 2 entries:
# RELAX: R_RISCV_CALL_PLT
Expand All @@ -16,23 +16,25 @@
# NORELAX-NEXT: Relocation section '.rela.eh_frame' at offset {{.*}} contains 1 entries:
# NORELAX: Offset Info Type Sym. Value Symbol's Name + Addend
# NORELAX-NEXT: 0000001c 00000139 R_RISCV_32_PCREL 00000000 .L0 + 0
# RELAX-NEXT: Relocation section '.rela.eh_frame' at offset {{.*}} contains 5 entries:
# RELAX-NEXT: Relocation section '.rela.eh_frame' at offset {{.*}} contains 7 entries:
# RELAX: Offset Info Type Sym. Value Symbol's Name + Addend
# RELAX-NEXT: 0000001c 00000139 R_RISCV_32_PCREL 00000000 .L0 + 0
# RELAX-NEXT: 00000020 00000c23 R_RISCV_ADD32 0001017a .L0 + 0
# RELAX-NEXT: 00000020 00000d23 R_RISCV_ADD32 0001017a .L0 + 0
# RELAX-NEXT: 00000020 00000127 R_RISCV_SUB32 00000000 .L0 + 0
# RELAX-NEXT: 00000035 00000b35 R_RISCV_SET6 00010176 .L0 + 0
# RELAX-NEXT: 00000035 00000934 R_RISCV_SUB6 0001016e .L0 + 0
# RELAX-NEXT: 00000026 00000536 R_RISCV_SET8 00000068 .L0 + 0
# RELAX-NEXT: 00000026 00000125 R_RISCV_SUB8 00000000 .L0 + 0
# RELAX-NEXT: 00000035 00000c35 R_RISCV_SET6 00010176 .L0 + 0
# RELAX-NEXT: 00000035 00000a34 R_RISCV_SUB6 0001016e .L0 + 0
# CHECK-EMPTY:
# NORELAX: Symbol table '.symtab' contains 13 entries:
# RELAX: Symbol table '.symtab' contains 16 entries:
# NORELAX: Symbol table '.symtab' contains 14 entries:
# RELAX: Symbol table '.symtab' contains 18 entries:
# RELAX-NEXT: Num: Value Size Type Bind Vis Ndx Name
# RELAX-NEXT: 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
# RELAX-NEXT: 1: 00000000 0 NOTYPE LOCAL DEFAULT 2 .L0 {{$}}
# RELAX: 3: 00000004 0 NOTYPE LOCAL DEFAULT 2 .L0{{$}}
# RELAX: 9: 0001016e 0 NOTYPE LOCAL DEFAULT 2 .L0 {{$}}
# RELAX: 11: 00010176 0 NOTYPE LOCAL DEFAULT 2 .L0 {{$}}
# RELAX: 12: 0001017a 0 NOTYPE LOCAL DEFAULT 2 .L0 {{$}}
# RELAX: 3: 00000008 0 NOTYPE LOCAL DEFAULT 2 .L0{{$}}
# RELAX: 10: 0001016e 0 NOTYPE LOCAL DEFAULT 2 .L0 {{$}}
# RELAX: 12: 00010176 0 NOTYPE LOCAL DEFAULT 2 .L0 {{$}}
# RELAX: 13: 0001017a 0 NOTYPE LOCAL DEFAULT 2 .L0 {{$}}

# CHECK-DWARFDUMP: DW_CFA_advance_loc1: 104
# CHECK-DWARFDUMP-NEXT: DW_CFA_def_cfa_offset: +8
Expand All @@ -48,11 +50,11 @@
.type test,@function
test:
.cfi_startproc
nop
call foo
## This looks similar to fake label names ".L0 ". Even if this is ".L0 ",
## the assembler will not conflate it with fake labels.
.L0:
.zero 100, 0x90
.zero 96, 0x90
.cfi_def_cfa_offset 8
nop
.zero 255, 0x90
Expand Down
19 changes: 6 additions & 13 deletions llvm/test/MC/RISCV/nop-slide.s
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# RUN: llvm-mc -triple riscv64 -mattr +c,-relax -filetype obj -o - %s | llvm-objdump -d - | FileCheck %s -check-prefix CHECK-RVC-NORELAX
# RUN: llvm-mc -triple riscv64 -mattr +c,+relax -filetype obj -o - %s | llvm-objdump -d - | FileCheck %s -check-prefix CHECK-RVC-RELAX
# RUN: llvm-mc -triple riscv64 -mattr +c,-relax -filetype obj -o - %s | llvm-objdump -d - | FileCheck %s -check-prefix CHECK-RVC
# RUN: llvm-mc -triple riscv64 -mattr +c,+relax -filetype obj -o - %s | llvm-objdump -d - | FileCheck %s -check-prefix CHECK-RVC
# RUN: llvm-mc -triple riscv64 -mattr -c,-relax -filetype obj -o - %s | llvm-objdump -d - | FileCheck %s
# RUN: llvm-mc -triple riscv64 -mattr -c,+relax -filetype obj -o - %s | llvm-objdump -d - | FileCheck %s

Expand All @@ -9,17 +9,10 @@
.balign 4
auipc a0, 0

# CHECK-RVC-NORELAX: 0000000000000000 <.text>:
# CHECK-RVC-NORELAX-NEXT: 0: 0000 unimp
# CHECK-RVC-NORELAX-NEXT: 2: 0001 nop
# CHECK-RVC-NORELAX-NEXT: 4: 00000517 auipc a0, 0x0

# CHECK-RVC-RELAX: 0000000000000000 <.text>:
# CHECK-RVC-RELAX-NEXT: 0: 0001 nop
# CHECK-RVC-RELAX-NEXT: 2: 0100 addi s0, sp, 0x80
# CHECK-RVC-RELAX-NEXT: 4: 1700 addi s0, sp, 0x3a0
# CHECK-RVC-RELAX-NEXT: 6: 0005 c.nop 0x1
# CHECK-RVC-RELAX-NEXT: 8: 00 <unknown>
# CHECK-RVC: 0000000000000000 <.text>:
# CHECK-RVC-NEXT: 0: 0000 unimp
# CHECK-RVC-NEXT: 2: 0001 nop
# CHECK-RVC-NEXT: 4: 00000517 auipc a0, 0x0

# CHECK: 0000000000000000 <.text>:
# CHECK-NEXT: 0: 0000 <unknown>
Expand Down
Loading