[SystemZ] Enable -fpatchable-function-entry=M,N (#178191)
This PR 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.
(cherry picked from commit 355898a6ce)
This commit is contained in:
parent
0d37e79da8
commit
ca06985982
7 changed files with 136 additions and 5 deletions
|
|
@ -967,9 +967,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>,
|
||||
|
|
|
|||
|
|
@ -6749,7 +6749,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.
|
||||
}];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)))
|
||||
|
|
|
|||
|
|
@ -901,6 +901,27 @@ void SystemZAsmPrinter::LowerPATCHPOINT(const MachineInstr &MI,
|
|||
|
||||
void SystemZAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(
|
||||
const MachineInstr &MI, SystemZMCInstLower &Lower) {
|
||||
|
||||
const MachineFunction &MF = *(MI.getParent()->getParent());
|
||||
const Function &F = MF.getFunction();
|
||||
|
||||
// If patchable-function-entry is set, emit in-function nops here.
|
||||
if (F.hasFnAttribute("patchable-function-entry")) {
|
||||
unsigned Num;
|
||||
// get M-N from function attribute (CodeGenFunction subtracts N
|
||||
// from M to yield the correct patchable-function-entry).
|
||||
if (F.getFnAttribute("patchable-function-entry")
|
||||
.getValueAsString()
|
||||
.getAsInteger(10, Num))
|
||||
return;
|
||||
// Emit M-N 2-byte nops. 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());
|
||||
return;
|
||||
}
|
||||
// Otherwise, emit xray sled.
|
||||
// .begin:
|
||||
// j .end # -> stmg %r2, %r15, 16(%r15)
|
||||
// nop
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -2378,3 +2379,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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -391,6 +391,8 @@ public:
|
|||
|
||||
ArrayRef<std::pair<unsigned, const char *>>
|
||||
getSerializableDirectMachineOperandTargetFlags() const override;
|
||||
|
||||
MCInst getNop() const override;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
|
|
|||
102
llvm/test/CodeGen/SystemZ/patchable-function-entry.ll
Normal file
102
llvm/test/CodeGen/SystemZ/patchable-function-entry.ll
Normal file
|
|
@ -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
|
||||
}
|
||||
Loading…
Reference in a new issue