[llvm] [PPC] Don't emit overflow error on branches accross different sections. (PR #206812)
Sean Fertile via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 14 11:53:12 PDT 2026
https://github.com/mandlebug updated https://github.com/llvm/llvm-project/pull/206812
>From adee7aead9b5ef2606dfa96a47fc11c6bacd7481 Mon Sep 17 00:00:00 2001
From: Sean Fertile <sd.fertile at gmail.com>
Date: Wed, 24 Jun 2026 21:55:52 -0400
Subject: [PATCH 1/2] [PPC] Don't emit overflow error on branches accross
different sections.
If a branch is to a symbol in a different sections we have to give the
linker a chance to fixup the overflow. On AIX in particualr we have to
emit the masked off overflowed value into the bits to be relocated as
the linker uses them in its final relocation calculation.
---
.../PowerPC/MCTargetDesc/PPCAsmBackend.cpp | 23 +++++++++++++++++--
.../CodeGen/PowerPC/call-overflow-error.ll | 22 ++++++++++++++++++
2 files changed, 43 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/CodeGen/PowerPC/call-overflow-error.ll
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp
index 72a5e60a01d87..0b561926ba498 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp
@@ -26,7 +26,8 @@
using namespace llvm;
static uint64_t adjustFixupValue(MCContext &Ctx, const MCFixup &Fixup,
- unsigned Kind, uint64_t Value) {
+ unsigned Kind, uint64_t Value,
+ const MCFragment &F, const MCValue &Target) {
auto checkBrFixup = [&](unsigned Bits) {
int64_t SVal = int64_t(Value);
if ((Value & 3) != 0) {
@@ -37,6 +38,24 @@ static uint64_t adjustFixupValue(MCContext &Ctx, const MCFixup &Fixup,
// Low two bits are not encoded.
if (!isIntN(Bits + 2, Value)) {
+ // Do not emit an error when the target of the branch is in a
+ // different section then the branch instruction. The linker may insert
+ // a trampoline or rearrange sections to avoid the overflow.
+ const MCSection *FragSection = F.getParent();
+ const MCSymbol *TargetSym = Target.getAddSym();
+
+ if (TargetSym) {
+ // Branch to an externally defined symbol.
+ if (!TargetSym->isDefined()) {
+ return;
+ }
+
+ const MCSection *TargetSection = TargetSym->getFragment()->getParent();
+ // Branch across sections.
+ if (TargetSection != FragSection)
+ return;
+ }
+
Ctx.reportError(Fixup.getLoc(), "branch target out of range (" +
Twine(SVal) + " not between " +
Twine(minIntN(Bits) * 4) + " and " +
@@ -231,7 +250,7 @@ void PPCAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,
MCFixupKind Kind = Fixup.getKind();
if (mc::isRelocation(Kind))
return;
- Value = adjustFixupValue(getContext(), Fixup, Kind, Value);
+ Value = adjustFixupValue(getContext(), Fixup, Kind, Value, F, TargetVal);
if (!Value)
return; // Doesn't change encoding.
diff --git a/llvm/test/CodeGen/PowerPC/call-overflow-error.ll b/llvm/test/CodeGen/PowerPC/call-overflow-error.ll
new file mode 100644
index 0000000000000..3619b8b2dc4af
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/call-overflow-error.ll
@@ -0,0 +1,22 @@
+; RUN: not llc -verify-machineinstrs -mcpu=pwr7 -mtriple powerpc-ibm-aix \
+; RUN: 2>&1 -filetype=obj < %s | FileCheck %s --check-prefix=ERROR
+
+; RUN: llc -verify-machineinstrs -mcpu=pwr7 -mtriple powerpc-ibm-aix \
+; RUN: --function-sections -filetype=obj -o %t.o < %s
+; RUN: llvm-objdump -Dr %t.o | FileCheck %s
+
+define signext i32 @bar() {
+entry:
+ ret i32 42
+}
+
+define signext i32 @foo() {
+entry:
+ call void asm sideeffect ".space 0x2000100", ""()
+ %call = call signext i32 @bar()
+ ret i32 %call
+}
+
+; ERROR: error: branch target out of range (-33554732 not between -33554432 and 33554428)
+; CHECK: 200012c: 49 ff fe d5 bl 0x4000000 <.bar+0x3ffffe0>
+; CHECK: 0200012c: R_RBR .bar
>From ddad99689c45675598675859032cfee2bed08bd6 Mon Sep 17 00:00:00 2001
From: Sean Fertile <sd.fertile at gmail.com>
Date: Tue, 14 Jul 2026 13:44:34 -0400
Subject: [PATCH 2/2] Normalize overflowed call offset in XCOFF object writer.
---
llvm/lib/MC/XCOFFObjectWriter.cpp | 39 +++++++++++++++++++
.../PowerPC/MCTargetDesc/PPCAsmBackend.cpp | 23 +----------
.../CodeGen/PowerPC/call-overflow-error.ll | 16 ++++++--
3 files changed, 54 insertions(+), 24 deletions(-)
diff --git a/llvm/lib/MC/XCOFFObjectWriter.cpp b/llvm/lib/MC/XCOFFObjectWriter.cpp
index d9f47d6f4ba25..ad7c3f5365cc1 100644
--- a/llvm/lib/MC/XCOFFObjectWriter.cpp
+++ b/llvm/lib/MC/XCOFFObjectWriter.cpp
@@ -553,6 +553,37 @@ static MCSectionXCOFF *getContainingCsect(const MCSymbolXCOFF *XSym) {
return XSym->getRepresentedCsect();
}
+// Checks that the branhc target symbol has a different section then the one
+// containing the fragment F.
+static bool haveDifferentSections(const MCFragment &F, MCValue Target) {
+ const MCSymbol *TargetSym = Target.getAddSym();
+ if (!TargetSym)
+ return false;
+
+ // Branch to an externally defined symbol.
+ if (!TargetSym->isDefined())
+ return true;
+
+ // Branch across sections.
+ const MCSection *FragSection = F.getParent();
+ const MCSection *TargetSection = TargetSym->getFragment()->getParent();
+ return TargetSection != FragSection;
+}
+
+static bool CallOverflows(MCFixupKindInfo Info, uint64_t FixedValue) {
+ if (Info.TargetSize != 24)
+ report_fatal_error("Unexepected call fixup kind for XCOFF");
+
+ return !isIntN(26, FixedValue);
+}
+
+static uint64_t NormalizeCallOffset(MCFixupKindInfo Info, uint64_t Offset) {
+ if (Info.TargetSize != 24)
+ report_fatal_error("Unexepected call fixup kind for XCOFF");
+
+ return llvm::SignExtend64<26>(Offset & 0x3ffffff);
+}
+
void XCOFFWriter::executePostLayoutBinding() {
for (const auto &S : *Asm) {
auto *MCSec = static_cast<const MCSectionXCOFF *>(&S);
@@ -760,6 +791,14 @@ void XCOFFWriter::recordRelocation(const MCFragment &F, const MCFixup &Fixup,
// and BR instr address plus any constant value.
FixedValue = getVirtualAddress(SymA, SymASec) - BRInstrAddress +
Target.getConstant();
+
+ // If the offset overflows but the call crosses sections then we need to
+ // normalize the offset to be a valid value for encoding. Since the call
+ // crosses a CSECT boundary the linker may fix the overflow by using a
+ // trampoline, or rearranging the sections in the output file.
+ MCFixupKindInfo Info = Asm->getBackend().getFixupKindInfo(Fixup.getKind());
+ if (CallOverflows(Info, FixedValue) && haveDifferentSections(F, Target))
+ FixedValue = NormalizeCallOffset(Info, FixedValue);
} else if (Type == XCOFF::RelocationType::R_REF) {
// The FixedValue and FixupOffsetInCsect should always be 0 since it
// specifies a nonrelocating reference.
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp
index 0b561926ba498..72a5e60a01d87 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp
@@ -26,8 +26,7 @@
using namespace llvm;
static uint64_t adjustFixupValue(MCContext &Ctx, const MCFixup &Fixup,
- unsigned Kind, uint64_t Value,
- const MCFragment &F, const MCValue &Target) {
+ unsigned Kind, uint64_t Value) {
auto checkBrFixup = [&](unsigned Bits) {
int64_t SVal = int64_t(Value);
if ((Value & 3) != 0) {
@@ -38,24 +37,6 @@ static uint64_t adjustFixupValue(MCContext &Ctx, const MCFixup &Fixup,
// Low two bits are not encoded.
if (!isIntN(Bits + 2, Value)) {
- // Do not emit an error when the target of the branch is in a
- // different section then the branch instruction. The linker may insert
- // a trampoline or rearrange sections to avoid the overflow.
- const MCSection *FragSection = F.getParent();
- const MCSymbol *TargetSym = Target.getAddSym();
-
- if (TargetSym) {
- // Branch to an externally defined symbol.
- if (!TargetSym->isDefined()) {
- return;
- }
-
- const MCSection *TargetSection = TargetSym->getFragment()->getParent();
- // Branch across sections.
- if (TargetSection != FragSection)
- return;
- }
-
Ctx.reportError(Fixup.getLoc(), "branch target out of range (" +
Twine(SVal) + " not between " +
Twine(minIntN(Bits) * 4) + " and " +
@@ -250,7 +231,7 @@ void PPCAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,
MCFixupKind Kind = Fixup.getKind();
if (mc::isRelocation(Kind))
return;
- Value = adjustFixupValue(getContext(), Fixup, Kind, Value, F, TargetVal);
+ Value = adjustFixupValue(getContext(), Fixup, Kind, Value);
if (!Value)
return; // Doesn't change encoding.
diff --git a/llvm/test/CodeGen/PowerPC/call-overflow-error.ll b/llvm/test/CodeGen/PowerPC/call-overflow-error.ll
index 3619b8b2dc4af..382c66038aba4 100644
--- a/llvm/test/CodeGen/PowerPC/call-overflow-error.ll
+++ b/llvm/test/CodeGen/PowerPC/call-overflow-error.ll
@@ -5,6 +5,13 @@
; RUN: --function-sections -filetype=obj -o %t.o < %s
; RUN: llvm-objdump -Dr %t.o | FileCheck %s
+declare void @baz()
+
+define i32 @padding() {
+ entry:
+ ret i32 55
+}
+
define signext i32 @bar() {
entry:
ret i32 42
@@ -14,9 +21,12 @@ define signext i32 @foo() {
entry:
call void asm sideeffect ".space 0x2000100", ""()
%call = call signext i32 @bar()
+ call void @baz()
ret i32 %call
}
-; ERROR: error: branch target out of range (-33554732 not between -33554432 and 33554428)
-; CHECK: 200012c: 49 ff fe d5 bl 0x4000000 <.bar+0x3ffffe0>
-; CHECK: 0200012c: R_RBR .bar
+; ERROR: error: branch target out of range (-33554736 not between -33554432 and 33554428)
+; CHECK: 2000170: 49 ff fe d1 bl 0x4000040
+; CHECK: 02000170: R_RBR .bar
+; CHECK: 200017c: 49 ff fe 85 bl 0x4000000
+; CHECK: 0200017c: R_RBR .baz
More information about the llvm-commits
mailing list