From e36442494a57571f98acea6418ea80d1418d4272 Mon Sep 17 00:00:00 2001 From: Sam Elliott Date: Tue, 22 Jul 2025 12:36:22 -0700 Subject: [PATCH 1/2] [MC] Relaxable Fragments Can be Linker Relaxable When relaxing a relaxable fragment, the new fixup may end up being linker relaxable (when the one before relaxation was not). This change ensures that: - a new linker-relaxable fixup propagates that info into the fragment and the section. - linker-relaxable relaxable fragments are handled in attemptToFoldSymbolOffsetDifference. Fixes: #150071 --- llvm/lib/MC/MCAssembler.cpp | 8 ++++++++ llvm/lib/MC/MCExpr.cpp | 5 ++++- llvm/lib/MC/MCFragment.cpp | 2 ++ llvm/lib/MC/MCSection.cpp | 2 ++ .../test/MC/RISCV/linker-relaxation-pr150071.s | 18 ++++++++++++++++++ 5 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 llvm/test/MC/RISCV/linker-relaxation-pr150071.s diff --git a/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp index 2b56e2a3dbf2a..4d487e6e92dfb 100644 --- a/llvm/lib/MC/MCAssembler.cpp +++ b/llvm/lib/MC/MCAssembler.cpp @@ -777,6 +777,14 @@ bool MCAssembler::relaxInstruction(MCFragment &F) { getEmitter().encodeInstruction(Relaxed, Data, Fixups, *F.getSubtargetInfo()); F.setVarContents(Data); F.setVarFixups(Fixups); + + for (const auto &Fixup : Fixups) { + if (!Fixup.isLinkerRelaxable()) + continue; + F.setLinkerRelaxable(); + F.getParent()->setLinkerRelaxable(); + } + return true; } diff --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp index dbb2fd16eb2e5..c3ccdb3e31464 100644 --- a/llvm/lib/MC/MCExpr.cpp +++ b/llvm/lib/MC/MCExpr.cpp @@ -269,7 +269,7 @@ bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm, return IsRelocatable && Value.isAbsolute() && Value.getSpecifier() == 0; } -/// Helper method for \see EvaluateSymbolAdd(). +/// Helper method for \see evaluateSymbolicAdd(). static void attemptToFoldSymbolOffsetDifference(const MCAssembler *Asm, bool InSet, const MCSymbol *&A, const MCSymbol *&B, @@ -361,6 +361,9 @@ static void attemptToFoldSymbolOffsetDifference(const MCAssembler *Asm, if (BBeforeRelax && AAfterRelax) return; } + if (F->getKind() == MCFragment::FT_Relaxable && Asm->hasFinalLayout() && F->isLinkerRelaxable()) + // FIXME: More accurate calculation of AAfterRelax/BBeforeRelax? + return; if (&*F == FA) { // If FA and FB belong to the same subsection, the loop will find FA and // we can resolve the difference. diff --git a/llvm/lib/MC/MCFragment.cpp b/llvm/lib/MC/MCFragment.cpp index 3c395e5ccdb0b..68e7d61fe2f7b 100644 --- a/llvm/lib/MC/MCFragment.cpp +++ b/llvm/lib/MC/MCFragment.cpp @@ -68,6 +68,8 @@ LLVM_DUMP_METHOD void MCFragment::dump() const { OS << "\n Fixup @" << F.getOffset() << " Value:"; F.getValue()->print(OS, nullptr); OS << " Kind:" << F.getKind(); + if (F.isLinkerRelaxable()) + OS << " LinkerRelaxable"; } }; diff --git a/llvm/lib/MC/MCSection.cpp b/llvm/lib/MC/MCSection.cpp index 023f7f27de0aa..54e3ebcedb46f 100644 --- a/llvm/lib/MC/MCSection.cpp +++ b/llvm/lib/MC/MCSection.cpp @@ -41,6 +41,8 @@ LLVM_DUMP_METHOD void MCSection::dump( raw_ostream &OS = errs(); OS << "MCSection Name:" << getName(); + if (isLinkerRelaxable()) + OS << " LinkerRelaxable"; for (auto &F : *this) { OS << '\n'; F.dump(); diff --git a/llvm/test/MC/RISCV/linker-relaxation-pr150071.s b/llvm/test/MC/RISCV/linker-relaxation-pr150071.s new file mode 100644 index 0000000000000..7d5297fbaa937 --- /dev/null +++ b/llvm/test/MC/RISCV/linker-relaxation-pr150071.s @@ -0,0 +1,18 @@ +# RUN: llvm-mc --triple=riscv32 -mattr=+relax,+experimental-xqcilb \ +# RUN: %s -filetype=obj -o - -riscv-add-build-attributes \ +# RUN: | llvm-objdump -dr - \ +# RUN: | FileCheck %s + +.global foo + +bar: + jal x1, foo +# CHECK: qc.e.jal 0x0 +# CHECK-NEXT: R_RISCV_VENDOR QUALCOMM +# CHECK-NEXT: R_RISCV_CUSTOM195 foo +# CHECK-NEXT: R_RISCV_RELAX *ABS* + bne a0, a1, bar +# CHECK-NEXT: bne a0, a1, 0x6 +# CHECK-NEXT: R_RISCV_BRANCH bar + ret +# CHECK-NEXT: ret From 214d5f8e9d93a481f90fa2bf381d9e87b82ae571 Mon Sep 17 00:00:00 2001 From: Sam Elliott Date: Tue, 22 Jul 2025 13:17:15 -0700 Subject: [PATCH 2/2] clang-format --- llvm/lib/MC/MCExpr.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp index c3ccdb3e31464..45c73489f9960 100644 --- a/llvm/lib/MC/MCExpr.cpp +++ b/llvm/lib/MC/MCExpr.cpp @@ -361,7 +361,8 @@ static void attemptToFoldSymbolOffsetDifference(const MCAssembler *Asm, if (BBeforeRelax && AAfterRelax) return; } - if (F->getKind() == MCFragment::FT_Relaxable && Asm->hasFinalLayout() && F->isLinkerRelaxable()) + if (F->getKind() == MCFragment::FT_Relaxable && Asm->hasFinalLayout() && + F->isLinkerRelaxable()) // FIXME: More accurate calculation of AAfterRelax/BBeforeRelax? return; if (&*F == FA) {