-
Notifications
You must be signed in to change notification settings - Fork 14.6k
[MC] Relaxable Fragments Can be Linker Relaxable #150096
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
base: main
Are you sure you want to change the base?
Conversation
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: llvm#150071
@llvm/pr-subscribers-mc @llvm/pr-subscribers-backend-risc-v Author: Sam Elliott (lenary) ChangesWhen relaxing a relaxable fragment, the new fixup may end up being linker relaxable (when the one before relaxation was not). This change ensures that:
Fixes: #150071 Full diff: https://github.com/llvm/llvm-project/pull/150096.diff 5 Files Affected:
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 <bar>
+# 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 <bar+0x6>
+# CHECK-NEXT: R_RISCV_BRANCH bar
+ ret
+# CHECK-NEXT: ret
|
for (const auto &Fixup : Fixups) { | ||
if (!Fixup.isLinkerRelaxable()) | ||
continue; | ||
F.setLinkerRelaxable(); | ||
F.getParent()->setLinkerRelaxable(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not cope with the other direction correctly, but I'm not sure we can.
The other direction is when a linker relaxable fixup is replaced by a non-linker-relaxable fixup in relaxation, which might need the fragment to be marked as not linker relaxable. I'm not sure this will ever happen though.
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM but please wait for someone else to review before merging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not look right. The LinkerRelaxable property should be set exclusively by MCObjectStreamer and remain unchanged. Modifying it during relaxation is inappropriate. Request changes to prevent accidental land. I'll think about this.
For example, MCObjectStreamer::emitDwarfAdvanceLineAddr
absoluteSymbolDiff relies on LinkerRelaxable
being correct at streaming time.
@MaskRay I wasn't going to land this until you had approved it, accidentally or not.
So we can never There's a lot more detail in the issue, hopefully it clarifies what this is trying to fix. This is causing real bugs for us with the LLVM 21 branch. |
This appears incorrect. The LinkerRelaxable property should be set exclusively by MCObjectStreamer and remain unchanged. Modifying it during relaxation is inappropriate. Please revise to prevent unintended changes. Thank you! I know you wouldn't😊 I've just gotten into the habit of clicking "Request Changes" in these situations... In the past, changes to areas I care about, like lld and MC, were sometimes approved and landed before their implications were fully thought through, requiring me to revise them later. At streaming/fragment generation time, we want to support code like
Assembler relaxing them from 32-bit to 48-bit and allowing linker relaxation? Aside: It seems the base RISC-V ISA has significant issues. Sigh... After assembler layout, it might be safe to clear the |
No. Today, in We do hit this case because in Here's why I don't fully understand your analysis of I used I don't think we can conservatively mark the fixups as linker relaxable when streaming, and then clear the bit later, but I'm not 100% sure. I thought we didn't have an accurate MCSubtargetInfo, but it looks like we do have that for the fragment. |
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:
Fixes: #150071