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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

MaskRay
Copy link
Member

@MaskRay MaskRay commented Jul 27, 2025

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 [RISCV] Fix alignment when mixing rvc/norvc relax/norelax code #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.

Created using spr 1.3.5-bogner
@llvmbot
Copy link
Member

llvmbot commented Jul 27, 2025

@llvm/pr-subscribers-mc
@llvm/pr-subscribers-backend-risc-v

@llvm/pr-subscribers-backend-loongarch

Author: Fangrui Song (MaskRay)

Changes

Generalize MCSection::LinkerRelaxable to a fragment index to implement
two behaviors:

  • Delete redundant ALIGN relocations before the first linker-relaxable
    instruction in the section.
  • Ensure alignments after the first linker-relaxable instruction,
    larger than the nop size, generate relocations, even if the
    MCSubtargetInfo specifies norelax. Fix the issue described by #150159

The new test llvm/test/MC/RISCV/Relocations/align-after-relax.s
demonstrates the second behavior. Before this patch, we did not generate
an ALIGN relocation for .balign 8: .word 0x12345678 inside a norelax
region after linker-relaxable instructions, potentially leading to
unaligned data after linker relaxation.


Full diff: https://github.com/llvm/llvm-project/pull/150816.diff

10 Files Affected:

  • (modified) llvm/include/llvm/MC/MCSection.h (+7-6)
  • (modified) llvm/lib/MC/MCObjectStreamer.cpp (+3-1)
  • (modified) llvm/lib/MC/MCSection.cpp (+1-1)
  • (modified) llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp (+2-1)
  • (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp (+14-5)
  • (added) llvm/test/MC/RISCV/Relocations/align-after-relax.s (+50)
  • (modified) llvm/test/MC/RISCV/align-option-relax.s (+18-5)
  • (modified) llvm/test/MC/RISCV/align.s (+13-22)
  • (modified) llvm/test/MC/RISCV/cfi-advance.s (+15-13)
  • (modified) llvm/test/MC/RISCV/nop-slide.s (+6-13)
diff --git a/llvm/include/llvm/MC/MCSection.h b/llvm/include/llvm/MC/MCSection.h
index 7989310e5a8f2..f70ed4ade23f2 100644
--- a/llvm/include/llvm/MC/MCSection.h
+++ b/llvm/include/llvm/MC/MCSection.h
@@ -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;
@@ -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
@@ -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; }
 
diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp
index f0465521c1433..6c66031e7dfb3 100644
--- a/llvm/lib/MC/MCObjectStreamer.cpp
+++ b/llvm/lib/MC/MCObjectStreamer.cpp
@@ -361,7 +361,9 @@ void MCObjectStreamer::emitInstToData(const MCInst &Inst,
     // instruction cannot be resolved at assemble-time.
     if (!MarkedLinkerRelaxable) {
       MarkedLinkerRelaxable = true;
-      getCurrentSectionOnly()->setLinkerRelaxable();
+      auto *Sec = getCurrentSectionOnly();
+      if (!Sec->isLinkerRelaxable())
+        Sec->setFirstLinkerRelaxable(F->getLayoutOrder());
       newFragment();
     }
   }
diff --git a/llvm/lib/MC/MCSection.cpp b/llvm/lib/MC/MCSection.cpp
index 4f282672afbbf..eafd59a2478e9 100644
--- a/llvm/lib/MC/MCSection.cpp
+++ b/llvm/lib/MC/MCSection.cpp
@@ -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);
 }
 
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp
index d9ea88cdeaf24..6110920b3760e 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp
@@ -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())
+    F.getParent()->setFirstLinkerRelaxable(F.getLayoutOrder());
   return true;
 }
 
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
index 82e3b5ceb4ef6..2d9ffc69ccc2f 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
@@ -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 following a linker-relaxable
+  // instruction require a relocation, even if the STI specifies norelax.
+  //
+  // firstLinkerRelaxable represents the layout order within the subsection,
+  // which may be smaller than the section's order. Therefore, alignments in
+  // an earlier 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;
@@ -321,7 +329,8 @@ bool RISCVAsmBackend::relaxAlign(MCFragment &F, unsigned &Size) {
       MCFixup::create(0, Expr, FirstLiteralRelocationKind + ELF::R_RISCV_ALIGN);
   F.setVarFixups({Fixup});
   F.setLinkerRelaxable();
-  F.getParent()->setLinkerRelaxable();
+  if (!Sec->isLinkerRelaxable())
+    Sec->setFirstLinkerRelaxable(F.getLayoutOrder());
   return true;
 }
 
diff --git a/llvm/test/MC/RISCV/Relocations/align-after-relax.s b/llvm/test/MC/RISCV/Relocations/align-after-relax.s
new file mode 100644
index 0000000000000..cb22e0245e286
--- /dev/null
+++ b/llvm/test/MC/RISCV/Relocations/align-after-relax.s
@@ -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 smaller-number subsection might 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 there is a preceding 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
diff --git a/llvm/test/MC/RISCV/align-option-relax.s b/llvm/test/MC/RISCV/align-option-relax.s
index 890e1e72d7706..60cd55f5a8b4d 100644
--- a/llvm/test/MC/RISCV/align-option-relax.s
+++ b/llvm/test/MC/RISCV/align-option-relax.s
@@ -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
diff --git a/llvm/test/MC/RISCV/align.s b/llvm/test/MC/RISCV/align.s
index da3b1aa9b637a..ab317f079dbcd 100644
--- a/llvm/test/MC/RISCV/align.s
+++ b/llvm/test/MC/RISCV/align.s
@@ -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
@@ -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
@@ -157,7 +150,6 @@ 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
@@ -165,6 +157,8 @@ data2:
 # 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
@@ -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
diff --git a/llvm/test/MC/RISCV/cfi-advance.s b/llvm/test/MC/RISCV/cfi-advance.s
index f3f8530c419f0..bad2ef07235e5 100644
--- a/llvm/test/MC/RISCV/cfi-advance.s
+++ b/llvm/test/MC/RISCV/cfi-advance.s
@@ -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
@@ -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
@@ -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
diff --git a/llvm/test/MC/RISCV/nop-slide.s b/llvm/test/MC/RISCV/nop-slide.s
index 4dc888b3ba777..9ce2e59f31b08 100644
--- a/llvm/test/MC/RISCV/nop-slide.s
+++ b/llvm/test/MC/RISCV/nop-slide.s
@@ -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
 
@@ -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>

MaskRay added 2 commits July 26, 2025 23:45
Created using spr 1.3.5-bogner
Created using spr 1.3.5-bogner
@@ -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.

@SixWeining
Copy link
Contributor

Thanks for the optimization (To be precise, it's about fixing).

But this seems to only address issues within the same object file. How about different object files merged by the linker with the -r option?

@kito-cheng
Copy link
Member

Share you my test scripts, it seems still some corner case isn't handled well.

The test script will show all step and why it fail :)

Setup

$ git clone git@github.com:kito-cheng/riscv-alignment-check.git
$ cd riscv-alignment-check
$ wget https://github.com/riscv-collab/riscv-gnu-toolchain/releases/download/2025.07.16/riscv64-glibc-ubuntu-22.04-gcc-nightly-2025.07.16-nightly.tar.xz
$ tar -xf riscv64-glibc-ubuntu-22.04-gcc-nightly-2025.07.16-nightly.tar.xz

How to run:

./test_runner.py --toolchain-base `pwd`/riscv/bin --clang --clang-path <path-to-clang> | tee log

Result for this PR:

==================================================
TEST SUMMARY
==================================================
norvc                     PASS
norvc-norelax             PASS
norelax                   PASS
relax-rvc                 PASS
relax1-norvc              FAIL
relax1-norvc-norelax      FAIL
relax1-norelax            PASS
relax1-relax-rvc          PASS
relax2-norvc              PASS
relax2-norvc-norelax      PASS
relax2-norelax            PASS
relax2-relax-rvc          PASS
relax3-norvc              FAIL
relax3-norvc-norelax      FAIL
relax3-norelax            PASS
relax3-relax-rvc          PASS
relax4-norvc              PASS
relax4-norvc-norelax      PASS
relax4-norelax            PASS
relax4-relax-rvc          PASS
relax5-norvc              PASS
relax5-norvc-norelax      PASS
relax5-norelax            PASS
relax5-relax-rvc          PASS
relax6-norvc              PASS
relax6-norvc-norelax      PASS
relax6-norelax            PASS
relax6-relax-rvc          PASS
relax7-norvc              FAIL
relax7-norvc-norelax      FAIL
relax7-norelax            FAIL
relax7-relax-rvc          FAIL
relax8-norvc              PASS
relax8-norvc-norelax      PASS
relax8-norelax            PASS
relax8-relax-rvc          PASS
relax9-norvc              PASS
relax9-norvc-norelax      PASS
relax9-norelax            PASS
relax9-relax-rvc          PASS
relax10-norvc             PASS
relax10-norvc-norelax     PASS
relax10-norelax           PASS
relax10-relax-rvc         PASS
relax11-norvc             PASS
relax11-norvc-norelax     PASS
relax11-norelax           PASS
relax11-relax-rvc         PASS
relax12-norvc             PASS
relax12-norvc-norelax     PASS
relax12-norelax           PASS
relax12-relax-rvc         PASS

Results: 44/52 tests passed
Some tests failed! ✗

@MaskRay
Copy link
Member Author

MaskRay commented Jul 28, 2025

@SixWeining reminded me that we have a large problem when mixing -mrelax and -mno-relax object files in relocatable links (-r).
Since we don't generate ALIGN relocations for the -mno-relax relocatable files, their alignment can be lost.
Since we can use a linker script with relocatable links, we should either force ALIGN for all text sections regardless of -mrelax or make linker synthesize ALIGN relocations at input section starts.

cat > x0.s <<e
.globl _start
_start:
  call foo
e
cat > x1.s <<e
.option push
.option norelax
.balign 8
l2:
  .word 0x12345678
.option pop

.section .text1,"ax"
.globl foo
foo:
e
clang --target=riscv64 -mrelax -c x0.s x1.s
ld.lld -r x0.o x1.o -o x01.o
ld.lld x01.o -o x01

@lenary
Copy link
Member

lenary commented Jul 29, 2025

@SixWeining reminded me that we have a large problem when mixing -mrelax and -mno-relax object files in relocatable links (-r). Since we don't generate ALIGN relocations for the -mno-relax relocatable files, their alignment can be lost. Since we can use a linker script with relocatable links, we should either force ALIGN for all text sections regardless of -mrelax or make linker synthesize ALIGN relocations at input section starts.

cat > x0.s <<e
.globl _start
_start:
  call foo
e
cat > x1.s <<e
.option push
.option norelax
.balign 8
l2:
  .word 0x12345678
.option pop

.section .text1,"ax"
.globl foo
foo:
e
clang --target=riscv64 -mrelax -c x0.s x1.s
ld.lld -r x0.o x1.o -o x01.o
ld.lld x01.o -o x01

I think "make linker synthesize ALIGN relocations at input section starts" would be my preference, otherwise -mno-relax objects will require relaxation support in the linker, which seems a bit odd (yes most linkers have support right now, but it still feels strange to require it)

@MaskRay
Copy link
Member Author

MaskRay commented Jul 31, 2025

I think "make linker synthesize ALIGN relocations at input section starts" would be my preference, otherwise -mno-relax objects will require relaxation support in the linker, which seems a bit odd (yes most linkers have support right now, but it still feels strange to require it)

Agreed. I have made a draft to synthesize ALIGN relocations at section start: MaskRay#5

Created https://sourceware.org/bugzilla/show_bug.cgi?id=33236 ("ld riscv: Relocatable linking challenge with R_RISCV_ALIGN")

@MaskRay
Copy link
Member Author

MaskRay commented Aug 1, 2025

$ git clone git@github.com:kito-cheng/riscv-alignment-check.git

Is this repo public?

% git clone https://github.com/kito-cheng/riscv-alignment-check
Cloning into 'riscv-alignment-check'...
remote: Repository not found.
fatal: repository 'https://github.com/kito-cheng/riscv-alignment-check/' not found

@kito-cheng
Copy link
Member

@MaskRay I thought I made it public before...anyway I change the visibility now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants