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 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
10 changes: 6 additions & 4 deletions lld/test/ELF/riscv-relax-align.s
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# RUN: ld.lld -Ttext=0x10000 --no-relax 32.o -o 32.norelax
# RUN: llvm-objdump -td --no-show-raw-insn -M no-aliases 32.norelax | FileCheck %s

# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax %s -o 64.o
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax %s -riscv-align-rvc=0 -o 64.o
# RUN: ld.lld -Ttext=0x10000 64.o -o 64
# RUN: llvm-objdump -td --no-show-raw-insn -M no-aliases 64 | FileCheck %s
# RUN: ld.lld -Ttext=0x10000 --no-relax 64.o -o 64.norelax
Expand All @@ -29,7 +29,7 @@
# CHECK-DAG: 00010000 g .text {{0*}}38 _start

# CHECK: <_start>:
# CHECK-NEXT: addi a0, a0, 0x1
# CHECK-NEXT: lui a0, 0x10
# CHECK-EMPTY:
# CHECK-NEXT: <a>:
# CHECK-NEXT: addi a0, a0, 0x2
Expand Down Expand Up @@ -82,7 +82,9 @@
# GC-NOT: <d>:

# CHECKR: <_start>:
# CHECKR-NEXT: addi a0, a0, 0x1
# CHECKR-NEXT: lui a0, 0x0
# CHECKR-NEXT: 0000000000000000: R_RISCV_HI20 _start
# CHECKR-NEXT: 0000000000000000: R_RISCV_RELAX *ABS*
# CHECKR-EMPTY:
# CHECKR-NEXT: <a>:
# CHECKR-NEXT: addi a0, a0, 0x2
Expand Down Expand Up @@ -116,7 +118,7 @@

.global _start
_start:
addi a0, a0, 0x1
lui a0, %hi(_start)
a:
addi a0, a0, 0x2
b:
Expand Down
4 changes: 2 additions & 2 deletions lld/test/ELF/riscv-relax-emit-relocs.s
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@

# RUN: rm -rf %t && mkdir %t && cd %t

# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax %s -o 32.o
# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax %s -o 32.o -riscv-align-rvc=0
# RUN: ld.lld -Ttext=0x10000 --emit-relocs 32.o -o 32
# RUN: llvm-objdump -dr --no-show-raw-insn -M no-aliases 32 | FileCheck %s

# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax %s -o 64.o
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax %s -o 64.o -riscv-align-rvc=0
# RUN: ld.lld -Ttext=0x10000 --emit-relocs 64.o -o 64
# RUN: llvm-objdump -dr --no-show-raw-insn -M no-aliases 64 | FileCheck %s

Expand Down
13 changes: 7 additions & 6 deletions llvm/include/llvm/MC/MCSection.h
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,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 @@ -543,10 +547,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 @@ -601,8 +601,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 @@ -443,7 +443,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 @@ -254,7 +254,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
30 changes: 22 additions & 8 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ static cl::opt<bool> ULEB128Reloc(
"riscv-uleb128-reloc", cl::init(true), cl::Hidden,
cl::desc("Emit R_RISCV_SET_ULEB128/E_RISCV_SUB_ULEB128 if appropriate"));

static cl::opt<bool>
AlignRvc("riscv-align-rvc", cl::init(true), cl::Hidden,
cl::desc("When generating R_RISCV_ALIGN, insert $alignment-2 "
"bytes of NOPs even in norvc code"));
Comment on lines +35 to +38
Copy link
Member

Choose a reason for hiding this comment

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

Is the intention to get rid of this once all the tests can be updated? I don't mind either way, it's just good to know for future reference.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, we can get rid of them after all the tests are updated. This might also be useful to restore the old behavior for debugging before toolchain's R_RISCV_ALIGN becomes more stable. This should hopefully be removed in one year or two.


RISCVAsmBackend::RISCVAsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI,
bool Is64Bit, const MCTargetOptions &Options)
: MCAsmBackend(llvm::endianness::little), STI(STI), OSABI(OSABI),
Expand Down Expand Up @@ -306,12 +311,21 @@ 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;
unsigned MinNopLen = STI->hasFeature(RISCV::FeatureStdExtZca) ? 2 : 4;

// Use default handling unless the alignment is larger than the nop size.
const MCSubtargetInfo *STI = F.getSubtargetInfo();
unsigned MinNopLen =
AlignRvc || STI->hasFeature(RISCV::FeatureStdExtZca) ? 2 : 4;
if (F.getAlignment() <= MinNopLen)
return false;

Expand All @@ -321,7 +335,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 Expand Up @@ -474,8 +487,9 @@ bool RISCVAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
// TODO: emit a mapping symbol right here

if (Count % 4 == 2) {
// The canonical nop with Zca is c.nop.
OS.write(STI->hasFeature(RISCV::FeatureStdExtZca) ? "\x01\0" : "\0\0", 2);
// The canonical nop with Zca is c.nop. For .balign 4, we generate a 2-byte
// c.nop even in a norvc region.
OS.write("\x01\0", 2);
Count -= 2;
}

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: 4: 00 00 01 00 .word 0x00010000
# CHECK-EMPTY:
# CHECK: 8: 78 56 34 12 .word 0x12345678
# CHECK-NEXT: c: 00 00 00 00 .word 0x00000000
# CHECK: 10: auipc ra, 0x0
# CHECK-NEXT: R_RISCV_CALL_PLT foo
# CHECK-NEXT: R_RISCV_RELAX *ABS*
# CHECK: 18: c.nop
# CHECK-NEXT: R_RISCV_ALIGN *ABS*+0x6

## Alignment directives in a lower-numbered subsection may be conservatively treated as linker-relaxable.
# CHECK0: 4: 00 00 01 00 .word 0x00010000
# CHECK0-NEXT: 000000006: R_RISCV_ALIGN *ABS*+0x6
# CHECK0-NEXT: 8: 13 00 00 00 .word 0x00000013
# CHECK0: 14: auipc ra, 0x0
# CHECK0: 1c: 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
.org .+1
.org .+3
.ifdef LATE
.org .+0
.endif
call foo

.text 0
_start:
.space 6
.option push
.option norelax
.balign 8
l0:
.word 0x12345678
.option pop
23 changes: 23 additions & 0 deletions llvm/test/MC/RISCV/Relocations/align-norvc.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## To ensure ALIGN relocations in norvc code can adapt to shrinking of preceding rvc code,
## we generate $alignment-2 bytes of NOPs regardless of rvc.
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax %s -o %t
# RUN: llvm-objdump -dr -M no-aliases %t | FileCheck %s

# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax -riscv-align-rvc=0 %s -o %t0
# RUN: llvm-objdump -dr -M no-aliases %t0 | FileCheck %s --check-prefix=CHECK0

# CHECK: 00000000: R_RISCV_RELAX *ABS*
# CHECK-NEXT: 4: 0001 <unknown>
# CHECK-NEXT: 00000004: R_RISCV_ALIGN *ABS*+0x6
# CHECK-NEXT: 6: 00000013 addi zero, zero, 0x0
# CHECK-NEXT: a: 00000537 lui a0, 0x0

# CHECK0: 00000000: R_RISCV_RELAX *ABS*
# CHECK0-NEXT: 4: 00000013 addi zero, zero, 0x0
# CHECK0-NEXT: 00000004: R_RISCV_ALIGN *ABS*+0x4
# CHECK0-NEXT: 8: 00000537 lui a0, 0x0

lui a0, %hi(foo)
.option norvc
.balign 8
lui a0, %hi(foo)
8 changes: 4 additions & 4 deletions llvm/test/MC/RISCV/Relocations/mc-dump.s
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
# CHECK-NEXT:0 Data LinkerRelaxable Size:8 [97,00,00,00,e7,80,00,00]
# CHECK-NEXT: Fixup @0 Value:specifier(19,ext) Kind:4023
# CHECK-NEXT: Symbol @0 $x
# CHECK-NEXT:8 Align LinkerRelaxable Size:0+4 []
# CHECK-NEXT:8 Align LinkerRelaxable Size:0+6 []
# CHECK-NEXT: Align:8 Fill:0 FillLen:1 MaxBytesToEmit:8 Nops
# CHECK-NEXT: Fixup @0 Value:4 Kind:[[#]]
# CHECK-NEXT:12 Align LinkerRelaxable Size:4+4 [13,05,30,00]
# CHECK-NEXT: Fixup @0 Value:6 Kind:[[#]]
# CHECK-NEXT:14 Align LinkerRelaxable Size:4+6 [13,05,30,00]
# CHECK-NEXT: Align:8 Fill:0 FillLen:1 MaxBytesToEmit:8 Nops
# CHECK-NEXT: Fixup @4 Value:4 Kind:[[#]]
# CHECK-NEXT: Fixup @4 Value:6 Kind:[[#]]
# CHECK-NEXT:]

call ext
Expand Down
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
45 changes: 18 additions & 27 deletions llvm/test/MC/RISCV/align.s
Original file line number Diff line number Diff line change
Expand Up @@ -46,20 +46,21 @@
# 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
# RELAX-RELOC: R_RISCV_ALIGN - 0x4
# RELAX-RELOC: R_RISCV_ALIGN - 0x6
# RELAX-INST: addi zero, zero, 0
# C-OR-ZCA-EXT-RELAX-RELOC: R_RISCV_ALIGN - 0x6
# C-OR-ZCA-EXT-RELAX-INST: c.nop
Expand All @@ -68,7 +69,7 @@ test:
add a0, a0, a1
.align 4
.LBB0_2:
# RELAX-RELOC: R_RISCV_ALIGN - 0xC
# RELAX-RELOC: R_RISCV_ALIGN - 0xE
# RELAX-INST: addi zero, zero, 0
# RELAX-INST: addi zero, zero, 0
# RELAX-INST: addi zero, zero, 0
Expand All @@ -84,7 +85,7 @@ test:
.p2align 3
.constant_pool:
.long 3126770193
# RELAX-RELOC: R_RISCV_ALIGN - 0x4
# RELAX-RELOC: R_RISCV_ALIGN - 0x6
# RELAX-INST: addi zero, zero, 0
# NORELAX-INST: addi zero, zero, 0
# C-OR-ZCA-EXT-RELAX-RELOC: R_RISCV_ALIGN - 0x6
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: 0x10 R_RISCV_ALIGN - 0x6
# RELAX-RELOC-NEXT: 0x16 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
Loading
Loading