Backport some upstream patches

From Fedora MR: https://src.fedoraproject.org/rpms/llvm/pull-request/620

Resolves: RHEL-210751
Related: RHEL-211002
This commit is contained in:
Nikita Popov 2026-07-20 10:35:45 +02:00
parent f16b24b7a9
commit d442823b06
8 changed files with 4713 additions and 1 deletions

View File

@ -0,0 +1,47 @@
From e710ff28456c1accbeb3a7e503163233bc615b16 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i@maskray.me>
Date: Wed, 11 Feb 2026 21:23:34 -0800
Subject: [PATCH] [ELF] Simplify AArch64::relocateAlloc. NFC
---
lld/ELF/Arch/AArch64.cpp | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index 55434ae2151c..3c0d4ca64555 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -931,9 +931,10 @@ static bool needsGotForMemtag(const Relocation &rel) {
void AArch64::relocateAlloc(InputSection &sec, uint8_t *buf) const {
uint64_t secAddr = sec.getOutputSection()->addr + sec.outSecOff;
- AArch64Relaxer relaxer(ctx, sec.relocs());
- for (size_t i = 0, size = sec.relocs().size(); i != size; ++i) {
- const Relocation &rel = sec.relocs()[i];
+ const ArrayRef<Relocation> relocs = sec.relocs();
+ AArch64Relaxer relaxer(ctx, relocs);
+ for (size_t i = 0, size = relocs.size(); i != size; ++i) {
+ const Relocation &rel = relocs[i];
if (rel.expr == R_NONE) // See finalizeAddressDependentContent()
continue;
uint8_t *loc = buf + rel.offset;
@@ -947,14 +948,14 @@ void AArch64::relocateAlloc(InputSection &sec, uint8_t *buf) const {
switch (rel.expr) {
case RE_AARCH64_GOT_PAGE_PC:
if (i + 1 < size &&
- relaxer.tryRelaxAdrpLdr(rel, sec.relocs()[i + 1], secAddr, buf)) {
+ relaxer.tryRelaxAdrpLdr(rel, relocs[i + 1], secAddr, buf)) {
++i;
continue;
}
break;
case RE_AARCH64_PAGE_PC:
if (i + 1 < size &&
- relaxer.tryRelaxAdrpAdd(rel, sec.relocs()[i + 1], secAddr, buf)) {
+ relaxer.tryRelaxAdrpAdd(rel, relocs[i + 1], secAddr, buf)) {
++i;
continue;
}
--
2.50.1

View File

@ -0,0 +1,416 @@
From 8d590969badd9f3fed18a99fffbd9afdf3a975c6 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov@redhat.com>
Date: Fri, 10 Jul 2026 09:09:08 +0200
Subject: [PATCH] [LLD][AArch64] Make adrp+ldr relaxation per-symbol
all-or-nothing (#208396)
We can't relax only some adrp+ldr pairs for a symbol, because there may
be a branch target between the adrp and ldr of this form:
adrp x1, :got:sym
.Lfoo:
ldr x1, [x1, :got_lo12:sym]
# ...
adrp x1, :got:sym
ldr x2, [x1, :got_lo12:sym]
b .Lfoo
Relaxing the first adrp+ldr here would be invalid. This was clarified in
the ARM ABI in:
https://github.com/ARM-software/abi-aa/commit/11fb4ef42898060189d6a34ee96966e696ecbd20.
The implementation already performed a pre-scan to check that the
relevant relocations occur in pairs. Change this scan to a) check all
the preconditions for the relaxation and b) make the decision per
symbol.
Fixes https://github.com/llvm/llvm-project/issues/138254.
---
bolt/test/AArch64/got-load-symbolization.s | 11 ++-
bolt/test/AArch64/lite-mode.s | 17 +++--
lld/ELF/Arch/AArch64.cpp | 83 +++++++++++++--------
lld/test/ELF/aarch64-adrp-ldr-got.s | 84 +++++++++++++++++++---
4 files changed, 149 insertions(+), 46 deletions(-)
diff --git a/bolt/test/AArch64/got-load-symbolization.s b/bolt/test/AArch64/got-load-symbolization.s
index b4d682688758..399859fd7bfd 100644
--- a/bolt/test/AArch64/got-load-symbolization.s
+++ b/bolt/test/AArch64/got-load-symbolization.s
@@ -38,9 +38,9 @@ _start:
# CHECK-NEXT: adrp x2, __BOLT_got_zero
# CHECK-NEXT: nop
# CHECK-NEXT: ldr x2, [x2, :lo12:__BOLT_got_zero{{.*}}]
- adrp x2, :got:near
+ adrp x2, :got:near2
nop
- ldr x2, [x2, :got_lo12:near]
+ ldr x2, [x2, :got_lo12:near2]
## Load data object with local visibility. Relaxable into adrp+add.
# CHECK-NEXT: adrp x3, "local_far_data/1"
@@ -58,6 +58,7 @@ _start:
.size _start, .-_start
.weak near
+.weak near2
.weak far
.weak far_data
@@ -77,6 +78,12 @@ near:
ret
.size near, .-near
+ .globl near2
+ .type near2, @function
+near2:
+ ret
+.size near2, .-near2
+
#--- far.s
.text
diff --git a/bolt/test/AArch64/lite-mode.s b/bolt/test/AArch64/lite-mode.s
index f2d06219f7a2..24c31772b847 100644
--- a/bolt/test/AArch64/lite-mode.s
+++ b/bolt/test/AArch64/lite-mode.s
@@ -24,12 +24,12 @@
# CHECK-COMPACT-NOT: <_start.org.0>
## Verify that the number of FDEs matches the number of functions in the output
-## binary. There are three original functions and two optimized.
+## binary. There are four original functions and three optimized.
## NOTE: at the moment we are emitting extra FDEs for patched functions, thus
## there is one more FDE for _start.
# RUN: llvm-readelf -u %t.bolt | grep -wc FDE \
# RUN: | FileCheck --check-prefix=CHECK-FDE %s
-# CHECK-FDE: 6
+# CHECK-FDE: 8
## In lite mode, optimized code will be separated from the original .text by
## over 128MB, making it impossible for call/bl instructions in cold functions
@@ -106,9 +106,9 @@ cold_function:
# CHECK-NEXT: add x4
## Check that non-relaxable GOT load is left intact.
- adrp x5, :got:far_func
+ adrp x5, :got:far_func2
nop
- ldr x5, [x5, #:got_lo12:far_func]
+ ldr x5, [x5, #:got_lo12:far_func2]
# CHECK-INPUT-NEXT: adrp x5
# CHECK-INPUT-NEXT: nop
# CHECK-INPUT-NEXT: ldr x5
@@ -155,3 +155,12 @@ far_func:
ret x30
.cfi_endproc
.size far_func, .-far_func
+
+ .globl far_func2
+ .type far_func2, %function
+far_func2:
+# FDATA: 0 [unknown] 0 1 far_func2 0 0 100
+ .cfi_startproc
+ ret x30
+ .cfi_endproc
+ .size far_func2, .-far_func2
diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index ed6d42fd4c05..11c3dca1a358 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -106,13 +106,17 @@ private:
struct AArch64Relaxer {
Ctx &ctx;
- bool safeToRelaxAdrpLdr = false;
+ SmallPtrSet<Symbol *, 32> unsafeToRelaxAdrpLdr;
- AArch64Relaxer(Ctx &ctx, ArrayRef<Relocation> relocs);
+ AArch64Relaxer(Ctx &ctx, ArrayRef<Relocation> relocs, uint64_t secAddr,
+ uint8_t *buf);
bool tryRelaxAdrpAdd(const Relocation &adrpRel, const Relocation &addRel,
uint64_t secAddr, uint8_t *buf) const;
bool tryRelaxAdrpLdr(const Relocation &adrpRel, const Relocation &ldrRel,
uint64_t secAddr, uint8_t *buf) const;
+ bool isLegalAdrpLdrRelaxationCandidate(const Relocation &adrpRel,
+ const Relocation &ldrRel,
+ uint64_t secAddr, uint8_t *buf) const;
};
} // namespace
@@ -896,26 +900,30 @@ void AArch64::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel,
llvm_unreachable("invalid relocation for TLS IE to LE relaxation");
}
-AArch64Relaxer::AArch64Relaxer(Ctx &ctx, ArrayRef<Relocation> relocs)
+AArch64Relaxer::AArch64Relaxer(Ctx &ctx, ArrayRef<Relocation> relocs,
+ uint64_t secAddr, uint8_t *buf)
: ctx(ctx) {
if (!ctx.arg.relax)
return;
- // Check if R_AARCH64_ADR_GOT_PAGE and R_AARCH64_LD64_GOT_LO12_NC
- // always appear in pairs.
+ // For a given symbol R_AARCH64_ADR_GOT_PAGE and R_AARCH64_LD64_GOT_LO12_NC
+ // relaxation is all-or-nothing. We can't relax only some of them, as there
+ // may be a jump destination between the two relocations.
size_t i = 0;
const size_t size = relocs.size();
for (; i != size; ++i) {
if (relocs[i].type == R_AARCH64_ADR_GOT_PAGE) {
- if (i + 1 < size && relocs[i + 1].type == R_AARCH64_LD64_GOT_LO12_NC) {
+ if (i + 1 < size && relocs[i + 1].type == R_AARCH64_LD64_GOT_LO12_NC &&
+ !unsafeToRelaxAdrpLdr.contains(relocs[i].sym) &&
+ isLegalAdrpLdrRelaxationCandidate(relocs[i], relocs[i + 1], secAddr,
+ buf)) {
++i;
continue;
}
- break;
+ unsafeToRelaxAdrpLdr.insert(relocs[i].sym);
} else if (relocs[i].type == R_AARCH64_LD64_GOT_LO12_NC) {
- break;
+ unsafeToRelaxAdrpLdr.insert(relocs[i].sym);
}
}
- safeToRelaxAdrpLdr = i == size;
}
bool AArch64Relaxer::tryRelaxAdrpAdd(const Relocation &adrpRel,
@@ -966,23 +974,9 @@ bool AArch64Relaxer::tryRelaxAdrpAdd(const Relocation &adrpRel,
return true;
}
-bool AArch64Relaxer::tryRelaxAdrpLdr(const Relocation &adrpRel,
- const Relocation &ldrRel, uint64_t secAddr,
- uint8_t *buf) const {
- if (!safeToRelaxAdrpLdr)
- return false;
-
- // When the definition of sym is not preemptible then we may
- // be able to relax
- // ADRP xn, :got: sym
- // LDR xn, [ xn :got_lo12: sym]
- // to
- // ADRP xn, sym
- // ADD xn, xn, :lo_12: sym
-
- if (adrpRel.type != R_AARCH64_ADR_GOT_PAGE ||
- ldrRel.type != R_AARCH64_LD64_GOT_LO12_NC)
- return false;
+bool AArch64Relaxer::isLegalAdrpLdrRelaxationCandidate(
+ const Relocation &adrpRel, const Relocation &ldrRel, uint64_t secAddr,
+ uint8_t *buf) const {
// Check if the relocations apply to consecutive instructions.
if (adrpRel.offset + 4 != ldrRel.offset)
return false;
@@ -1022,10 +1016,37 @@ bool AArch64Relaxer::tryRelaxAdrpLdr(const Relocation &adrpRel,
if (val != llvm::SignExtend64(val, 33))
return false;
+ return true;
+}
+
+bool AArch64Relaxer::tryRelaxAdrpLdr(const Relocation &adrpRel,
+ const Relocation &ldrRel, uint64_t secAddr,
+ uint8_t *buf) const {
+ // When the definition of sym is not preemptible then we may
+ // be able to relax
+ // ADRP xn, :got: sym
+ // LDR xn, [ xn :got_lo12: sym]
+ // to
+ // ADRP xn, sym
+ // ADD xn, xn, :lo_12: sym
+
+ if (!ctx.arg.relax || adrpRel.type != R_AARCH64_ADR_GOT_PAGE ||
+ ldrRel.type != R_AARCH64_LD64_GOT_LO12_NC)
+ return false;
+
+ Symbol *sym = adrpRel.sym;
+ if (unsafeToRelaxAdrpLdr.contains(sym))
+ return false;
+
+ assert(isLegalAdrpLdrRelaxationCandidate(adrpRel, ldrRel, secAddr, buf) &&
+ "Should have been marked as unsafe");
+
+ uint32_t adrpInstr = read32le(buf + adrpRel.offset);
+ uint32_t adrpDestReg = adrpInstr & 0x1f;
Relocation adrpSymRel = {RE_AARCH64_PAGE_PC, R_AARCH64_ADR_PREL_PG_HI21,
- adrpRel.offset, /*addend=*/0, &sym};
+ adrpRel.offset, /*addend=*/0, sym};
Relocation addRel = {R_ABS, R_AARCH64_ADD_ABS_LO12_NC, ldrRel.offset,
- /*addend=*/0, &sym};
+ /*addend=*/0, sym};
// adrp x_<dest_reg>
write32le(buf + adrpSymRel.offset, 0x90000000 | adrpDestReg);
@@ -1034,11 +1055,11 @@ bool AArch64Relaxer::tryRelaxAdrpLdr(const Relocation &adrpRel,
ctx.target->relocate(
buf + adrpSymRel.offset, adrpSymRel,
- SignExtend64(getAArch64Page(sym.getVA(ctx)) -
+ SignExtend64(getAArch64Page(sym->getVA(ctx)) -
getAArch64Page(secAddr + adrpSymRel.offset),
64));
ctx.target->relocate(buf + addRel.offset, addRel,
- SignExtend64(sym.getVA(ctx), 64));
+ SignExtend64(sym->getVA(ctx), 64));
tryRelaxAdrpAdd(adrpSymRel, addRel, secAddr, buf);
return true;
}
@@ -1052,7 +1073,7 @@ static bool needsGotForMemtag(const Relocation &rel) {
void AArch64::relocateAlloc(InputSection &sec, uint8_t *buf) const {
uint64_t secAddr = sec.getOutputSection()->addr + sec.outSecOff;
const ArrayRef<Relocation> relocs = sec.relocs();
- AArch64Relaxer relaxer(ctx, relocs);
+ AArch64Relaxer relaxer(ctx, relocs, secAddr, buf);
for (size_t i = 0, size = relocs.size(); i != size; ++i) {
const Relocation &rel = relocs[i];
if (rel.expr == R_NONE) // See finalizeAddressDependentContent()
diff --git a/lld/test/ELF/aarch64-adrp-ldr-got.s b/lld/test/ELF/aarch64-adrp-ldr-got.s
index 56a90aac3876..a8216da9f20c 100644
--- a/lld/test/ELF/aarch64-adrp-ldr-got.s
+++ b/lld/test/ELF/aarch64-adrp-ldr-got.s
@@ -4,6 +4,7 @@
# RUN: llvm-mc -filetype=obj -triple=aarch64 %t/a.s -o %t/a.o
# RUN: llvm-mc -filetype=obj -triple=aarch64 %t/unpaired.s -o %t/unpaired.o
# RUN: llvm-mc -filetype=obj -triple=aarch64 %t/lone-ldr.s -o %t/lone-ldr.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64 %t/all-or-nothing.s -o %t/all-or-nothing.o
# RUN: ld.lld %t/a.o -T %t/out-of-adr-range.t -o %t/a
# RUN: llvm-objdump --no-show-raw-insn -d %t/a | FileCheck %s
@@ -49,7 +50,8 @@
# RUN: llvm-objdump --no-show-raw-insn -d %t/out-of-range | \
# RUN: FileCheck --check-prefix=X1-NO-RELAX %s
-## Relocations do not appear in pairs, no relaxations should be applied.
+## Relocations do not appear in pairs, no relaxations should be applied for
+## that symbol. We can still relax other symbols.
# RUN: ld.lld %t/unpaired.o -o %t/unpaired
# RUN: llvm-objdump --no-show-raw-insn -d %t/unpaired | \
# RUN: FileCheck --check-prefix=UNPAIRED %s
@@ -58,6 +60,9 @@
# UNPAIRED-NEXT: b
# UNPAIRED-NEXT: adrp x0
# UNPAIRED: ldr x0
+## This is a different symbol.
+# UNPAIRED: nop
+# UNPAIRED: adr x1
## Relocations do not appear in pairs, no relaxations should be applied.
# RUN: ld.lld %t/lone-ldr.o -o %t/lone-ldr
@@ -66,6 +71,26 @@
# LONE-LDR: ldr x0
+## Make sure that relaxation is not applied if not all adrp+ldr pairs for
+## a given symbol can be relaxed. This is not legal, because there may be
+## a branch destination between the adrp and ldr instructions. We can still
+## perform the relaxation for other symbols, or the same symbol in a different
+## section.
+# RUN: ld.lld %t/all-or-nothing.o -o %t/all-or-nothing
+# RUN: llvm-objdump --no-show-raw-insn -d %t/all-or-nothing | \
+# RUN: FileCheck --check-prefix=ALL-OR-NOTHING %s
+
+# ALL-OR-NOTHING-LABEL: <_start>:
+# ALL-OR-NOTHING: adrp x1
+# ALL-OR-NOTHING: ldr x1
+# ALL-OR-NOTHING: adrp x1
+# ALL-OR-NOTHING: ldr x2
+# ALL-OR-NOTHING: nop
+# ALL-OR-NOTHING: adr x1
+# ALL-OR-NOTHING-LABEL: <foo>:
+# ALL-OR-NOTHING: nop
+# ALL-OR-NOTHING: adr x1
+
## This linker script ensures that .rodata and .text are sufficiently (>1M)
## far apart so that the adrp + ldr pair cannot be relaxed to adr + nop.
#--- out-of-adr-range.t
@@ -95,25 +120,40 @@ SECTIONS {
.hidden x
x:
.word 10
+.hidden y
+y:
+.word 10
+.hidden z
+z:
+.word 10
+.hidden u
+u:
+.word 10
+.hidden v
+v:
+.word 10
.text
.global _start
_start:
adrp x1, :got:x
ldr x1, [x1, #:got_lo12:x]
- adrp x2, :got:x+1
- ldr x2, [x2, #:got_lo12:x]
- adrp x3, :got:x
- ldr x3, [x3, #:got_lo12:x+8]
- adrp x4, :got:x
- ldr x5, [x4, #:got_lo12:x]
- adrp x6, :got:x
- ldr x6, [x0, #:got_lo12:x]
+ adrp x2, :got:y+1
+ ldr x2, [x2, #:got_lo12:y]
+ adrp x3, :got:z
+ ldr x3, [x3, #:got_lo12:z+8]
+ adrp x4, :got:u
+ ldr x5, [x4, #:got_lo12:u]
+ adrp x6, :got:v
+ ldr x6, [x0, #:got_lo12:v]
#--- unpaired.s
.text
.hidden x
x:
nop
+.hidden y
+y:
+ nop
.global _start
_start:
adrp x0, :got:x
@@ -121,6 +161,8 @@ _start:
adrp x0, :got:x
L:
ldr x0, [x0, #:got_lo12:x]
+ adrp x1, :got:y
+ ldr x1, [x1, #:got_lo12:y]
#--- lone-ldr.s
.text
@@ -130,3 +172,27 @@ x:
.global _start
_start:
ldr x0, [x0, #:got_lo12:x]
+
+#--- all-or-nothing.s
+.rodata
+.hidden x
+x:
+.word 10
+.hidden y
+y:
+.word 10
+.text
+.global _start
+_start:
+ adrp x1, :got:x
+ ldr x1, [x1, #:got_lo12:x]
+ adrp x1, :got:x
+ ldr x2, [x1, #:got_lo12:x]
+ adrp x1, :got:y
+ ldr x1, [x1, #:got_lo12:y]
+
+.section .text.foo
+.global foo
+foo:
+ adrp x1, :got:x
+ ldr x1, [x1, #:got_lo12:x]
--
2.50.1

View File

@ -0,0 +1,88 @@
From 7bb9626d5ab901e5c1a8e9acbbb1684c982401b4 Mon Sep 17 00:00:00 2001
From: Tulio Magno Quites Machado Filho <tuliom@redhat.com>
Date: Fri, 10 Jul 2026 15:45:02 -0300
Subject: [PATCH] [LLVM][Verifier] Fix buffer overflow when verifying
gc.statepoint (#208278)
When a negative base index is passed, the verification detects the
out-of-bounds value and start printing information that helps to
identify what caused the error. In order to print all the information,
it tries to dereference the Base pointer at
GCRelocateInst::getBasePtr(), causing the buffer overflow. Add a bounds
check to getBasePTR() and getDerivedPtr() in order to avoid this.
Improve the test in order to validate negative values passed as indexes.
They're based on the reproducer from issue #199191.
Fixes #199191
---
llvm/lib/IR/AsmWriter.cpp | 10 ++++++++--
llvm/lib/IR/IntrinsicInst.cpp | 19 ++++++++++++++++---
3 files changed, 40 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp
index e90630a8cae5..6752d6aa344d 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -4372,9 +4372,15 @@ void AssemblyWriter::printInstructionLine(const Instruction &I) {
/// intrinsic indicating base and derived pointer names.
void AssemblyWriter::printGCRelocateComment(const GCRelocateInst &Relocate) {
Out << " ; (";
- writeOperand(Relocate.getBasePtr(), false);
+ if (Value *BasePtr = Relocate.getBasePtr())
+ writeOperand(BasePtr, false);
+ else
+ Out << "invalid";
Out << ", ";
- writeOperand(Relocate.getDerivedPtr(), false);
+ if (Value *DerivedPtr = Relocate.getDerivedPtr())
+ writeOperand(DerivedPtr, false);
+ else
+ Out << "invalid";
Out << ")";
}
diff --git a/llvm/lib/IR/IntrinsicInst.cpp b/llvm/lib/IR/IntrinsicInst.cpp
index 3e9f3257956a..eb964d566f29 100644
--- a/llvm/lib/IR/IntrinsicInst.cpp
+++ b/llvm/lib/IR/IntrinsicInst.cpp
@@ -867,10 +867,16 @@ Value *GCRelocateInst::getBasePtr() const {
auto Statepoint = getStatepoint();
if (isa<UndefValue>(Statepoint))
return UndefValue::get(Statepoint->getType());
-
+ // Handle too few (bundle) arguments to avoid crashes when printing invalid
+ // IR, e.g. in the verifier.
auto *GCInst = cast<GCStatepointInst>(Statepoint);
- if (auto Opt = GCInst->getOperandBundle(LLVMContext::OB_gc_live))
+ if (auto Opt = GCInst->getOperandBundle(LLVMContext::OB_gc_live)) {
+ if (getBasePtrIndex() > Opt->Inputs.size())
+ return nullptr;
return *(Opt->Inputs.begin() + getBasePtrIndex());
+ }
+ if (getBasePtrIndex() > GCInst->arg_size())
+ return nullptr;
return *(GCInst->arg_begin() + getBasePtrIndex());
}
@@ -879,9 +885,16 @@ Value *GCRelocateInst::getDerivedPtr() const {
if (isa<UndefValue>(Statepoint))
return UndefValue::get(Statepoint->getType());
+ // Handle too few (bundle) arguments to avoid crashes when printing invalid
+ // IR, e.g. in the verifier.
auto *GCInst = cast<GCStatepointInst>(Statepoint);
- if (auto Opt = GCInst->getOperandBundle(LLVMContext::OB_gc_live))
+ if (auto Opt = GCInst->getOperandBundle(LLVMContext::OB_gc_live)) {
+ if (getDerivedPtrIndex() > Opt->Inputs.size())
+ return nullptr;
return *(Opt->Inputs.begin() + getDerivedPtrIndex());
+ }
+ if (getDerivedPtrIndex() > GCInst->arg_size())
+ return nullptr;
return *(GCInst->arg_begin() + getDerivedPtrIndex());
}
--
2.50.1

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,81 @@
From a04c1eced55f2f3ea8dbd3d17db0b6df271c0809 Mon Sep 17 00:00:00 2001
From: Stefan Weigl-Bosker <stefan@s00.xyz>
Date: Mon, 18 May 2026 10:47:14 -0400
Subject: [PATCH] [X86] Fix EVEX compression for VPMOV*2M + KMOV with tied mask
use (#198220)
When scanning uses of the mask produced by `VPMOV*2M`, we previously bailed out as soon as we encountered a write. For tied read/write mask instructions such as `KSHIFTR*`, which both read and write the same mask register, the pass could miss the use, fold the earlier `KMOV`, and erase the `VPMOV*2M` def even though the mask was still live.
Disclaimer: LLM came up with the MIR tests and explained this pass to me.
Fixes #198197
(cherry picked from commit f0fc9d0abf7024ceb5cb827b16f02c10e54fe0fd)
---
llvm/lib/Target/X86/X86CompressEVEX.cpp | 12 ++++++------
llvm/test/CodeGen/X86/evex-to-vex-compress.mir | 12 ++++++++++++
2 files changed, 18 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Target/X86/X86CompressEVEX.cpp b/llvm/lib/Target/X86/X86CompressEVEX.cpp
index c1faf7d1aa1e..b8fbcd2582de 100644
--- a/llvm/lib/Target/X86/X86CompressEVEX.cpp
+++ b/llvm/lib/Target/X86/X86CompressEVEX.cpp
@@ -271,12 +271,6 @@ static bool tryCompressVPMOVPattern(MachineInstr &MI, MachineBasicBlock &MBB,
for (MachineInstr &CurMI : llvm::make_range(
std::next(MachineBasicBlock::iterator(MI)), MBB.end())) {
- if (CurMI.modifiesRegister(MaskReg, TRI)) {
- if (!KMovMI)
- return false; // Mask clobbered before use
- break;
- }
-
if (CurMI.readsRegister(MaskReg, TRI)) {
if (KMovMI)
return false; // Fail: Mask has MULTIPLE uses
@@ -295,6 +289,12 @@ static bool tryCompressVPMOVPattern(MachineInstr &MI, MachineBasicBlock &MBB,
}
}
+ if (CurMI.modifiesRegister(MaskReg, TRI)) {
+ if (!KMovMI)
+ return false; // Mask clobbered before use
+ break;
+ }
+
if (!KMovMI && CurMI.modifiesRegister(SrcVecReg, TRI)) {
return false; // SrcVecReg modified before it could be used by MOVMSK
}
diff --git a/llvm/test/CodeGen/X86/evex-to-vex-compress.mir b/llvm/test/CodeGen/X86/evex-to-vex-compress.mir
index b33a1d571c81..575f0c7d6a4f 100644
--- a/llvm/test/CodeGen/X86/evex-to-vex-compress.mir
+++ b/llvm/test/CodeGen/X86/evex-to-vex-compress.mir
@@ -914,6 +914,12 @@ body: |
$k0 = VPMOVD2MZ256kr $ymm0
$eax = KMOVBrk $k0
$ebx = KMOVBrk $k0
+ ; CHECK: $k0 = VPMOVD2MZ256kr $ymm0
+ ; CHECK: $eax = KMOVBrk $k0
+ ; CHECK: $k0 = KSHIFTRBki $k0, 2
+ $k0 = VPMOVD2MZ256kr $ymm0
+ $eax = KMOVBrk $k0
+ $k0 = KSHIFTRBki $k0, 2
; CHECK: $k0 = VPMOVB2MZ256kr $ymm0
; CHECK: $eax = KMOVWrk $k0
$k0 = VPMOVB2MZ256kr $ymm0
@@ -1803,6 +1809,12 @@ body: |
$k0 = VPMOVD2MZ128kr $xmm0
$eax = KMOVBrk $k0
$ebx = KMOVBrk $k0
+ ; CHECK: $k0 = VPMOVD2MZ128kr $xmm0
+ ; CHECK: $eax = KMOVBrk $k0
+ ; CHECK: $k0 = KSHIFTRBki $k0, 2
+ $k0 = VPMOVD2MZ128kr $xmm0
+ $eax = KMOVBrk $k0
+ $k0 = KSHIFTRBki $k0, 2
; CHECK: $k0 = VPMOVB2MZ128kr $xmm0
; CHECK: $eax = KMOVBrk $k0
$k0 = VPMOVB2MZ128kr $xmm0
--
2.50.1

View File

@ -0,0 +1,87 @@
From 2119e359b1f968da94ff27a4078d569e18903aef Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov@redhat.com>
Date: Mon, 13 Jul 2026 09:08:54 +0200
Subject: [PATCH] [lld][ELF] Concatenate .gnu.build.attributes.* sections
(#208737)
ld.bfd/ld.gold have been concatenating the GNU build attribute sections
since 2018:
https://gitlab.com/gnutools/binutils-gdb/-/commit/7d8a31665739412395f6dd370d2279acd322e78e
Do the same in LLD. These do not have a dedicated section type or flags,
so this is handled by the name-based logic. (Peculiarly, there used to
be SHF_GNU_BUILD_NOTE, but it was removed again.)
Not concatenating these results in a huge number of sections, which
breaks tools like `file`.
---
lld/ELF/LinkerScript.cpp | 2 +-
lld/test/ELF/gnu-build-attributes.s | 42 +++++++++++++++++++++++++++++
2 files changed, 43 insertions(+), 1 deletion(-)
create mode 100644 lld/test/ELF/gnu-build-attributes.s
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index 1c0a49a73962..64fb717e17d9 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -119,7 +119,7 @@ StringRef LinkerScript::getOutputSectionName(const InputSectionBase *s) const {
".init_array", ".fini_array", ".tbss",
".tdata", ".ARM.exidx", ".ARM.extab",
".ctors", ".dtors", ".sbss",
- ".sdata", ".srodata"})
+ ".sdata", ".srodata", ".gnu.build.attributes"})
if (isSectionPrefix(v, s->name))
return v;
diff --git a/lld/test/ELF/gnu-build-attributes.s b/lld/test/ELF/gnu-build-attributes.s
new file mode 100644
index 000000000000..79ad6c40ae50
--- /dev/null
+++ b/lld/test/ELF/gnu-build-attributes.s
@@ -0,0 +1,42 @@
+# REQUIRES: x86
+
+## Check that .gnu.build.attributes.* sections are concatenated into a single
+## .gnu.build.attributes section.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-linux-gnu %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-readobj -n %t | FileCheck %s
+
+# CHECK: NoteSections [
+# CHECK-NEXT: NoteSection {
+# CHECK-NEXT: Name: .gnu.build.attributes
+# CHECK-NEXT: Offset: 0x120
+# CHECK-NEXT: Size: 0x28
+# CHECK-NEXT: Notes [
+# CHECK-NEXT: {
+# CHECK-NEXT: Owner: GA${{.*}}:a1
+# CHECK-NEXT: Data size: 0x0
+# CHECK-NEXT: Type: OPEN
+# CHECK-NEXT: }
+# CHECK-NEXT: {
+# CHECK-NEXT: Owner: GA${{.*}}:b1
+# CHECK-NEXT: Data size: 0x0
+# CHECK-NEXT: Type: OPEN
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+.section ".gnu.build.attributes.text.foo", "", @note
+.balign 4
+.long 8
+.long 0
+.long 0x100
+.asciz "GA$\x03:a1"
+
+.section ".gnu.build.attributes.text.bar", "", @note
+.balign 4
+.long 8
+.long 0
+.long 0x100
+.asciz "GA$\x03:b1"
--
2.50.1

View File

@ -1,3 +1,6 @@
* Fri Jul 17 2026 Nikita Popov <npopov@redhat.com> - 22.1.8-2
- Backport some patches (RHEL-210751)
* Thu Jun 25 2026 Nikita Popov <npopov@redhat.com> - 22.1.8-1
- Update to LLVM 22.1.8

View File

@ -443,7 +443,7 @@ end
Name: %{pkg_name_llvm}
Version: %{maj_ver}.%{min_ver}.%{patch_ver}%{?rc_ver:~%{rc_ver}}%{?llvm_snapshot_version_suffix:~%{llvm_snapshot_version_suffix}}
%if 0%{?rhel} == 8
Release: 1%{?dist}
Release: 2%{?dist}
%else
Release: 1%{?dist}
%endif
@ -530,9 +530,22 @@ Patch2209: https://github.com/llvm/llvm-project/commit/0b6a1ef429.patch
# s390x fix for unaligned memory access performance regressions.
Patch2210: 0001-SystemZ-Avoid-unaligned-VL-VST-s-with-memcpy-memmove.patch
# Fix a heap buffer overflow.
# https://bugzilla.redhat.com/show_bug.cgi?id=2496390
Patch2211: 0001-LLVM-Verifier-Fix-buffer-overflow-when-verifying-gc..patch
# Fix miscompilation.
# https://bugzilla.redhat.com/show_bug.cgi?id=2499684
Patch2212: 0001-SDAG-Freeze-condition-in-select-of-load-fold-208683.patch
# Fix a vector miscompilation
Patch2213: 0001-X86-Fix-EVEX-compression-for-VPMOV-2M-KMOV-with-tied.patch
#region LLD patches
Patch106: 0001-19-Always-build-shared-libs-for-LLD.patch
Patch2103: 0001-lld-Adjust-compressed-debug-level-test-for-s390x-wit.patch
Patch2214: 0001-ELF-Simplify-AArch64-relocateAlloc.-NFC.patch
Patch2215: 0001-LLD-AArch64-Make-adrp-ldr-relaxation-per-symbol-all-.patch
Patch2216: 0001-lld-ELF-Concatenate-.gnu.build.attributes.-sections-.patch
#endregion LLD patches
#region polly patches