Skip to content

Commit bd8172e

Browse files
dominik-steenkenGeorgeARM
authored andcommitted
[SystemZ] Add proper mcount handling (llvm#135767)
When compiling with `-pg`, the `EntryExitInstrumenterPass` will insert calls to the glibc function `mcount` at the begining of each `MachineFunction`. On SystemZ, these calls require special handling: - The call to `mcount` needs to happen at the beginning of the prologue. - Prior to the call to `mcount`, register `%r14`, the return address of the callee function, must be stored 8 bytes above the stack pointer `%r15`. After the call to `mcount` returns, that register needs to be restored. This commit adds some special handling to the EntryExitInstrumenterPass that keeps the insertion of the mcount function into the module, but skips over insertion of the actual call in order to perform this insertion in the `emitPrologue` function. There, a simple sequence of store/call/load is inserted, which implements the above. The desired change in the `EntryExitInstrumenterPass` necessitated the addition of a new attribute and attribute kind to each function, which is used to trigger the postprocessing, aka call insertion, in `emitPrologue`. Note that the new attribute must be of a different kind than the `mcount` atribute, since otherwise it would replace that attribute and later be deleted by the code that intended to delete `mcount`. The new attribnute is called `insert-mcount`, while the attribute kind is `systemz-backend`, to clearly mark it as a SystemZ-specific backend concern. This PR should address issue llvm#121137 . The test inserted here is derived from the example given in that issue.
1 parent f0869f8 commit bd8172e

File tree

3 files changed

+72
-0
lines changed

3 files changed

+72
-0
lines changed

llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
#include "llvm/CodeGen/MachineRegisterInfo.h"
1818
#include "llvm/CodeGen/RegisterScavenging.h"
1919
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
20+
#include "llvm/IR/CallingConv.h"
2021
#include "llvm/IR/Function.h"
22+
#include "llvm/IR/Module.h"
2123
#include "llvm/Target/TargetMachine.h"
2224

2325
using namespace llvm;
@@ -557,6 +559,36 @@ void SystemZELFFrameLowering::emitPrologue(MachineFunction &MF,
557559
// Debug location must be unknown since the first debug location is used
558560
// to determine the end of the prologue.
559561
DebugLoc DL;
562+
// Add mcount instrumentation if necessary.
563+
if (MF.getFunction()
564+
.getFnAttribute("systemz-instrument-function-entry")
565+
.getValueAsString() == "mcount") {
566+
567+
// Store return address 8 bytes above stack pointer.
568+
BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::STG))
569+
.addReg(SystemZ::R14D)
570+
.addReg(SystemZ::R15D)
571+
.addImm(8)
572+
.addReg(0);
573+
574+
// Call mcount (Regmask from CC AnyReg since mcount preserves all normal
575+
// argument registers).
576+
FunctionCallee FC = MF.getFunction().getParent()->getOrInsertFunction(
577+
"mcount", Type::getVoidTy(MF.getFunction().getContext()));
578+
const uint32_t *Mask = MF.getSubtarget<SystemZSubtarget>()
579+
.getSpecialRegisters()
580+
->getCallPreservedMask(MF, CallingConv::AnyReg);
581+
BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::CallBRASL))
582+
.addGlobalAddress(dyn_cast<Function>(FC.getCallee()))
583+
.addRegMask(Mask);
584+
585+
// Reload return address from 8 bytes above stack pointer.
586+
BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::LG))
587+
.addReg(SystemZ::R14D)
588+
.addReg(SystemZ::R15D)
589+
.addImm(8)
590+
.addReg(0);
591+
}
560592

561593
// The current offset of the stack pointer from the CFA.
562594
int64_t SPOffsetFromCFA = -SystemZMC::ELFCFAOffsetFromInitialSP;

llvm/lib/Transforms/Utils/EntryExitInstrumenter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ static void insertCall(Function &CurFn, StringRef Func,
6363
false));
6464
CallInst *Call = CallInst::Create(Fn, RetAddr, "", InsertionPt);
6565
Call->setDebugLoc(DL);
66+
} else if (TargetTriple.isSystemZ()) {
67+
// skip insertion for `mcount` on SystemZ. This will be handled later in
68+
// `emitPrologue`. Add custom attribute to denote this.
69+
CurFn.addFnAttr(
70+
llvm::Attribute::get(C, "systemz-instrument-function-entry", Func));
6671
} else {
6772
FunctionCallee Fn = M.getOrInsertFunction(Func, Type::getVoidTy(C));
6873
CallInst *Call = CallInst::Create(Fn, "", InsertionPt);

llvm/test/CodeGen/SystemZ/mcount.ll

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
; Test proper insertion of mcount instrumentation
2+
;
3+
; RUN: llc < %s -mtriple=s390x-linux-gnu -o - | FileCheck %s
4+
;
5+
; CHECK: # %bb.0:
6+
; CHECK-NEXT: stg %r14, 8(%r15)
7+
; CHECK-NEXT: brasl %r14, mcount@PLT
8+
; CHECK-NEXT: lg %r14, 8(%r15)
9+
define dso_local signext i32 @fib(i32 noundef signext %n) #0 {
10+
entry:
11+
%n.addr = alloca i32, align 4
12+
store i32 %n, ptr %n.addr, align 4
13+
%0 = load i32, ptr %n.addr, align 4
14+
%cmp = icmp sle i32 %0, 1
15+
br i1 %cmp, label %cond.true, label %cond.false
16+
17+
cond.true: ; preds = %entry
18+
br label %cond.end
19+
20+
cond.false: ; preds = %entry
21+
%1 = load i32, ptr %n.addr, align 4
22+
%sub = sub nsw i32 %1, 1
23+
%call = call signext i32 @fib(i32 noundef signext %sub)
24+
%2 = load i32, ptr %n.addr, align 4
25+
%sub1 = sub nsw i32 %2, 2
26+
%call2 = call signext i32 @fib(i32 noundef signext %sub1)
27+
%add = add nsw i32 %call, %call2
28+
br label %cond.end
29+
30+
cond.end: ; preds = %cond.false, %cond.true
31+
%cond = phi i32 [ 1, %cond.true ], [ %add, %cond.false ]
32+
ret i32 %cond
33+
}
34+
35+
attributes #0 = { "instrument-function-entry-inlined"="mcount" }

0 commit comments

Comments
 (0)