From a8fbdc576990653e92ce1d766659005678fd8514 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sat, 4 Jan 2020 19:52:36 -0800 Subject: [PATCH] [X86] Support function attribute "patchable-function-entry" For x86-64, we diverge from GCC -fpatchable-function-entry in that we emit multi-byte NOPs. Differential Revision: https://reviews.llvm.org/D72220 --- llvm/lib/Target/X86/X86MCInstLower.cpp | 18 +++++-- llvm/test/CodeGen/X86/patchable-function-entry.ll | 58 +++++++++++++++++++++++ 2 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 llvm/test/CodeGen/X86/patchable-function-entry.ll diff --git a/llvm/lib/Target/X86/X86MCInstLower.cpp b/llvm/lib/Target/X86/X86MCInstLower.cpp index 3cb9115..e20d1ee 100644 --- a/llvm/lib/Target/X86/X86MCInstLower.cpp +++ b/llvm/lib/Target/X86/X86MCInstLower.cpp @@ -1035,9 +1035,11 @@ void X86AsmPrinter::LowerTlsAddr(X86MCInstLower &MCInstLowering, /// bytes. Return the size of nop emitted. static unsigned EmitNop(MCStreamer &OS, unsigned NumBytes, bool Is64Bit, const MCSubtargetInfo &STI) { - // This works only for 64bit. For 32bit we have to do additional checking if - // the CPU supports multi-byte nops. - assert(Is64Bit && "EmitNops only supports X86-64"); + if (!Is64Bit) { + // TODO Do additional checking if the CPU supports multi-byte nops. + OS.EmitInstruction(MCInstBuilder(X86::NOOP), STI); + return 1; + } unsigned NopSize; unsigned Opc, BaseReg, ScaleVal, IndexReg, Displacement, SegmentReg; @@ -1597,6 +1599,16 @@ void X86AsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI, NoAutoPaddingScope NoPadScope(*OutStreamer); + const Function &F = MF->getFunction(); + if (F.hasFnAttribute("patchable-function-entry")) { + unsigned Num; + if (F.getFnAttribute("patchable-function-entry") + .getValueAsString() + .getAsInteger(10, Num)) + return; + EmitNops(*OutStreamer, Num, Subtarget->is64Bit(), getSubtargetInfo()); + return; + } // We want to emit the following pattern: // // .p2align 1, ... diff --git a/llvm/test/CodeGen/X86/patchable-function-entry.ll b/llvm/test/CodeGen/X86/patchable-function-entry.ll new file mode 100644 index 0000000..89d94f8 --- /dev/null +++ b/llvm/test/CodeGen/X86/patchable-function-entry.ll @@ -0,0 +1,58 @@ +; RUN: llc -mtriple=i386 %s -o - | FileCheck --check-prefixes=CHECK,NOFSECT,32 %s +; RUN: llc -mtriple=x86_64 %s -o - | FileCheck --check-prefixes=CHECK,NOFSECT,64 %s + +define void @f0() "patchable-function-entry"="0" { +; CHECK-LABEL: f0: +; CHECK-NEXT: .Lfunc_begin0: +; CHECK-NOT: nop +; CHECK: ret +; CHECK: .section __patchable_function_entries,"awo",@progbits,f0,unique,0 +; 32: .p2align 2 +; 32-NEXT: .long .Lfunc_begin0 +; 64: .p2align 3 +; 64-NEXT: .quad .Lfunc_begin0 + ret void +} + +define void @f1() "patchable-function-entry"="1" { +; CHECK-LABEL: f1: +; CHECK: nop +; CHECK-NEXT: ret +; NOFSECT: .section __patchable_function_entries,"awo",@progbits,f0,unique,0 +; FSECT: .section __patchable_function_entries,"awo",@progbits,f1,unique,1 +; 32: .p2align 2 +; 32-NEXT: .long .Lfunc_begin1 +; 64: .p2align 3 +; 64-NEXT: .quad .Lfunc_begin1 + ret void +} + +$f3 = comdat any +define void @f3() "patchable-function-entry"="3" comdat { +; CHECK-LABEL: f3: +; 32-COUNT-3: nop +; 64: nopl (%rax) +; CHECK: ret +; NOFSECT: .section __patchable_function_entries,"aGwo",@progbits,f3,comdat,f3,unique,1 +; FSECT: .section __patchable_function_entries,"aGwo",@progbits,f3,comdat,f3,unique,2 +; 32: .p2align 2 +; 32-NEXT: .long .Lfunc_begin2 +; 64: .p2align 3 +; 64-NEXT: .quad .Lfunc_begin2 + ret void +} + +$f5 = comdat any +define void @f5() "patchable-function-entry"="5" comdat { +; CHECK-LABEL: f5: +; 32-COUNT-5: nop +; 64: nopl 8(%rax,%rax) +; CHECK-NEXT: ret +; NOFSECT .section __patchable_function_entries,"aGwo",@progbits,f5,comdat,f5,unique,2 +; FSECT: .section __patchable_function_entries,"aGwo",@progbits,f5,comdat,f5,unique,3 +; 32: .p2align 2 +; 32-NEXT: .long .Lfunc_begin3 +; 64: .p2align 3 +; 64-NEXT: .quad .Lfunc_begin3 + ret void +} -- 2.7.4