diff --git a/llvm/lib/CodeGen/PatchableFunction.cpp b/llvm/lib/CodeGen/PatchableFunction.cpp --- a/llvm/lib/CodeGen/PatchableFunction.cpp +++ b/llvm/lib/CodeGen/PatchableFunction.cpp @@ -55,6 +55,15 @@ } bool PatchableFunction::runOnMachineFunction(MachineFunction &MF) { + if (MF.getFunction().hasFnAttribute("patchable-function-entry")) { + MachineBasicBlock &FirstMBB = *MF.begin(); + MachineInstr &FirstMI = *FirstMBB.begin(); + const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); + BuildMI(FirstMBB, FirstMI, FirstMI.getDebugLoc(), + TII->get(TargetOpcode::PATCHABLE_FUNCTION_ENTER)); + return true; + } + if (!MF.getFunction().hasFnAttribute("patchable-function")) return false; diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -1851,6 +1851,18 @@ if (FP != "all" && FP != "non-leaf" && FP != "none") CheckFailed("invalid value for 'frame-pointer' attribute: " + FP, V); } + + if (Attrs.hasFnAttribute("patchable-function-entry")) { + StringRef S0 = Attrs + .getAttribute(AttributeList::FunctionIndex, + "patchable-function-entry") + .getValueAsString(); + StringRef S = S0; + unsigned N; + if (S.consumeInteger(10, N) || !S.consume_front(",") || + S.consumeInteger(10, N) || N) + CheckFailed("\"patchable-function-entry\" accepts N,0: " + S0, V); + } } void Verifier::verifyFunctionMetadata( diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -243,6 +243,18 @@ void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI) { + const Function &F = MF->getFunction(); + if (F.hasFnAttribute("patchable-function-entry")) { + StringRef Entry = + F.getFnAttribute("patchable-function-entry").getValueAsString(); + unsigned Num; + if (Entry.consumeInteger(10, Num)) + return; + for (; Num; --Num) + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0)); + return; + } + EmitSled(MI, SledKind::FUNCTION_ENTER); } diff --git a/llvm/test/CodeGen/AArch64/patchable-function-entry.ll b/llvm/test/CodeGen/AArch64/patchable-function-entry.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/patchable-function-entry.ll @@ -0,0 +1,23 @@ +; RUN: llc -mtriple=aarch64 %s -o - | FileCheck %s + +define i32 @f0() "patchable-function-entry"="0,0" { +; CHECK-LABEL: f0: +; CHECK-NOT: nop +; CHECK: mov w0, wzr + ret i32 0 +} + +define i32 @f1() "patchable-function-entry"="1,0" { +; CHECK-LABEL: f1: +; CHECK: nop +; CHECK-NEXT: mov w0, wzr + ret i32 0 +} + +define void @f3() "patchable-function-entry"="3,0" { +; CHECK-LABEL: f3: +; CHECK-COUNT-3: nop +; CHECK-NEXT: sub sp, sp, #16 + %frame = alloca i8, i32 16 + ret void +} diff --git a/llvm/test/Verifier/invalid-patchable-function-entry.ll b/llvm/test/Verifier/invalid-patchable-function-entry.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Verifier/invalid-patchable-function-entry.ll @@ -0,0 +1,13 @@ +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s + +; CHECK: "patchable-function-entry" accepts N,0: +; CHECK: "patchable-function-entry" accepts N,0: a +; CHECK: "patchable-function-entry" accepts N,0: -1,0 +; CHECK: "patchable-function-entry" accepts N,0: 3 +; CHECK: "patchable-function-entry" accepts N,0: 3,1 + +define void @f() "patchable-function-entry" { ret void } +define void @fa() "patchable-function-entry"="a" { ret void } +define void @f_1() "patchable-function-entry"="-1,0" { ret void } +define void @f3() "patchable-function-entry"="3" { ret void } +define void @f31() "patchable-function-entry"="3,1" { ret void }