Skip to content

[PowerPC] Support -fpatchable-function-entry #92997

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -892,7 +892,7 @@ def PatchableFunctionEntry
: InheritableAttr,
TargetSpecificAttr<TargetArch<
["aarch64", "aarch64_be", "loongarch32", "loongarch64", "riscv32",
"riscv64", "x86", "x86_64"]>> {
"riscv64", "x86", "x86_64", "ppc", "ppc64"]>> {
let Spellings = [GCC<"patchable_function_entry">];
let Subjects = SubjectList<[Function, ObjCMethod]>;
let Args = [UnsignedArgument<"Count">, DefaultIntArgument<"Offset", 0>];
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -5796,7 +5796,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.
}];
}

Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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 "
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

little-endian variants (ppcle ppc64le) are omitted here.

Use isPPC

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Linux little endian targets are this patch's scope. This patch tries to support -fpatchable-function-entry for big endian targets but not AIX.

If we are going to support little endian, we first need to check the possibility about removal of XRAY. (XRAY also uses backend node PATCHABLE_FUNCTION_ENTER)

Triple.getArch() == llvm::Triple::ppc64)))
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << TripleStr;
else if (S.consumeInteger(10, Size) ||
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
9 changes: 7 additions & 2 deletions clang/test/Driver/fpatchable-function-entry.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,20 @@
// 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
// 11: "-fpatchable-function-entry=1" "-fpatchable-function-entry-offset=1"
// 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=
Expand Down
5 changes: 5 additions & 0 deletions clang/test/Sema/patchable-function-entry-attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@
// 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
// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -fsyntax-only -verify=AIX %s
// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -fsyntax-only -verify=AIX %s

// silence-no-diagnostics

// AIX-error@+2 {{'patchable_function_entry' attribute is not yet supported on AIX}}
// expected-warning@+1 {{unknown attribute 'patchable_function_entry' ignored}}
[[gnu::patchable_function_entry(0)]] void f();
23 changes: 22 additions & 1 deletion llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,23 @@ 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 = MF->getFunction();
unsigned Num = 0;
(void)F.getFnAttribute("patchable-function-entry")
.getValueAsString()
.getAsInteger(10, Num);
if (!Num)
return;
emitNops(Num);
return;
}
case TargetOpcode::DBG_VALUE:
llvm_unreachable("Should be handled target independently");
case TargetOpcode::STACKMAP:
Expand Down Expand Up @@ -1781,7 +1798,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]
Expand All @@ -1794,6 +1811,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);
Expand Down Expand Up @@ -1910,6 +1930,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) {
Expand Down
58 changes: 58 additions & 0 deletions llvm/test/CodeGen/PowerPC/patchable-function-entry.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
; RUN: llc -mtriple=powerpc %s -o - | FileCheck %s --check-prefixes=CHECK,PPC32
; RUN: llc -mtriple=powerpc64 %s -o - | FileCheck %s --check-prefixes=CHECK,PPC64

@a = global i32 0, align 4

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 i32 @f3() "patchable-function-entry"="1" "patchable-function-prefix"="2" {
; CHECK-LABEL: .Ltmp0:
; CHECK-COUNT-2: nop
; CHECK-LABEL: f3:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test addis/addi, instructions at the global entry point.

Per https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99888#c5 #c8 and #15, GCC will change the current strategy to match us :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

; CHECK: # %bb.0:
; CHECK-NEXT: nop
; PPC32: lis 3, a@ha
; PPC32-NEXT: lwz 3, a@l(3)
; PPC64: addis 3, 2, .LC0@toc@ha
; PPC64-NEXT: ld 3, .LC0@toc@l(3)
; PPC64-NEXT: lwz 3, 0(3)
; CHECK: blr
; CHECK: .section __patchable_function_entries
; PPC32: .p2align 2, 0x0
; PPC64: .p2align 3, 0x0
; PPC32-NEXT: .long .Ltmp0
; PPC64-NEXT: .quad .Ltmp0
entry:
%0 = load i32, ptr @a, align 4
ret i32 %0
}
Loading