https://github.com/dominik-steenken updated 
https://github.com/llvm/llvm-project/pull/178191

>From 6813c4ea28b0a3e77d101e386e880bcf180abc8c Mon Sep 17 00:00:00 2001
From: Dominik Steenken <[email protected]>
Date: Thu, 22 Jan 2026 08:47:36 +0100
Subject: [PATCH] [SystemZ] Enable -fpatchable-function-entry=M,N

This commit enables the option `-fpatchable-function-entry` for SystemZ. It 
utilizes
existing common code and just adds the emission of nops after the function label
in the backend.

SystemZ provides multiple nop options of varying length, making
the semantics of this option somewhat ambiguous. In order to align with what
`gcc` does with that same option, we#re choosing `nopr` as the canoonical nop
for this purpose.

For test, this adapts an existing test file from aarch64.
---
 clang/include/clang/Basic/Attr.td             |   7 +-
 clang/include/clang/Basic/AttrDocs.td         |   2 +-
 clang/lib/Driver/ToolChains/Clang.cpp         |   2 +-
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp |  58 ++++++----
 llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp  |   5 +
 llvm/lib/Target/SystemZ/SystemZInstrInfo.h    |   2 +
 .../SystemZ/patchable-function-entry.ll       | 102 ++++++++++++++++++
 7 files changed, 153 insertions(+), 25 deletions(-)
 create mode 100644 llvm/test/CodeGen/SystemZ/patchable-function-entry.ll

diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index 2335168e4510c..fac86418bc8de 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -969,9 +969,10 @@ def XRayLogArgs : InheritableAttr {
 
 def PatchableFunctionEntry
     : InheritableAttr,
-      TargetSpecificAttr<TargetArch<
-          ["aarch64", "aarch64_be", "loongarch32", "loongarch64", "riscv32",
-           "riscv64", "x86", "x86_64", "ppc", "ppc64", "ppc64le"]>> {
+      TargetSpecificAttr<
+          TargetArch<["aarch64", "aarch64_be", "loongarch32", "loongarch64",
+                      "riscv32", "riscv64", "x86", "x86_64", "ppc", "ppc64",
+                      "ppc64le", "systemz"]>> {
   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 6e2c73f924352..5b97a91af0adc 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -6763,7 +6763,7 @@ if omitted.``Section`` defaults  to the 
``-fpatchable-function-entry`` section n
 set, or to ``__patchable_function_entries`` otherwise.
 
 This attribute is only supported on
-aarch64/aarch64-be/loongarch32/loongarch64/riscv32/riscv64/i386/x86-64/ppc/ppc64/ppc64le
 targets.
+aarch64/aarch64-be/loongarch32/loongarch64/riscv32/riscv64/i386/x86-64/ppc/ppc64/ppc64le/s390x
 targets.
 For ppc/ppc64 targets, AIX is still not supported.
 }];
 }
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index ab671d032644b..93e7b596f567b 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6777,7 +6777,7 @@ 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.isSystemZ() &&
         !(!Triple.isOSAIX() && (Triple.getArch() == llvm::Triple::ppc ||
                                 Triple.getArch() == llvm::Triple::ppc64 ||
                                 Triple.getArch() == llvm::Triple::ppc64le)))
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp 
b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 33e48f8ff1511..d3e500096af89 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -909,26 +909,44 @@ void SystemZAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(
   //
   // Update compiler-rt/lib/xray/xray_s390x.cpp accordingly when number
   // of instructions change.
-  bool HasVectorFeature =
-      TM.getMCSubtargetInfo()->hasFeature(SystemZ::FeatureVector) &&
-      !TM.getMCSubtargetInfo()->hasFeature(SystemZ::FeatureSoftFloat);
-  MCSymbol *FuncEntry = OutContext.getOrCreateSymbol(
-      HasVectorFeature ? "__xray_FunctionEntryVec" : "__xray_FunctionEntry");
-  MCSymbol *BeginOfSled = OutContext.createTempSymbol("xray_sled_", true);
-  MCSymbol *EndOfSled = OutContext.createTempSymbol();
-  OutStreamer->emitLabel(BeginOfSled);
-  EmitToStreamer(*OutStreamer,
-                 MCInstBuilder(SystemZ::J)
-                     .addExpr(MCSymbolRefExpr::create(EndOfSled, OutContext)));
-  EmitNop(OutContext, *OutStreamer, 2, getSubtargetInfo());
-  EmitToStreamer(*OutStreamer,
-                 MCInstBuilder(SystemZ::LLILF).addReg(SystemZ::R2D).addImm(0));
-  EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BRASL)
-                                   .addReg(SystemZ::R14D)
-                                   .addExpr(MCSymbolRefExpr::create(
-                                       FuncEntry, SystemZ::S_PLT, 
OutContext)));
-  OutStreamer->emitLabel(EndOfSled);
-  recordSled(BeginOfSled, MI, SledKind::FUNCTION_ENTER, 2);
+  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;
+    // Emit M-N 2-byte nops (CodeGenFunction subtracts N from M to yield the
+    // correct patchable-function-entry).
+    // Use getNop() here instead of emitNops() to keep it aligned with the
+    // common code implementation emitting the prefix nops
+    for (unsigned I = 0; I < Num; ++I)
+      EmitToStreamer(*OutStreamer, MF.getSubtarget().getInstrInfo()->getNop());
+  } else {
+    bool HasVectorFeature =
+        TM.getMCSubtargetInfo()->hasFeature(SystemZ::FeatureVector) &&
+        !TM.getMCSubtargetInfo()->hasFeature(SystemZ::FeatureSoftFloat);
+    MCSymbol *FuncEntry = OutContext.getOrCreateSymbol(
+        HasVectorFeature ? "__xray_FunctionEntryVec" : "__xray_FunctionEntry");
+    MCSymbol *BeginOfSled = OutContext.createTempSymbol("xray_sled_", true);
+    MCSymbol *EndOfSled = OutContext.createTempSymbol();
+    OutStreamer->emitLabel(BeginOfSled);
+    EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::J)
+                                     .addExpr(MCSymbolRefExpr::create(
+                                         EndOfSled, OutContext)));
+    EmitNop(OutContext, *OutStreamer, 2, getSubtargetInfo());
+    EmitToStreamer(
+        *OutStreamer,
+        MCInstBuilder(SystemZ::LLILF).addReg(SystemZ::R2D).addImm(0));
+    EmitToStreamer(*OutStreamer,
+                   MCInstBuilder(SystemZ::BRASL)
+                       .addReg(SystemZ::R14D)
+                       .addExpr(MCSymbolRefExpr::create(
+                           FuncEntry, SystemZ::S_PLT, OutContext)));
+    OutStreamer->emitLabel(EndOfSled);
+    recordSled(BeginOfSled, MI, SledKind::FUNCTION_ENTER, 2);
+  }
 }
 
 void SystemZAsmPrinter::LowerPATCHABLE_RET(const MachineInstr &MI,
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp 
b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index 16654125d2b52..c48e471fdadb2 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -33,6 +33,7 @@
 #include "llvm/CodeGen/TargetOpcodes.h"
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
 #include "llvm/CodeGen/VirtRegMap.h"
+#include "llvm/MC/MCInstBuilder.h"
 #include "llvm/MC/MCInstrDesc.h"
 #include "llvm/MC/MCRegisterInfo.h"
 #include "llvm/Support/BranchProbability.h"
@@ -2376,3 +2377,7 @@ 
SystemZInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
       {MO_ADA_DIRECT_FUNC_DESC, "systemz-ada-directfuncdesc"}};
   return ArrayRef(TargetFlags);
 }
+
+MCInst SystemZInstrInfo::getNop() const {
+  return MCInstBuilder(SystemZ::NOPR).addReg(0);
+}
\ No newline at end of file
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.h 
b/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
index 6fc66c72a25e6..29ae9e0ed80e7 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
@@ -391,6 +391,8 @@ class SystemZInstrInfo : public SystemZGenInstrInfo {
 
   ArrayRef<std::pair<unsigned, const char *>>
   getSerializableDirectMachineOperandTargetFlags() const override;
+
+  MCInst getNop() const override;
 };
 
 } // end namespace llvm
diff --git a/llvm/test/CodeGen/SystemZ/patchable-function-entry.ll 
b/llvm/test/CodeGen/SystemZ/patchable-function-entry.ll
new file mode 100644
index 0000000000000..24c5ab4502bf0
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/patchable-function-entry.ll
@@ -0,0 +1,102 @@
+; RUN: llc -mtriple=s390x-ibm-linux %s -o - | FileCheck %s
+; RUN: llc -mtriple=s390x-ibm-linux -function-sections %s -o - | FileCheck %s
+; RUN: llc -mtriple=s390x-ibm-linux -function-sections %s -o - | FileCheck %s
+; RUN: llc -mtriple=s390x-ibm-linux -no-integrated-as -binutils-version=2.35 
%s -o - | FileCheck --check-prefix=NOLINK %s
+; RUN: llc -mtriple=s390x-ibm-linux -no-integrated-as -binutils-version=2.36 
%s -o - | FileCheck %s
+
+;; GNU ld < 2.36 did not support mixed SHF_LINK_ORDER and non-SHF_LINK_ORDER 
sections.
+; NOLINK-NOT: "awo"
+
+define i32 @f0() "patchable-function-entry"="0" {
+; CHECK-LABEL: f0:
+; CHECK-NEXT: .Lfunc_begin0:
+; CHECK-NOT:   nopr
+; CHECK:       lhi     %r2, 0
+; CHECK-NOT:   .section __patchable_function_entries
+  ret i32 0
+}
+
+define i32 @f1() "patchable-function-entry"="1" {
+; CHECK-LABEL: f1:
+; CHECK-NEXT: .Lfunc_begin1:
+; CHECK:       nopr
+; CHECK-NEXT:  lhi     %r2, 0
+; CHECK:       .section __patchable_function_entries,"awo",@progbits,f1{{$}}
+; CHECK-NEXT:  .p2align 3, 0x0
+; CHECK-NEXT: .quad   .Lfunc_begin1
+  ret i32 0
+}
+
+;; Without -function-sections, f2 is in the same text section as f1.
+;; They share the __patchable_function_entries section.
+;; With -function-sections, f1 and f2 are in different text sections.
+;; Use separate __patchable_function_entries.
+define void @f2() "patchable-function-entry"="2" {
+; CHECK-LABEL: f2:
+; CHECK-NEXT: .Lfunc_begin2:
+; CHECK-COUNT-2: nopr
+; CHECK-NEXT:  br      %r14
+; CHECK:       .section __patchable_function_entries,"awo",@progbits,f2{{$}}
+; CHECK-NEXT:  .p2align 3, 0x0
+; CHECK-NEXT: .quad   .Lfunc_begin2
+  ret void
+}
+
+$f3 = comdat any
+define void @f3() "patchable-function-entry"="3" comdat {
+; CHECK-LABEL: f3:
+; CHECK-NEXT: .Lfunc_begin3:
+; CHECK-COUNT-3: nopr
+; CHECK-NEXT:  br      %r14
+; CHECK:       .section 
__patchable_function_entries,"awoG",@progbits,f3,f3,comdat{{$}}
+; CHECK-NEXT:  .p2align 3, 0x0
+; CHECK-NEXT: .quad   .Lfunc_begin3
+  ret void
+}
+
+$f5 = comdat any
+define void @f5() "patchable-function-entry"="5" comdat {
+; CHECK-LABEL: f5:
+; CHECK-NEXT: .Lfunc_begin4:
+; CHECK-COUNT-5: nopr
+; CHECK-NEXT:  aghi    %r15, -176
+; CHECK:       .section 
__patchable_function_entries,"awoG",@progbits,f5,f5,comdat{{$}}
+; CHECK:       .p2align 3, 0x0
+; CHECK-NEXT: .quad   .Lfunc_begin4
+  %frame = alloca i8, i32 16
+  ret void
+}
+
+;; -fpatchable-function-entry=3,2
+;; "patchable-function-prefix" emits data before the function entry label.
+define void @f3_2() "patchable-function-entry"="1" 
"patchable-function-prefix"="2" {
+; CHECK-LABEL: .type f3_2,@function
+; CHECK-NEXT: .Ltmp0:
+; CHECK-NEXT:  nopr
+; CHECK-NEXT:  nopr
+; CHECK-NEXT: f3_2:  # @f3_2
+; CHECK:      # %bb.0:
+; CHECK-NEXT:  nopr
+; CHECK-NEXT:  br      %r14
+;; .size does not include the prefix.
+; CHECK:      .Lfunc_end5:
+; CHECK-NEXT: .size f3_2, .Lfunc_end5-f3_2
+; CHECK:      .section __patchable_function_entries,"awo",@progbits,f3_2{{$}}
+; CHECK:      .p2align 3, 0x0
+; CHECK-NEXT: .quad   .Ltmp0
+  ret void
+}
+
+;; When prefix data is used, arbitrarily place noprs after prefix data.
+define void @prefix() "patchable-function-entry"="0" 
"patchable-function-prefix"="1" prefix i32 1 {
+; CHECK-LABEL: .type prefix,@function
+; CHECK-NEXT: .long 1 # 0x1
+; CHECK:      .Ltmp1:
+; CHECK:       nopr
+; CHECK-NEXT: prefix:  # @prefix
+;; Emit a __patchable_function_entries entry even if 
"patchable-function-entry" is 0.
+; CHECK:      .section __patchable_function_entries,"awo",@progbits,prefix{{$}}
+; CHECK:      .p2align        3, 0x0
+; CHECK-NEXT: .quad   .Ltmp1
+  ret void
+}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to