Skip to content

Commit 296fa31

Browse files
[SystemZ] Add proper mcount handling
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.
1 parent b4017d8 commit 296fa31

File tree

3 files changed

+73
-6
lines changed

3 files changed

+73
-6
lines changed

llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "SystemZFrameLowering.h"
10+
#include "MCTargetDesc/SystemZMCTargetDesc.h"
1011
#include "SystemZCallingConv.h"
1112
#include "SystemZInstrInfo.h"
1213
#include "SystemZMachineFunctionInfo.h"
@@ -18,6 +19,8 @@
1819
#include "llvm/CodeGen/RegisterScavenging.h"
1920
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
2021
#include "llvm/IR/Function.h"
22+
#include "llvm/IR/GlobalVariable.h"
23+
#include "llvm/IR/Module.h"
2124
#include "llvm/Target/TargetMachine.h"
2225

2326
using namespace llvm;
@@ -558,6 +561,31 @@ void SystemZELFFrameLowering::emitPrologue(MachineFunction &MF,
558561
// to determine the end of the prologue.
559562
DebugLoc DL;
560563

564+
// Add mcount instrumentation if necessary.
565+
if (MF.getFunction().getFnAttribute("instrument-function-entry-inlined").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 0 to ensure this will not be moved by the
575+
// scheduler.).
576+
const uint32_t Mask = 0;
577+
BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::CallBRASL))
578+
.addGlobalAddress(MF.getFunction().getParent()->getFunction("mcount"))
579+
.addRegMask(&Mask);
580+
581+
// Reload return address drom 8 bytes above stack pointer.
582+
BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::LG))
583+
.addReg(SystemZ::R14D)
584+
.addReg(SystemZ::R15D)
585+
.addImm(8)
586+
.addReg(0);
587+
}
588+
561589
// The current offset of the stack pointer from the CFA.
562590
int64_t SPOffsetFromCFA = -SystemZMC::ELFCFAOffsetFromInitialSP;
563591

llvm/lib/Transforms/Utils/EntryExitInstrumenter.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
using namespace llvm;
2424

25-
static void insertCall(Function &CurFn, StringRef Func,
25+
static bool insertCall(Function &CurFn, StringRef Func,
2626
BasicBlock::iterator InsertionPt, DebugLoc DL) {
2727
Module &M = *InsertionPt->getParent()->getParent()->getParent();
2828
LLVMContext &C = InsertionPt->getParent()->getContext();
@@ -63,12 +63,16 @@ 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+
M.getOrInsertFunction(Func, Type::getVoidTy(C));
68+
// skip insertion for `mcount` on SystemZ. This will be handled later in `emitPrologue`.
69+
return false;
6670
} else {
6771
FunctionCallee Fn = M.getOrInsertFunction(Func, Type::getVoidTy(C));
6872
CallInst *Call = CallInst::Create(Fn, "", InsertionPt);
6973
Call->setDebugLoc(DL);
7074
}
71-
return;
75+
return true;
7276
}
7377

7478
if (Func == "__cyg_profile_func_enter" || Func == "__cyg_profile_func_exit") {
@@ -87,7 +91,7 @@ static void insertCall(Function &CurFn, StringRef Func,
8791
CallInst *Call =
8892
CallInst::Create(Fn, ArrayRef<Value *>(Args), "", InsertionPt);
8993
Call->setDebugLoc(DL);
90-
return;
94+
return true;
9195
}
9296

9397
// We only know how to call a fixed set of instrumentation functions, because
@@ -129,9 +133,9 @@ static bool runOnFunction(Function &F, bool PostInlining) {
129133
if (auto SP = F.getSubprogram())
130134
DL = DILocation::get(SP->getContext(), SP->getScopeLine(), 0, SP);
131135

132-
insertCall(F, EntryFunc, F.begin()->getFirstInsertionPt(), DL);
133-
Changed = true;
134-
F.removeFnAttr(EntryAttr);
136+
Changed = insertCall(F, EntryFunc, F.begin()->getFirstInsertionPt(), DL);
137+
if (Changed)
138+
F.removeFnAttr(EntryAttr);
135139
}
136140

137141
if (!ExitFunc.empty()) {

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)