From 7bbd096b9024b27359f63c8cc12fb1be4d7e2cbf Mon Sep 17 00:00:00 2001 From: Chen Zheng Date: Wed, 22 May 2024 02:37:04 -0400 Subject: [PATCH] [PowerPC] Support -fpatchable-function-entry For now only PPC big endian Linux is supported. PPC little endian Linux has XRAY support for 64-bit. PPC AIX has different patchable function entry implementations. Fixes #63220 Fixes #57031 --- clang/include/clang/Basic/Attr.td | 2 +- clang/include/clang/Basic/AttrDocs.td | 3 +- .../clang/Basic/DiagnosticSemaKinds.td | 2 +- clang/lib/Driver/ToolChains/Clang.cpp | 4 +- clang/lib/Sema/SemaDeclAttr.cpp | 4 ++ clang/test/Driver/fpatchable-function-entry.c | 9 +++- .../patchable-function-entry-attr-aix.cpp | 4 ++ .../Sema/patchable-function-entry-attr.cpp | 2 + llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 24 ++++++++- .../PowerPC/patchable-function-entry.ll | 49 +++++++++++++++++++ 10 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 clang/test/Sema/patchable-function-entry-attr-aix.cpp create mode 100644 llvm/test/CodeGen/PowerPC/patchable-function-entry.ll diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 7008bea483c872..e98d0edb6fca02 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -892,7 +892,7 @@ def PatchableFunctionEntry : InheritableAttr, TargetSpecificAttr> { + "riscv64", "x86", "x86_64", "ppc", "ppc64"]>> { let Spellings = [GCC<"patchable_function_entry">]; let Subjects = SubjectList<[Function, ObjCMethod]>; let Args = [UnsignedArgument<"Count">, DefaultIntArgument<"Offset", 0>]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 54197d588eb450..fe566cc25bd0d3 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -5799,7 +5799,8 @@ takes precedence over the command line option ``-fpatchable-function-entry=N,M`` ``M`` defaults to 0 if omitted. This attribute is only supported on -aarch64/aarch64-be/loongarch32/loongarch64/riscv32/riscv64/i386/x86-64 targets. +aarch64/aarch64-be/loongarch32/loongarch64/riscv32/riscv64/i386/x86-64/ppc/ppc64 targets. +For ppc/ppc64 targets, AIX is still not supported. }]; } diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 5a32463763aa67..b807eda3862b2a 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3470,7 +3470,7 @@ def err_attr_tlsmodel_arg : Error<"tls_model must be \"global-dynamic\", " def err_attr_codemodel_arg : Error<"code model '%0' is not supported on this target">; -def err_aix_attr_unsupported_tls_model : Error<"TLS model '%0' is not yet supported on AIX">; +def err_aix_attr_unsupported : Error<"%0 attribute is not yet supported on AIX">; def err_tls_var_aligned_over_maximum : Error< "alignment (%0) of thread-local variable %1 is greater than the maximum supported " diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 6d2015b2cd1566..c7fa6d9a0ffe86 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6681,7 +6681,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, StringRef S0 = A->getValue(), S = S0; unsigned Size, Offset = 0; if (!Triple.isAArch64() && !Triple.isLoongArch() && !Triple.isRISCV() && - !Triple.isX86()) + !Triple.isX86() && + !(!Triple.isOSAIX() && (Triple.getArch() == llvm::Triple::ppc || + Triple.getArch() == llvm::Triple::ppc64))) D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args) << TripleStr; else if (S.consumeInteger(10, Size) || diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index ca5938083917f7..17c17032ef96b5 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5922,6 +5922,10 @@ static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (S.Context.getTargetInfo().getTriple().isOSAIX()) { + S.Diag(AL.getLoc(), diag::err_aix_attr_unsupported) << AL; + return; + } uint32_t Count = 0, Offset = 0; if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), Count, 0, true)) return; diff --git a/clang/test/Driver/fpatchable-function-entry.c b/clang/test/Driver/fpatchable-function-entry.c index 4d0d609584c8de..8df3311f33b0e8 100644 --- a/clang/test/Driver/fpatchable-function-entry.c +++ b/clang/test/Driver/fpatchable-function-entry.c @@ -6,6 +6,8 @@ // RUN: %clang -target loongarch64 %s -fpatchable-function-entry=1,0 -c -### 2>&1 | FileCheck %s // RUN: %clang -target riscv32 %s -fpatchable-function-entry=1,0 -c -### 2>&1 | FileCheck %s // RUN: %clang -target riscv64 %s -fpatchable-function-entry=1,0 -c -### 2>&1 | FileCheck %s +// RUN: %clang -target powerpc-unknown-linux-gnu %s -fpatchable-function-entry=1,0 -c -### 2>&1 | FileCheck %s +// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fpatchable-function-entry=1,0 -c -### 2>&1 | FileCheck %s // CHECK: "-fpatchable-function-entry=1" // RUN: %clang -target aarch64 -fsyntax-only %s -fpatchable-function-entry=1,1 -c -### 2>&1 | FileCheck --check-prefix=11 %s @@ -13,8 +15,11 @@ // RUN: %clang -target aarch64 -fsyntax-only %s -fpatchable-function-entry=2,1 -c -### 2>&1 | FileCheck --check-prefix=21 %s // 21: "-fpatchable-function-entry=2" "-fpatchable-function-entry-offset=1" -// RUN: not %clang -target ppc64 -fsyntax-only %s -fpatchable-function-entry=1 2>&1 | FileCheck --check-prefix=TARGET %s -// TARGET: error: unsupported option '-fpatchable-function-entry=1' for target 'ppc64' +// RUN: not %clang -target powerpc64-ibm-aix-xcoff -fsyntax-only %s -fpatchable-function-entry=1 2>&1 | FileCheck --check-prefix=AIX64 %s +// AIX64: error: unsupported option '-fpatchable-function-entry=1' for target 'powerpc64-ibm-aix-xcoff' + +// RUN: not %clang -target powerpc-ibm-aix-xcoff -fsyntax-only %s -fpatchable-function-entry=1 2>&1 | FileCheck --check-prefix=AIX32 %s +// AIX32: error: unsupported option '-fpatchable-function-entry=1' for target 'powerpc-ibm-aix-xcoff' // RUN: not %clang -target x86_64 -fsyntax-only %s -fpatchable-function-entry=1,0, 2>&1 | FileCheck --check-prefix=EXCESS %s // EXCESS: error: invalid argument '1,0,' to -fpatchable-function-entry= diff --git a/clang/test/Sema/patchable-function-entry-attr-aix.cpp b/clang/test/Sema/patchable-function-entry-attr-aix.cpp new file mode 100644 index 00000000000000..648ad739b1df72 --- /dev/null +++ b/clang/test/Sema/patchable-function-entry-attr-aix.cpp @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -fsyntax-only -verify %s + +// expected-error@+1 {{'patchable_function_entry' attribute is not yet supported on AIX}} +__attribute__((patchable_function_entry(0))) void f(); diff --git a/clang/test/Sema/patchable-function-entry-attr.cpp b/clang/test/Sema/patchable-function-entry-attr.cpp index 9134c851da588c..c08293dfe66729 100644 --- a/clang/test/Sema/patchable-function-entry-attr.cpp +++ b/clang/test/Sema/patchable-function-entry-attr.cpp @@ -6,6 +6,8 @@ // RUN: %clang_cc1 -triple loongarch64 -fsyntax-only -verify=silence %s // RUN: %clang_cc1 -triple riscv32 -fsyntax-only -verify=silence %s // RUN: %clang_cc1 -triple riscv64 -fsyntax-only -verify=silence %s +// RUN: %clang_cc1 -triple powerpc-unknown-linux-gnu -fsyntax-only -verify=silence %s +// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -fsyntax-only -verify=silence %s // RUN: %clang_cc1 -triple ppc64le -fsyntax-only -verify %s // silence-no-diagnostics diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp index 72e8215fffaf70..76e3fc10877cd5 100644 --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -909,6 +909,24 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) { // Lower multi-instruction pseudo operations. switch (MI->getOpcode()) { default: break; + case TargetOpcode::PATCHABLE_FUNCTION_ENTER: { + assert(!Subtarget->isAIXABI() && + "AIX does not support patchable function entry!"); + // PATCHABLE_FUNCTION_ENTER on little endian is for XRAY support which is + // handled in PPCLinuxAsmPrinter. + if (MAI->isLittleEndian()) + return; + const Function &F = MI->getParent()->getParent()->getFunction(); + if (F.hasFnAttribute("patchable-function-entry")) { + unsigned Num = 0; + if (F.getFnAttribute("patchable-function-entry") + .getValueAsString() + .getAsInteger(10, Num)) + return; + emitNops(Num); + return; + } + } case TargetOpcode::DBG_VALUE: llvm_unreachable("Should be handled target independently"); case TargetOpcode::STACKMAP: @@ -1781,7 +1799,7 @@ void PPCLinuxAsmPrinter::emitInstruction(const MachineInstr *MI) { switch (MI->getOpcode()) { default: - return PPCAsmPrinter::emitInstruction(MI); + break; case TargetOpcode::PATCHABLE_FUNCTION_ENTER: { // .begin: // b .end # lis 0, FuncId[16..32] @@ -1794,6 +1812,9 @@ void PPCLinuxAsmPrinter::emitInstruction(const MachineInstr *MI) { // // Update compiler-rt/lib/xray/xray_powerpc64.cc accordingly when number // of instructions change. + // XRAY is only supported on PPC Linux little endian. + if (!MAI->isLittleEndian()) + break; MCSymbol *BeginOfSled = OutContext.createTempSymbol(); MCSymbol *EndOfSled = OutContext.createTempSymbol(); OutStreamer->emitLabel(BeginOfSled); @@ -1910,6 +1931,7 @@ void PPCLinuxAsmPrinter::emitInstruction(const MachineInstr *MI) { llvm_unreachable("Tail call is handled in the normal case. See comments " "around this assert."); } + return PPCAsmPrinter::emitInstruction(MI); } void PPCLinuxAsmPrinter::emitStartOfAsmFile(Module &M) { diff --git a/llvm/test/CodeGen/PowerPC/patchable-function-entry.ll b/llvm/test/CodeGen/PowerPC/patchable-function-entry.ll new file mode 100644 index 00000000000000..088b616eb77fce --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/patchable-function-entry.ll @@ -0,0 +1,49 @@ +; RUN: llc -mtriple=powerpc-unknown-linux-gnu %s -o - | FileCheck %s --check-prefixes=CHECK,PPC32 +; RUN: llc -mtriple=powerpc64-unknown-linux-gnu %s -o - | FileCheck %s --check-prefixes=CHECK,PPC64 + +define void @f0() { +; CHECK-LABEL: f0: +; CHECK-NOT: nop +; CHECK: # %bb.0: +; CHECK-NEXT: blr +; CHECK-NOT: .section __patchable_function_entries + ret void +} + +define void @f1() "patchable-function-entry"="0" { +; CHECK-LABEL: f1: +; CHECK-NOT: nop +; CHECK: # %bb.0: +; CHECK-NEXT: blr +; CHECK-NOT: .section __patchable_function_entries + ret void +} + +define void @f2() "patchable-function-entry"="1" { +; CHECK-LABEL: f2: +; CHECK-LABEL-NEXT: .Lfunc_begin2: +; CHECK: # %bb.0: +; CHECK-NEXT: nop +; CHECK-NEXT: blr +; CHECK: .section __patchable_function_entries +; PPC32: .p2align 2, 0x0 +; PPC64: .p2align 3, 0x0 +; PPC32-NEXT: .long .Lfunc_begin2 +; PPC64-NEXT: .quad .Lfunc_begin2 + ret void +} + +define void @f3() "patchable-function-entry"="1" "patchable-function-prefix"="2" { +; CHECK-LABEL: .Ltmp0: +; CHECK-COUNT-2: nop +; CHECK-LABEL: f3: +; CHECK: # %bb.0: +; CHECK-NEXT: nop +; CHECK-NEXT: blr +; CHECK: .section __patchable_function_entries +; PPC32: .p2align 2, 0x0 +; PPC64: .p2align 3, 0x0 +; PPC32-NEXT: .long .Ltmp0 +; PPC64-NEXT: .quad .Ltmp0 + ret void +}