[llvm] [CodeGen] Assert on invalid patchable-function-entry/prefix attributes (PR #194726)
JP Hafer via llvm-commits
llvm-commits at lists.llvm.org
Tue Apr 28 14:54:41 PDT 2026
https://github.com/jph-13 updated https://github.com/llvm/llvm-project/pull/194726
>From 53a6e0ae158e08d4c6204e2b131af141eb05d5d1 Mon Sep 17 00:00:00 2001
From: Jason Hafer <jhafer at mathworks.com>
Date: Tue, 28 Apr 2026 16:58:14 -0400
Subject: [PATCH] [CodeGen] Use getFnAttributeAsParsedInteger for
patchable-function-entry/prefix
Replace hand-rolled getAsInteger + assert patterns across all backends
with the existing Function::getFnAttributeAsParsedInteger() helper.
This eliminates duplicated parsing logic in 12 files and produces a
proper error diagnostic instead of an assertion failure on malformed
attributes (though the verifier rejects them before we get here).
---
llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 23 +++++++------------
llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 9 +++-----
llvm/lib/Target/ARM/ARMAsmPrinter.cpp | 8 ++-----
.../Target/LoongArch/LoongArchAsmPrinter.cpp | 6 +----
.../Target/LoongArch/LoongArchInstrInfo.cpp | 7 ++----
llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 10 ++------
llvm/lib/Target/PowerPC/PPCInstrInfo.cpp | 5 +---
llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp | 17 ++++----------
llvm/lib/Target/RISCV/RISCVInstrInfo.cpp | 8 ++-----
llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 6 +----
llvm/lib/Target/X86/X86AsmPrinter.cpp | 7 ++----
llvm/lib/Target/X86/X86MCInstLower.cpp | 13 +++--------
12 files changed, 32 insertions(+), 87 deletions(-)
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 8c75ca7c17f7e..36ed46c6904e0 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1083,14 +1083,10 @@ void AsmPrinter::emitFunctionHeader() {
// Emit M NOPs for -fpatchable-function-entry=N,M where M>0. We arbitrarily
// place prefix data before NOPs.
- unsigned PatchableFunctionPrefix = 0;
- unsigned PatchableFunctionEntry = 0;
- (void)F.getFnAttribute("patchable-function-prefix")
- .getValueAsString()
- .getAsInteger(10, PatchableFunctionPrefix);
- (void)F.getFnAttribute("patchable-function-entry")
- .getValueAsString()
- .getAsInteger(10, PatchableFunctionEntry);
+ unsigned PatchableFunctionPrefix =
+ F.getFnAttributeAsParsedInteger("patchable-function-prefix");
+ unsigned PatchableFunctionEntry =
+ F.getFnAttributeAsParsedInteger("patchable-function-entry");
if (PatchableFunctionPrefix) {
CurrentPatchableFunctionEntrySym =
OutContext.createLinkerPrivateTempSymbol();
@@ -5101,13 +5097,10 @@ void AsmPrinter::recordSled(MCSymbol *Sled, const MachineInstr &MI,
void AsmPrinter::emitPatchableFunctionEntries() {
const Function &F = MF->getFunction();
- unsigned PatchableFunctionPrefix = 0, PatchableFunctionEntry = 0;
- (void)F.getFnAttribute("patchable-function-prefix")
- .getValueAsString()
- .getAsInteger(10, PatchableFunctionPrefix);
- (void)F.getFnAttribute("patchable-function-entry")
- .getValueAsString()
- .getAsInteger(10, PatchableFunctionEntry);
+ unsigned PatchableFunctionPrefix =
+ F.getFnAttributeAsParsedInteger("patchable-function-prefix");
+ unsigned PatchableFunctionEntry =
+ F.getFnAttributeAsParsedInteger("patchable-function-entry");
if (!PatchableFunctionPrefix && !PatchableFunctionEntry)
return;
const unsigned PointerSize = getPointerSize();
diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index 97edd896c5992..1bdd54c8db05a 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -687,12 +687,9 @@ void AArch64AsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {
// Adjust the offset for patchable-function-prefix. This assumes that
// patchable-function-prefix is the same for all functions.
- int64_t PrefixNops = 0;
- (void)MI.getMF()
- ->getFunction()
- .getFnAttribute("patchable-function-prefix")
- .getValueAsString()
- .getAsInteger(10, PrefixNops);
+ int64_t PrefixNops =
+ MI.getMF()->getFunction().getFnAttributeAsParsedInteger(
+ "patchable-function-prefix");
// Load the target function type hash.
EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDURWi)
diff --git a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
index fb2bbb5680156..1df5bbd6a0756 100644
--- a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
+++ b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
@@ -1915,12 +1915,8 @@ void ARMAsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {
const MachineInstr &Call = *std::next(MI.getIterator());
// Adjust the offset for patchable-function-prefix.
- int64_t PrefixNops = 0;
- MI.getMF()
- ->getFunction()
- .getFnAttribute("patchable-function-prefix")
- .getValueAsString()
- .getAsInteger(10, PrefixNops);
+ int64_t PrefixNops = MI.getMF()->getFunction().getFnAttributeAsParsedInteger(
+ "patchable-function-prefix");
// Emit the appropriate instruction sequence based on the opcode variant.
switch (MI.getOpcode()) {
diff --git a/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp b/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp
index 4b5cba716c638..da267cbc233eb 100644
--- a/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp
@@ -215,11 +215,7 @@ void LoongArchAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(
const MachineInstr &MI) {
const Function &F = MF->getFunction();
if (F.hasFnAttribute("patchable-function-entry")) {
- unsigned Num;
- if (F.getFnAttribute("patchable-function-entry")
- .getValueAsString()
- .getAsInteger(10, Num))
- return;
+ unsigned Num = F.getFnAttributeAsParsedInteger("patchable-function-entry");
emitNops(Num);
return;
}
diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
index 631565b963b79..2d7609f3ef1d5 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
@@ -267,11 +267,8 @@ unsigned LoongArchInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
const MachineFunction *MF = MI.getParent()->getParent();
const Function &F = MF->getFunction();
if (F.hasFnAttribute("patchable-function-entry")) {
- unsigned Num;
- if (F.getFnAttribute("patchable-function-entry")
- .getValueAsString()
- .getAsInteger(10, Num))
- return 0;
+ unsigned Num =
+ F.getFnAttributeAsParsedInteger("patchable-function-entry");
return Num * 4;
}
[[fallthrough]];
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 49c54fbae1bf0..5a6e9b48c07ba 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -952,10 +952,7 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
assert(!Subtarget->isAIXABI() &&
"AIX does not support patchable function entry!");
const Function &F = MF->getFunction();
- unsigned Num = 0;
- (void)F.getFnAttribute("patchable-function-entry")
- .getValueAsString()
- .getAsInteger(10, Num);
+ unsigned Num = F.getFnAttributeAsParsedInteger("patchable-function-entry");
if (!Num)
return;
emitNops(Num);
@@ -1817,10 +1814,7 @@ void PPCLinuxAsmPrinter::emitInstruction(const MachineInstr *MI) {
// of instructions change.
// XRAY is only supported on PPC Linux little endian.
const Function &F = MF->getFunction();
- unsigned Num = 0;
- (void)F.getFnAttribute("patchable-function-entry")
- .getValueAsString()
- .getAsInteger(10, Num);
+ unsigned Num = F.getFnAttributeAsParsedInteger("patchable-function-entry");
if (!MAI->isLittleEndian() || Num)
break;
diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
index f854dca003964..3d3e734443b46 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
+++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
@@ -3023,10 +3023,7 @@ unsigned PPCInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
case TargetOpcode::PATCHABLE_FUNCTION_ENTER: {
const MachineFunction *MF = MI.getParent()->getParent();
const Function &F = MF->getFunction();
- unsigned Num = 0;
- (void)F.getFnAttribute("patchable-function-entry")
- .getValueAsString()
- .getAsInteger(10, Num);
+ unsigned Num = F.getFnAttributeAsParsedInteger("patchable-function-entry");
if (Num || MF->getTarget().getTargetTriple().isOSAIX() ||
!MF->getTarget().getTargetTriple().isLittleEndian())
return Num * 4;
diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
index d71fd640be7bc..0aa51d9905321 100644
--- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
+++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
@@ -338,12 +338,8 @@ void RISCVAsmPrinter::emitInstruction(const MachineInstr *MI) {
case TargetOpcode::PATCHABLE_FUNCTION_ENTER: {
const Function &F = MI->getParent()->getParent()->getFunction();
if (F.hasFnAttribute("patchable-function-entry")) {
- unsigned Num;
- [[maybe_unused]] bool Result =
- F.getFnAttribute("patchable-function-entry")
- .getValueAsString()
- .getAsInteger(10, Num);
- assert(!Result && "Enforced by the verifier");
+ unsigned Num =
+ F.getFnAttributeAsParsedInteger("patchable-function-entry");
emitNops(Num);
return;
}
@@ -681,12 +677,9 @@ void RISCVAsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {
// Adjust the offset for patchable-function-prefix. This assumes that
// patchable-function-prefix is the same for all functions.
int NopSize = STI->hasStdExtZca() ? 2 : 4;
- int64_t PrefixNops = 0;
- (void)MI.getMF()
- ->getFunction()
- .getFnAttribute("patchable-function-prefix")
- .getValueAsString()
- .getAsInteger(10, PrefixNops);
+ int64_t PrefixNops =
+ MI.getMF()->getFunction().getFnAttributeAsParsedInteger(
+ "patchable-function-prefix");
// Load the target function type hash.
EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::LW)
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index 6671669a8942b..4b6d19422229f 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -2086,12 +2086,8 @@ unsigned RISCVInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
const Function &F = MF.getFunction();
if (Opcode == TargetOpcode::PATCHABLE_FUNCTION_ENTER &&
F.hasFnAttribute("patchable-function-entry")) {
- unsigned Num;
- if (F.getFnAttribute("patchable-function-entry")
- .getValueAsString()
- .getAsInteger(10, Num))
- return get(Opcode).getSize();
-
+ unsigned Num =
+ F.getFnAttributeAsParsedInteger("patchable-function-entry");
// Number of C.NOP or NOP
return (STI.hasStdExtZca() ? 2 : 4) * Num;
}
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 7871e4a53de2a..6da1567ed7f30 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -938,13 +938,9 @@ void SystemZAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(
// If patchable-function-entry is set, emit in-function nops here.
if (F.hasFnAttribute("patchable-function-entry")) {
- unsigned Num;
// get M-N from function attribute (CodeGenFunction subtracts N
// from M to yield the correct patchable-function-entry).
- if (F.getFnAttribute("patchable-function-entry")
- .getValueAsString()
- .getAsInteger(10, Num))
- return;
+ unsigned Num = F.getFnAttributeAsParsedInteger("patchable-function-entry");
// Emit M-N 2-byte nops. Use getNop() here instead of emitNops()
// to keep it aligned with the common code implementation emitting
// the prefix nops.
diff --git a/llvm/lib/Target/X86/X86AsmPrinter.cpp b/llvm/lib/Target/X86/X86AsmPrinter.cpp
index 94dd706fe9944..f297949d13c5d 100644
--- a/llvm/lib/Target/X86/X86AsmPrinter.cpp
+++ b/llvm/lib/Target/X86/X86AsmPrinter.cpp
@@ -153,11 +153,8 @@ void X86AsmPrinter::EmitKCFITypePadding(const MachineFunction &MF,
bool HasType) {
// Keep the function entry aligned, taking patchable-function-prefix into
// account if set.
- int64_t PrefixBytes = 0;
- (void)MF.getFunction()
- .getFnAttribute("patchable-function-prefix")
- .getValueAsString()
- .getAsInteger(10, PrefixBytes);
+ int64_t PrefixBytes = MF.getFunction().getFnAttributeAsParsedInteger(
+ "patchable-function-prefix");
// Also take the type identifier into account if we're emitting
// one. Otherwise, just pad with nops. The X86::MOV32ri instruction emitted
diff --git a/llvm/lib/Target/X86/X86MCInstLower.cpp b/llvm/lib/Target/X86/X86MCInstLower.cpp
index 98126ec07b74d..d98cbefde2893 100644
--- a/llvm/lib/Target/X86/X86MCInstLower.cpp
+++ b/llvm/lib/Target/X86/X86MCInstLower.cpp
@@ -909,11 +909,8 @@ void X86AsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {
// bytes. This assumes that patchable-function-prefix is the same for all
// functions.
const MachineFunction &MF = *MI.getMF();
- int64_t PrefixNops = 0;
- (void)MF.getFunction()
- .getFnAttribute("patchable-function-prefix")
- .getValueAsString()
- .getAsInteger(10, PrefixNops);
+ int64_t PrefixNops = MF.getFunction().getFnAttributeAsParsedInteger(
+ "patchable-function-prefix");
// KCFI allows indirect calls to any location that's preceded by a valid
// type identifier. To avoid encoding the full constant into an instruction,
@@ -1310,11 +1307,7 @@ void X86AsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI,
const Function &F = MF->getFunction();
if (F.hasFnAttribute("patchable-function-entry")) {
- unsigned Num;
- if (F.getFnAttribute("patchable-function-entry")
- .getValueAsString()
- .getAsInteger(10, Num))
- return;
+ unsigned Num = F.getFnAttributeAsParsedInteger("patchable-function-entry");
emitX86Nops(*OutStreamer, Num, Subtarget);
return;
}
More information about the llvm-commits
mailing list