Skip to content

Commit 3769ce0

Browse files
authored
MC: Refine ALIGN relocation conditions
Each section now tracks the index of the first linker-relaxable fragment, enabling two changes: * Delete redundant ALIGN relocations before the first linker-relaxable instruction in a section. The primary example is the offset 0 R_RISCV_ALIGN relocation for a text section aligned by 4. * For alignments larger than the NOP size after the first linker-relaxable instruction, ALIGN relocations are now generated, even in norelax regions. This fixes the issue #150159. The new test llvm/test/MC/RISCV/Relocations/align-after-relax.s verifies the required ALIGN in a norelax region following linker-relaxable instructions. By using a fragment index within the subsection (which is less than or equal to the section's index), the implementation may generate redundant ALIGN relocations in lower-numbered subsections before the first linker-relaxable instruction. align-option-relax.s demonstrates the ALIGN optimization. Add an initial `call` to a few tests to prevent the ALIGN optimization. --- When the alignment exceeds 2, we insert $alignment-2 bytes of NOPs, even in non-RVC code. This enables non-RVC code following RVC code to handle a 2-byte adjustment without requiring an additional state in MCSection or AsmParser. ``` .globl _start _start: // GNU ld can relax this to 6505 lui a0, 0x1 // LLD hasn't implemented this transformation. lui a0, %hi(foo) .option push .option norelax .option norvc // Now we generate R_RISCV_ALIGN with addend 2, even if this is a norvc region. .balign 4 b0: .word 0x3a393837 .option pop foo: ``` Pull Request: #150816
1 parent c9f3a70 commit 3769ce0

File tree

14 files changed

+172
-85
lines changed

14 files changed

+172
-85
lines changed

lld/test/ELF/riscv-relax-align.s

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
# RUN: ld.lld -Ttext=0x10000 --no-relax 32.o -o 32.norelax
1111
# RUN: llvm-objdump -td --no-show-raw-insn -M no-aliases 32.norelax | FileCheck %s
1212

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

3131
# CHECK: <_start>:
32-
# CHECK-NEXT: addi a0, a0, 0x1
32+
# CHECK-NEXT: lui a0, 0x10
3333
# CHECK-EMPTY:
3434
# CHECK-NEXT: <a>:
3535
# CHECK-NEXT: addi a0, a0, 0x2
@@ -82,7 +82,9 @@
8282
# GC-NOT: <d>:
8383

8484
# CHECKR: <_start>:
85-
# CHECKR-NEXT: addi a0, a0, 0x1
85+
# CHECKR-NEXT: lui a0, 0x0
86+
# CHECKR-NEXT: 0000000000000000: R_RISCV_HI20 _start
87+
# CHECKR-NEXT: 0000000000000000: R_RISCV_RELAX *ABS*
8688
# CHECKR-EMPTY:
8789
# CHECKR-NEXT: <a>:
8890
# CHECKR-NEXT: addi a0, a0, 0x2
@@ -116,7 +118,7 @@
116118

117119
.global _start
118120
_start:
119-
addi a0, a0, 0x1
121+
lui a0, %hi(_start)
120122
a:
121123
addi a0, a0, 0x2
122124
b:

lld/test/ELF/riscv-relax-emit-relocs.s

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33

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

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

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

llvm/include/llvm/MC/MCSection.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,10 @@ class LLVM_ABI MCSection {
534534
Align Alignment;
535535
/// The section index in the assemblers section list.
536536
unsigned Ordinal = 0;
537+
// If not -1u, the first linker-relaxable fragment's order within the
538+
// subsection. When present, the offset between two locations crossing this
539+
// fragment may not be fully resolved.
540+
unsigned FirstLinkerRelaxable = -1u;
537541

538542
/// Whether this section has had instructions emitted into it.
539543
bool HasInstructions : 1;
@@ -543,10 +547,6 @@ class LLVM_ABI MCSection {
543547
bool IsText : 1;
544548
bool IsBss : 1;
545549

546-
/// Whether the section contains linker-relaxable fragments. If true, the
547-
/// offset between two locations may not be fully resolved.
548-
bool LinkerRelaxable : 1;
549-
550550
MCFragment DummyFragment;
551551

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

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

607608
MCFragment &getDummyFragment() { return DummyFragment; }
608609

llvm/lib/MC/MCObjectStreamer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ void MCObjectStreamer::emitInstToData(const MCInst &Inst,
443443
// MCAssembler::relaxAlign.
444444
auto *Sec = F->getParent();
445445
if (!Sec->isLinkerRelaxable())
446-
Sec->setLinkerRelaxable();
446+
Sec->setFirstLinkerRelaxable(F->getLayoutOrder());
447447
// Do not add data after a linker-relaxable instruction. The difference
448448
// between a new label and a label at or before the linker-relaxable
449449
// instruction cannot be resolved at assemble-time.

llvm/lib/MC/MCSection.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ using namespace llvm;
2020

2121
MCSection::MCSection(StringRef Name, bool IsText, bool IsBss, MCSymbol *Begin)
2222
: Begin(Begin), HasInstructions(false), IsRegistered(false), IsText(IsText),
23-
IsBss(IsBss), LinkerRelaxable(false), Name(Name) {
23+
IsBss(IsBss), Name(Name) {
2424
DummyFragment.setParent(this);
2525
}
2626

llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,8 @@ bool LoongArchAsmBackend::relaxAlign(MCFragment &F, unsigned &Size) {
254254
MCFixup::create(0, Expr, FirstLiteralRelocationKind + ELF::R_LARCH_ALIGN);
255255
F.setVarFixups({Fixup});
256256
F.setLinkerRelaxable();
257-
F.getParent()->setLinkerRelaxable();
257+
if (!F.getParent()->isLinkerRelaxable())
258+
F.getParent()->setFirstLinkerRelaxable(F.getLayoutOrder());
258259
return true;
259260
}
260261

llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ static cl::opt<bool> ULEB128Reloc(
3232
"riscv-uleb128-reloc", cl::init(true), cl::Hidden,
3333
cl::desc("Emit R_RISCV_SET_ULEB128/E_RISCV_SUB_ULEB128 if appropriate"));
3434

35+
static cl::opt<bool>
36+
AlignRvc("riscv-align-rvc", cl::init(true), cl::Hidden,
37+
cl::desc("When generating R_RISCV_ALIGN, insert $alignment-2 "
38+
"bytes of NOPs even in norvc code"));
39+
3540
RISCVAsmBackend::RISCVAsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI,
3641
bool Is64Bit, const MCTargetOptions &Options)
3742
: MCAsmBackend(llvm::endianness::little), STI(STI), OSABI(OSABI),
@@ -306,12 +311,21 @@ void RISCVAsmBackend::relaxInstruction(MCInst &Inst,
306311
// If conditions are met, compute the padding size and create a fixup encoding
307312
// the padding size in the addend.
308313
bool RISCVAsmBackend::relaxAlign(MCFragment &F, unsigned &Size) {
309-
// Use default handling unless linker relaxation is enabled and the alignment
310-
// is larger than the nop size.
311-
const MCSubtargetInfo *STI = F.getSubtargetInfo();
312-
if (!STI->hasFeature(RISCV::FeatureRelax))
314+
// Alignments before the first linker-relaxable instruction have fixed sizes
315+
// and do not require relocations. Alignments after a linker-relaxable
316+
// instruction require a relocation, even if the STI specifies norelax.
317+
//
318+
// firstLinkerRelaxable is the layout order within the subsection, which may
319+
// be smaller than the section's order. Therefore, alignments in a
320+
// lower-numbered subsection may be unnecessarily treated as linker-relaxable.
321+
auto *Sec = F.getParent();
322+
if (F.getLayoutOrder() <= Sec->firstLinkerRelaxable())
313323
return false;
314-
unsigned MinNopLen = STI->hasFeature(RISCV::FeatureStdExtZca) ? 2 : 4;
324+
325+
// Use default handling unless the alignment is larger than the nop size.
326+
const MCSubtargetInfo *STI = F.getSubtargetInfo();
327+
unsigned MinNopLen =
328+
AlignRvc || STI->hasFeature(RISCV::FeatureStdExtZca) ? 2 : 4;
315329
if (F.getAlignment() <= MinNopLen)
316330
return false;
317331

@@ -321,7 +335,6 @@ bool RISCVAsmBackend::relaxAlign(MCFragment &F, unsigned &Size) {
321335
MCFixup::create(0, Expr, FirstLiteralRelocationKind + ELF::R_RISCV_ALIGN);
322336
F.setVarFixups({Fixup});
323337
F.setLinkerRelaxable();
324-
F.getParent()->setLinkerRelaxable();
325338
return true;
326339
}
327340

@@ -474,8 +487,9 @@ bool RISCVAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
474487
// TODO: emit a mapping symbol right here
475488

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

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax %s --defsym LATE=1 -o %t1
2+
# RUN: llvm-objdump -dr --no-show-raw-insn -M no-aliases %t1 | FileCheck %s
3+
4+
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax %s -o %t0
5+
# RUN: llvm-objdump -dr --no-show-raw-insn -M no-aliases %t0 | FileCheck %s --check-prefix=CHECK0
6+
7+
# CHECK: 4: 00 00 01 00 .word 0x00010000
8+
# CHECK-EMPTY:
9+
# CHECK: 8: 78 56 34 12 .word 0x12345678
10+
# CHECK-NEXT: c: 00 00 00 00 .word 0x00000000
11+
# CHECK: 10: auipc ra, 0x0
12+
# CHECK-NEXT: R_RISCV_CALL_PLT foo
13+
# CHECK-NEXT: R_RISCV_RELAX *ABS*
14+
# CHECK: 18: c.nop
15+
# CHECK-NEXT: R_RISCV_ALIGN *ABS*+0x6
16+
17+
## Alignment directives in a lower-numbered subsection may be conservatively treated as linker-relaxable.
18+
# CHECK0: 4: 00 00 01 00 .word 0x00010000
19+
# CHECK0-NEXT: 000000006: R_RISCV_ALIGN *ABS*+0x6
20+
# CHECK0-NEXT: 8: 13 00 00 00 .word 0x00000013
21+
# CHECK0: 14: auipc ra, 0x0
22+
# CHECK0: 1c: c.nop
23+
# CHECK0-NEXT: R_RISCV_ALIGN *ABS*+0x6
24+
25+
.text 2
26+
.option push
27+
.option norelax
28+
## R_RISCV_ALIGN is required even if norelax, because it is after a linker-relaxable instruction.
29+
.balign 8
30+
l2:
31+
.word 0x12345678
32+
.option pop
33+
34+
.text 1
35+
.org .+1
36+
.org .+3
37+
.ifdef LATE
38+
.org .+0
39+
.endif
40+
call foo
41+
42+
.text 0
43+
_start:
44+
.space 6
45+
.option push
46+
.option norelax
47+
.balign 8
48+
l0:
49+
.word 0x12345678
50+
.option pop
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
## To ensure ALIGN relocations in norvc code can adapt to shrinking of preceding rvc code,
2+
## we generate $alignment-2 bytes of NOPs regardless of rvc.
3+
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax %s -o %t
4+
# RUN: llvm-objdump -dr -M no-aliases %t | FileCheck %s
5+
6+
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax -riscv-align-rvc=0 %s -o %t0
7+
# RUN: llvm-objdump -dr -M no-aliases %t0 | FileCheck %s --check-prefix=CHECK0
8+
9+
# CHECK: 00000000: R_RISCV_RELAX *ABS*
10+
# CHECK-NEXT: 4: 0001 <unknown>
11+
# CHECK-NEXT: 00000004: R_RISCV_ALIGN *ABS*+0x6
12+
# CHECK-NEXT: 6: 00000013 addi zero, zero, 0x0
13+
# CHECK-NEXT: a: 00000537 lui a0, 0x0
14+
15+
# CHECK0: 00000000: R_RISCV_RELAX *ABS*
16+
# CHECK0-NEXT: 4: 00000013 addi zero, zero, 0x0
17+
# CHECK0-NEXT: 00000004: R_RISCV_ALIGN *ABS*+0x4
18+
# CHECK0-NEXT: 8: 00000537 lui a0, 0x0
19+
20+
lui a0, %hi(foo)
21+
.option norvc
22+
.balign 8
23+
lui a0, %hi(foo)

llvm/test/MC/RISCV/Relocations/mc-dump.s

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99
# CHECK-NEXT:0 Data LinkerRelaxable Size:8 [97,00,00,00,e7,80,00,00]
1010
# CHECK-NEXT: Fixup @0 Value:specifier(19,ext) Kind:4023
1111
# CHECK-NEXT: Symbol @0 $x
12-
# CHECK-NEXT:8 Align LinkerRelaxable Size:0+4 []
12+
# CHECK-NEXT:8 Align LinkerRelaxable Size:0+6 []
1313
# CHECK-NEXT: Align:8 Fill:0 FillLen:1 MaxBytesToEmit:8 Nops
14-
# CHECK-NEXT: Fixup @0 Value:4 Kind:[[#]]
15-
# CHECK-NEXT:12 Align LinkerRelaxable Size:4+4 [13,05,30,00]
14+
# CHECK-NEXT: Fixup @0 Value:6 Kind:[[#]]
15+
# CHECK-NEXT:14 Align LinkerRelaxable Size:4+6 [13,05,30,00]
1616
# CHECK-NEXT: Align:8 Fill:0 FillLen:1 MaxBytesToEmit:8 Nops
17-
# CHECK-NEXT: Fixup @4 Value:4 Kind:[[#]]
17+
# CHECK-NEXT: Fixup @4 Value:6 Kind:[[#]]
1818
# CHECK-NEXT:]
1919

2020
call ext

0 commit comments

Comments
 (0)