[CodeGen] Use getFnAttributeAsParsedInteger for patchable-function attributes (#194726)

Replace `getAsInteger()` parsing of the `patchable-function-entry`
and `patchable-function-prefix` function attributes with the existing
`Function::getFnAttributeAsParsedInteger()` helper across AsmPrinter
and all backend targets.

The IR verifier already validates these attributes as unsigned base-10
integers via `checkUnsignedBaseTenFuncAttr`, so parse failure at point
of use indicates a verifier bypass or IR corruption.
`getFnAttributeAsParsedInteger()` returns a default of 0 on failure
(matching the implicit behavior of the old code) and emits a diagnostic
rather than silently continuing.
This commit is contained in:
JP Hafer
2026-04-29 11:18:07 -04:00
committed by GitHub
parent 095d465cdd
commit 766a42a11c
12 changed files with 32 additions and 87 deletions

View File

@@ -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();

View File

@@ -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)

View File

@@ -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()) {

View File

@@ -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;
}

View File

@@ -343,11 +343,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]];

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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.

View File

@@ -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

View File

@@ -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;
}