Skip to content

Commit 3c96d01

Browse files
committed
Generate Callee Saved Register (CSR) related cfi directives like .cfi_restore.
https://reviews.llvm.org/D42848 only handled CFA related cfi directives but didn't handle CSR related cfi. The patch adds the CSR part. Basically it reuses the framework created in D42848. For each basicblock, the patch tracks which CSR set have been saved at its CFG predecessors's exits, and compare the CSR set with the set at its previous basicblock's exit (The previous block is the block laid before the current block). If the saved CSR set at its previous basicblock's exit is larger, .cfi_restore will be inserted. The patch also generates proper .cfi_restore in epilogue to make sure the saved CSR set is consistent for the incoming edges of each block. Differential Revision: https://reviews.llvm.org/D74303
1 parent ee9a3eb commit 3c96d01

File tree

7 files changed

+256
-16
lines changed

7 files changed

+256
-16
lines changed

llvm/lib/CodeGen/CFIInstrInserter.cpp

Lines changed: 66 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
//===----------------------------------------------------------------------===//
1919

2020
#include "llvm/ADT/DepthFirstIterator.h"
21+
#include "llvm/ADT/SetOperations.h"
2122
#include "llvm/CodeGen/MachineFunctionPass.h"
2223
#include "llvm/CodeGen/MachineInstrBuilder.h"
2324
#include "llvm/CodeGen/MachineModuleInfo.h"
@@ -76,6 +77,10 @@ class CFIInstrInserter : public MachineFunctionPass {
7677
unsigned IncomingCFARegister = 0;
7778
/// Value of cfa register valid at basic block exit.
7879
unsigned OutgoingCFARegister = 0;
80+
/// Set of callee saved registers saved at basic block entry.
81+
BitVector IncomingCSRSaved;
82+
/// Set of callee saved registers saved at basic block exit.
83+
BitVector OutgoingCSRSaved;
7984
/// If in/out cfa offset and register values for this block have already
8085
/// been set or not.
8186
bool Processed = false;
@@ -108,7 +113,8 @@ class CFIInstrInserter : public MachineFunctionPass {
108113
return -MBBVector[MBB->getNumber()].IncomingCFAOffset;
109114
}
110115

111-
void report(const MBBCFAInfo &Pred, const MBBCFAInfo &Succ);
116+
void reportCFAError(const MBBCFAInfo &Pred, const MBBCFAInfo &Succ);
117+
void reportCSRError(const MBBCFAInfo &Pred, const MBBCFAInfo &Succ);
112118
/// Go through each MBB in a function and check that outgoing offset and
113119
/// register of its predecessors match incoming offset and register of that
114120
/// MBB, as well as that incoming offset and register of its successors match
@@ -132,6 +138,8 @@ void CFIInstrInserter::calculateCFAInfo(MachineFunction &MF) {
132138
// function.
133139
unsigned InitialRegister =
134140
MF.getSubtarget().getFrameLowering()->getInitialCFARegister(MF);
141+
const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
142+
unsigned NumRegs = TRI.getNumRegs();
135143

136144
// Initialize MBBMap.
137145
for (MachineBasicBlock &MBB : MF) {
@@ -141,6 +149,8 @@ void CFIInstrInserter::calculateCFAInfo(MachineFunction &MF) {
141149
MBBInfo.OutgoingCFAOffset = InitialOffset;
142150
MBBInfo.IncomingCFARegister = InitialRegister;
143151
MBBInfo.OutgoingCFARegister = InitialRegister;
152+
MBBInfo.IncomingCSRSaved.resize(NumRegs);
153+
MBBInfo.OutgoingCSRSaved.resize(NumRegs);
144154
MBBVector[MBB.getNumber()] = MBBInfo;
145155
}
146156

@@ -159,8 +169,11 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
159169
int SetOffset = MBBInfo.IncomingCFAOffset;
160170
// Outgoing cfa register set by the block.
161171
unsigned SetRegister = MBBInfo.IncomingCFARegister;
162-
const std::vector<MCCFIInstruction> &Instrs =
163-
MBBInfo.MBB->getParent()->getFrameInstructions();
172+
MachineFunction *MF = MBBInfo.MBB->getParent();
173+
const std::vector<MCCFIInstruction> &Instrs = MF->getFrameInstructions();
174+
const TargetRegisterInfo &TRI = *MF->getSubtarget().getRegisterInfo();
175+
unsigned NumRegs = TRI.getNumRegs();
176+
BitVector CSRSaved(NumRegs), CSRRestored(NumRegs);
164177

165178
// Determine cfa offset and register set by the block.
166179
for (MachineInstr &MI : *MBBInfo.MBB) {
@@ -181,6 +194,15 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
181194
SetRegister = CFI.getRegister();
182195
SetOffset = CFI.getOffset();
183196
break;
197+
case MCCFIInstruction::OpOffset:
198+
case MCCFIInstruction::OpRegister:
199+
case MCCFIInstruction::OpRelOffset:
200+
CSRSaved.set(CFI.getRegister());
201+
break;
202+
case MCCFIInstruction::OpRestore:
203+
case MCCFIInstruction::OpUndefined:
204+
CSRRestored.set(CFI.getRegister());
205+
break;
184206
case MCCFIInstruction::OpRememberState:
185207
// TODO: Add support for handling cfi_remember_state.
186208
#ifndef NDEBUG
@@ -199,12 +221,7 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
199221
break;
200222
// Other CFI directives do not affect CFA value.
201223
case MCCFIInstruction::OpSameValue:
202-
case MCCFIInstruction::OpOffset:
203-
case MCCFIInstruction::OpRelOffset:
204224
case MCCFIInstruction::OpEscape:
205-
case MCCFIInstruction::OpRestore:
206-
case MCCFIInstruction::OpUndefined:
207-
case MCCFIInstruction::OpRegister:
208225
case MCCFIInstruction::OpWindowSave:
209226
case MCCFIInstruction::OpNegateRAState:
210227
case MCCFIInstruction::OpGnuArgsSize:
@@ -218,6 +235,11 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
218235
// Update outgoing CFA info.
219236
MBBInfo.OutgoingCFAOffset = SetOffset;
220237
MBBInfo.OutgoingCFARegister = SetRegister;
238+
239+
// Update outgoing CSR info.
240+
MBBInfo.OutgoingCSRSaved = MBBInfo.IncomingCSRSaved;
241+
MBBInfo.OutgoingCSRSaved |= CSRSaved;
242+
MBBInfo.OutgoingCSRSaved.reset(CSRRestored);
221243
}
222244

223245
void CFIInstrInserter::updateSuccCFAInfo(MBBCFAInfo &MBBInfo) {
@@ -236,6 +258,7 @@ void CFIInstrInserter::updateSuccCFAInfo(MBBCFAInfo &MBBInfo) {
236258
if (!SuccInfo.Processed) {
237259
SuccInfo.IncomingCFAOffset = CurrentInfo.OutgoingCFAOffset;
238260
SuccInfo.IncomingCFARegister = CurrentInfo.OutgoingCFARegister;
261+
SuccInfo.IncomingCSRSaved = CurrentInfo.OutgoingCSRSaved;
239262
Stack.push_back(Succ);
240263
}
241264
}
@@ -287,12 +310,23 @@ bool CFIInstrInserter::insertCFIInstrs(MachineFunction &MF) {
287310
.addCFIIndex(CFIIndex);
288311
InsertedCFIInstr = true;
289312
}
313+
314+
BitVector SetDifference = PrevMBBInfo->OutgoingCSRSaved;
315+
SetDifference.reset(MBBInfo.IncomingCSRSaved);
316+
for (int Reg : SetDifference.set_bits()) {
317+
unsigned CFIIndex =
318+
MF.addFrameInst(MCCFIInstruction::createRestore(nullptr, Reg));
319+
BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
320+
.addCFIIndex(CFIIndex);
321+
InsertedCFIInstr = true;
322+
}
290323
PrevMBBInfo = &MBBInfo;
291324
}
292325
return InsertedCFIInstr;
293326
}
294327

295-
void CFIInstrInserter::report(const MBBCFAInfo &Pred, const MBBCFAInfo &Succ) {
328+
void CFIInstrInserter::reportCFAError(const MBBCFAInfo &Pred,
329+
const MBBCFAInfo &Succ) {
296330
errs() << "*** Inconsistent CFA register and/or offset between pred and succ "
297331
"***\n";
298332
errs() << "Pred: " << Pred.MBB->getName() << " #" << Pred.MBB->getNumber()
@@ -307,6 +341,22 @@ void CFIInstrInserter::report(const MBBCFAInfo &Pred, const MBBCFAInfo &Succ) {
307341
<< " incoming CFA Offset:" << Succ.IncomingCFAOffset << "\n";
308342
}
309343

344+
void CFIInstrInserter::reportCSRError(const MBBCFAInfo &Pred,
345+
const MBBCFAInfo &Succ) {
346+
errs() << "*** Inconsistent CSR Saved between pred and succ in function "
347+
<< Pred.MBB->getParent()->getName() << " ***\n";
348+
errs() << "Pred: " << Pred.MBB->getName() << " #" << Pred.MBB->getNumber()
349+
<< " outgoing CSR Saved: ";
350+
for (int Reg : Pred.OutgoingCSRSaved.set_bits())
351+
errs() << Reg << " ";
352+
errs() << "\n";
353+
errs() << "Succ: " << Succ.MBB->getName() << " #" << Succ.MBB->getNumber()
354+
<< " incoming CSR Saved: ";
355+
for (int Reg : Succ.IncomingCSRSaved.set_bits())
356+
errs() << Reg << " ";
357+
errs() << "\n";
358+
}
359+
310360
unsigned CFIInstrInserter::verify(MachineFunction &MF) {
311361
unsigned ErrorNum = 0;
312362
for (auto *CurrMBB : depth_first(&MF)) {
@@ -321,7 +371,13 @@ unsigned CFIInstrInserter::verify(MachineFunction &MF) {
321371
// we don't generate epilogues inside such blocks.
322372
if (SuccMBBInfo.MBB->succ_empty() && !SuccMBBInfo.MBB->isReturnBlock())
323373
continue;
324-
report(CurrMBBInfo, SuccMBBInfo);
374+
reportCFAError(CurrMBBInfo, SuccMBBInfo);
375+
ErrorNum++;
376+
}
377+
// Check that IncomingCSRSaved of every successor matches the
378+
// OutgoingCSRSaved of CurrMBB
379+
if (SuccMBBInfo.IncomingCSRSaved != CurrMBBInfo.OutgoingCSRSaved) {
380+
reportCSRError(CurrMBBInfo, SuccMBBInfo);
325381
ErrorNum++;
326382
}
327383
}

llvm/lib/Target/X86/X86FrameLowering.cpp

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ void X86FrameLowering::BuildCFI(MachineBasicBlock &MBB,
486486

487487
void X86FrameLowering::emitCalleeSavedFrameMoves(
488488
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
489-
const DebugLoc &DL) const {
489+
const DebugLoc &DL, bool IsPrologue) const {
490490
MachineFunction &MF = *MBB.getParent();
491491
MachineFrameInfo &MFI = MF.getFrameInfo();
492492
MachineModuleInfo &MMI = MF.getMMI();
@@ -501,10 +501,15 @@ void X86FrameLowering::emitCalleeSavedFrameMoves(
501501
I = CSI.begin(), E = CSI.end(); I != E; ++I) {
502502
int64_t Offset = MFI.getObjectOffset(I->getFrameIdx());
503503
unsigned Reg = I->getReg();
504-
505504
unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true);
506-
BuildCFI(MBB, MBBI, DL,
507-
MCCFIInstruction::createOffset(nullptr, DwarfReg, Offset));
505+
506+
if (IsPrologue) {
507+
BuildCFI(MBB, MBBI, DL,
508+
MCCFIInstruction::createOffset(nullptr, DwarfReg, Offset));
509+
} else {
510+
BuildCFI(MBB, MBBI, DL,
511+
MCCFIInstruction::createRestore(nullptr, DwarfReg));
512+
}
508513
}
509514
}
510515

@@ -1675,7 +1680,7 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
16751680
}
16761681

16771682
// Emit DWARF info specifying the offsets of the callee-saved registers.
1678-
emitCalleeSavedFrameMoves(MBB, MBBI, DL);
1683+
emitCalleeSavedFrameMoves(MBB, MBBI, DL, true);
16791684
}
16801685

16811686
// X86 Interrupt handling function cannot assume anything about the direction
@@ -1825,6 +1830,8 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
18251830
}
18261831
uint64_t SEHStackAllocAmt = NumBytes;
18271832

1833+
// AfterPop is the position to insert .cfi_restore.
1834+
MachineBasicBlock::iterator AfterPop = MBBI;
18281835
if (HasFP) {
18291836
// Pop EBP.
18301837
BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
@@ -1835,6 +1842,13 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
18351842
TRI->getDwarfRegNum(Is64Bit ? X86::RSP : X86::ESP, true);
18361843
BuildCFI(MBB, MBBI, DL, MCCFIInstruction::createDefCfa(
18371844
nullptr, DwarfStackPtr, -SlotSize));
1845+
if (!MBB.succ_empty() && !MBB.isReturnBlock()) {
1846+
unsigned DwarfFramePtr = TRI->getDwarfRegNum(MachineFramePtr, true);
1847+
BuildCFI(MBB, AfterPop, DL,
1848+
MCCFIInstruction::createRestore(nullptr, DwarfFramePtr));
1849+
--MBBI;
1850+
--AfterPop;
1851+
}
18381852
--MBBI;
18391853
}
18401854
}
@@ -1934,6 +1948,13 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
19341948
}
19351949
}
19361950

1951+
// Emit DWARF info specifying the restores of the callee-saved registers.
1952+
// For epilogue with return inside or being other block without successor,
1953+
// no need to generate .cfi_restore for callee-saved registers.
1954+
if (NeedsDwarfCFI && !MBB.succ_empty() && !MBB.isReturnBlock()) {
1955+
emitCalleeSavedFrameMoves(MBB, AfterPop, DL, false);
1956+
}
1957+
19371958
if (Terminator == MBB.end() || !isTailCallOpcode(Terminator->getOpcode())) {
19381959
// Add the return addr area delta back since we are not tail calling.
19391960
int Offset = -1 * X86FI->getTCReturnAddrDelta();

llvm/lib/Target/X86/X86FrameLowering.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class X86FrameLowering : public TargetFrameLowering {
6060

6161
void emitCalleeSavedFrameMoves(MachineBasicBlock &MBB,
6262
MachineBasicBlock::iterator MBBI,
63-
const DebugLoc &DL) const;
63+
const DebugLoc &DL, bool IsPrologue) const;
6464

6565
/// emitProlog/emitEpilog - These methods insert prolog and epilog code into
6666
/// the function.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# RUN: llc -o - %s -mtriple=x86_64-- -run-pass=prologepilog 2>&1 | FileCheck %s
2+
--- |
3+
define i64 @_Z3foob(i1 zeroext %cond) #0 {
4+
ret i64 0
5+
}
6+
attributes #0 = {"frame-pointer"="all"}
7+
...
8+
---
9+
# If the epilogue bb.1 is a return block, no .cfi_restore is
10+
# needed in it.
11+
# CHECK: bb.1:
12+
# CHECK-NOT: CFI_INSTRUCTION restore
13+
# CHECK: RET 0
14+
# CHECK: bb.2:
15+
# CHECK: RET 0
16+
name: _Z3foob
17+
alignment: 16
18+
tracksRegLiveness: true
19+
liveins:
20+
- { reg: '$edi' }
21+
frameInfo:
22+
maxAlignment: 1
23+
hasCalls: true
24+
savePoint: '%bb.1'
25+
restorePoint: '%bb.1'
26+
machineFunctionInfo: {}
27+
body: |
28+
bb.0:
29+
liveins: $edi
30+
31+
TEST8rr renamable $dil, renamable $dil, implicit-def $eflags, implicit killed $edi
32+
JCC_1 %bb.2, 4, implicit killed $eflags
33+
JMP_1 %bb.1
34+
35+
bb.1:
36+
renamable $rbx = IMPLICIT_DEF
37+
renamable $r14 = IMPLICIT_DEF
38+
renamable $r15 = IMPLICIT_DEF
39+
renamable $r12 = IMPLICIT_DEF
40+
renamable $r13 = IMPLICIT_DEF
41+
dead $eax = MOV32r0 implicit-def dead $eflags, implicit-def $rax
42+
RET 0, killed $rax
43+
44+
bb.2:
45+
dead $eax = MOV32r0 implicit-def dead $eflags, implicit-def $rax
46+
RET 0, killed $rax
47+
48+
...
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# RUN: llc -o - %s -mtriple=x86_64-- -run-pass=prologepilog 2>&1 | FileCheck %s
2+
--- |
3+
declare dso_local void @_Z3goov()
4+
define i64 @_Z3foob(i1 zeroext %cond) #0 {
5+
ret i64 0
6+
}
7+
attributes #0 = {"frame-pointer"="all"}
8+
...
9+
---
10+
# If the epilogue bb.1.if.then is not a return block, .cfi_restore is
11+
# needed in it, otherwise bb.2.return will see different outgoing CFI
12+
# information from its predecessors.
13+
# CHECK: bb.1:
14+
# CHECK: CFI_INSTRUCTION restore $rbx
15+
# CHECK-NEXT: CFI_INSTRUCTION restore $r12
16+
# CHECK-NEXT: CFI_INSTRUCTION restore $r13
17+
# CHECK-NEXT: CFI_INSTRUCTION restore $r14
18+
# CHECK-NEXT: CFI_INSTRUCTION restore $r15
19+
# CHECK-NEXT: CFI_INSTRUCTION restore $rbp
20+
# CHECK-NOT: RET 0
21+
# CHECK: bb.2:
22+
# CHECK: RET 0
23+
name: _Z3foob
24+
alignment: 16
25+
tracksRegLiveness: true
26+
liveins:
27+
- { reg: '$edi' }
28+
frameInfo:
29+
maxAlignment: 1
30+
hasCalls: true
31+
savePoint: '%bb.1'
32+
restorePoint: '%bb.1'
33+
machineFunctionInfo: {}
34+
body: |
35+
bb.0:
36+
liveins: $edi
37+
38+
TEST8rr renamable $dil, renamable $dil, implicit-def $eflags, implicit killed $edi
39+
JCC_1 %bb.2, 4, implicit killed $eflags
40+
JMP_1 %bb.1
41+
42+
bb.1:
43+
renamable $rbx = IMPLICIT_DEF
44+
renamable $r14 = IMPLICIT_DEF
45+
renamable $r15 = IMPLICIT_DEF
46+
renamable $r12 = IMPLICIT_DEF
47+
renamable $r13 = IMPLICIT_DEF
48+
49+
bb.2:
50+
dead $eax = MOV32r0 implicit-def dead $eflags, implicit-def $rax
51+
RET 0, killed $rax
52+
53+
...
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# RUN: llc -o - %s -mtriple=x86_64-- -verify-cfiinstrs \
2+
# RUN: -run-pass=cfi-instr-inserter 2>&1 | FileCheck %s
3+
# Test that CFI inserter inserts .cfi_restore properly for
4+
# callee saved registers.
5+
--- |
6+
define void @foo() {
7+
ret void
8+
}
9+
...
10+
---
11+
# CHECK: bb.3:
12+
# CHECK: CFI_INSTRUCTION restore $rbx
13+
# CHECK-NEXT: CFI_INSTRUCTION restore $rbp
14+
name: foo
15+
body: |
16+
bb.0:
17+
TEST8rr renamable $dil, renamable $dil, implicit-def $eflags, implicit killed $edi
18+
JCC_1 %bb.2, 5, implicit killed $eflags
19+
20+
bb.1:
21+
JMP_1 %bb.3
22+
23+
bb.2:
24+
CFI_INSTRUCTION def_cfa_offset 16
25+
CFI_INSTRUCTION offset $rbp, -16
26+
CFI_INSTRUCTION def_cfa_register $rbp
27+
CFI_INSTRUCTION offset $rbx, -24
28+
CFI_INSTRUCTION def_cfa $rsp, 8
29+
RET 0, $rax
30+
31+
bb.3:
32+
RET 0, $rax
33+
34+
...

0 commit comments

Comments
 (0)