[llvm] [CFIFixup] Fixup CFI for split functions with synchronous uwtables (PR #125299)
Daniel Hoekwater via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 10 12:04:44 PST 2025
https://github.com/dhoekwater updated https://github.com/llvm/llvm-project/pull/125299
>From 2e9b586f54d6a889e08cdd52c3d84b8c60dde908 Mon Sep 17 00:00:00 2001
From: Daniel Hoekwater <hoekwater at google.com>
Date: Fri, 31 Jan 2025 21:04:55 +0000
Subject: [PATCH 1/2] Precommit tests for synchronous uwtable CFI fixup
---
.../AArch64/cfi-fixup-multi-section.mir | 183 ++++++++++++++++++
1 file changed, 183 insertions(+)
diff --git a/llvm/test/CodeGen/AArch64/cfi-fixup-multi-section.mir b/llvm/test/CodeGen/AArch64/cfi-fixup-multi-section.mir
index a24972d1388320f..fbced223429e8fa 100644
--- a/llvm/test/CodeGen/AArch64/cfi-fixup-multi-section.mir
+++ b/llvm/test/CodeGen/AArch64/cfi-fixup-multi-section.mir
@@ -10,9 +10,19 @@
ret i32 0
}
+ define i32 @f1(i32 %x) #1 {
+ entry: br label %return
+ if.end: br label %return
+ if.then2: br label %return
+ if.else: br label %return
+ return:
+ ret i32 0
+ }
+
declare i32 @g(i32)
attributes #0 = { nounwind shadowcallstack uwtable "sign-return-address"="non-leaf" "target-features"="+reserve-x18" }
+ attributes #1 = { nounwind shadowcallstack uwtable(sync) "sign-return-address"="non-leaf" "target-features"="+reserve-x18" }
...
---
@@ -197,4 +207,177 @@ body: |
B %bb.7
+...
+---
+name: f1
+alignment: 4
+exposesReturnsTwice: false
+legalized: false
+regBankSelected: false
+selected: false
+failedISel: false
+tracksRegLiveness: true
+hasWinCFI: false
+failsVerification: false
+registers: []
+liveins:
+ - { reg: '$w0', virtual-reg: '' }
+frameInfo:
+ isFrameAddressTaken: false
+ isReturnAddressTaken: false
+ hasStackMap: false
+ hasPatchPoint: false
+ stackSize: 16
+ offsetAdjustment: 0
+ maxAlignment: 16
+ adjustsStack: true
+ hasCalls: true
+ stackProtector: ''
+ maxCallFrameSize: 0
+ cvBytesOfCalleeSavedRegisters: 0
+ hasOpaqueSPAdjustment: false
+ hasVAStart: false
+ hasMustTailInVarArgFunc: false
+ hasTailCall: false
+ localFrameSize: 0
+ savePoint: ''
+ restorePoint: ''
+fixedStack: []
+stack:
+ - { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 16,
+ stack-id: default, callee-saved-register: '$lr', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+callSites: []
+debugValueSubstitutions: []
+constants: []
+body: |
+ ; CHECK-LABEL: name: f1
+ ; CHECK: bb.0.entry:
+ ; CHECK-NEXT: successors: %bb.4(0x30000000), %bb.1(0x50000000)
+ ; CHECK-NEXT: liveins: $w0, $lr, $x18
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: CBZW renamable $w0, %bb.4
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.1.if.end:
+ ; CHECK-NEXT: successors: %bb.3(0x30000000), %bb.2(0x50000000)
+ ; CHECK-NEXT: liveins: $w0, $lr, $x18
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: early-clobber $x18 = frame-setup STRXpost $lr, $x18, 8
+ ; CHECK-NEXT: frame-setup CFI_INSTRUCTION escape 0x16, 0x12, 0x02, 0x82, 0x78
+ ; CHECK-NEXT: frame-setup PACIASP implicit-def $lr, implicit killed $lr, implicit $sp
+ ; CHECK-NEXT: frame-setup CFI_INSTRUCTION negate_ra_sign_state
+ ; CHECK-NEXT: early-clobber $sp = frame-setup STRXpre killed $lr, $sp, -16 :: (store (s64) into %stack.0)
+ ; CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
+ ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $w30, -16
+ ; CHECK-NEXT: TBNZW renamable $w0, 31, %bb.3
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.2.if.else:
+ ; CHECK-NEXT: successors: %bb.5(0x80000000)
+ ; CHECK-NEXT: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: renamable $w0 = nuw nsw ADDWri killed renamable $w0, 1, 0
+ ; CHECK-NEXT: BL @g, csr_aarch64_aapcs_scs, implicit-def dead $lr, implicit $sp, implicit killed $w0, implicit-def $sp, implicit-def $w0
+ ; CHECK-NEXT: renamable $w8 = MOVZWi 1, 0
+ ; CHECK-NEXT: $w0 = SUBWrs killed renamable $w8, killed renamable $w0, 0
+ ; CHECK-NEXT: B %bb.5
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.3.if.then2 (bbsections 1):
+ ; CHECK-NEXT: successors: %bb.5(0x80000000)
+ ; CHECK-NEXT: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: renamable $w0 = nsw SUBWri killed renamable $w0, 1, 0
+ ; CHECK-NEXT: BL @g, csr_aarch64_aapcs_scs, implicit-def dead $lr, implicit $sp, implicit killed $w0, implicit-def $sp, implicit-def $w0
+ ; CHECK-NEXT: renamable $w0 = nsw ADDWri killed renamable $w0, 1, 0
+ ; CHECK-NEXT: B %bb.5
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.4.return:
+ ; CHECK-NEXT: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: RET undef $lr, implicit killed $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.5.return:
+ ; CHECK-NEXT: successors: %bb.7(0x80000000)
+ ; CHECK-NEXT: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: B %bb.7
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.6.return:
+ ; CHECK-NEXT: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
+ ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+ ; CHECK-NEXT: frame-destroy AUTIASP implicit-def $lr, implicit killed $lr, implicit $sp
+ ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION negate_ra_sign_state
+ ; CHECK-NEXT: early-clobber $x18, $lr = frame-destroy LDRXpre $x18, -8
+ ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $w18
+ ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $w30
+ ; CHECK-NEXT: RET undef $lr, implicit killed $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.7.return:
+ ; CHECK-NEXT: successors: %bb.6(0x80000000)
+ ; CHECK-NEXT: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: B %bb.6
+ bb.0.entry:
+ successors: %bb.4(0x30000000), %bb.1(0x50000000)
+ liveins: $w0, $lr, $x18
+
+ CBZW renamable $w0, %bb.4
+
+ bb.1.if.end:
+ successors: %bb.3(0x30000000), %bb.2(0x50000000)
+ liveins: $w0, $lr, $x18
+
+ early-clobber $x18 = frame-setup STRXpost $lr, $x18, 8
+ frame-setup CFI_INSTRUCTION escape 0x16, 0x12, 0x02, 0x82, 0x78
+ frame-setup PACIASP implicit-def $lr, implicit killed $lr, implicit $sp
+ frame-setup CFI_INSTRUCTION negate_ra_sign_state
+ early-clobber $sp = frame-setup STRXpre killed $lr, $sp, -16 :: (store (s64) into %stack.0)
+ frame-setup CFI_INSTRUCTION def_cfa_offset 16
+ frame-setup CFI_INSTRUCTION offset $w30, -16
+ TBNZW renamable $w0, 31, %bb.3
+
+ bb.2.if.else:
+ successors: %bb.5(0x80000000)
+ liveins: $w0
+
+ renamable $w0 = nuw nsw ADDWri killed renamable $w0, 1, 0
+ BL @g, csr_aarch64_aapcs_scs, implicit-def dead $lr, implicit $sp, implicit killed $w0, implicit-def $sp, implicit-def $w0
+ renamable $w8 = MOVZWi 1, 0
+ $w0 = SUBWrs killed renamable $w8, killed renamable $w0, 0
+ B %bb.5
+
+ bb.3.if.then2 (bbsections 1):
+ successors: %bb.5(0x80000000)
+ liveins: $w0
+
+ renamable $w0 = nsw SUBWri killed renamable $w0, 1, 0
+ BL @g, csr_aarch64_aapcs_scs, implicit-def dead $lr, implicit $sp, implicit killed $w0, implicit-def $sp, implicit-def $w0
+ renamable $w0 = nsw ADDWri killed renamable $w0, 1, 0
+ B %bb.5
+
+ bb.4.return:
+ liveins: $w0
+ RET undef $lr, implicit killed $w0
+
+ bb.5.return:
+ liveins: $w0
+ B %bb.6
+
+ bb.7.return:
+ liveins: $w0
+ early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
+ frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+ frame-destroy AUTIASP implicit-def $lr, implicit killed $lr, implicit $sp
+ frame-destroy CFI_INSTRUCTION negate_ra_sign_state
+ early-clobber $x18, $lr = frame-destroy LDRXpre $x18, -8
+ frame-destroy CFI_INSTRUCTION restore $w18
+ frame-destroy CFI_INSTRUCTION restore $w30
+ RET undef $lr, implicit killed $w0
+
+ bb.6.return:
+ liveins: $w0
+ B %bb.7
+
+
...
>From b29f23bb2f8880da55e3888aa5747e80435a687a Mon Sep 17 00:00:00 2001
From: Daniel Hoekwater <hoekwater at google.com>
Date: Fri, 31 Jan 2025 21:17:08 +0000
Subject: [PATCH 2/2] [CFIFixup] Fixup CFI for split functions with synchronous
uwtables
Commit 6e54fccede402c9ed0e8038aa258a99c5a2773e5 disables CFI fixup for
functions with synchronous tables, breaking CFI for split functions.
Instead, we can disable *block-level* CFI fixup for functions with
synchronous tables.
Unwind tables can be:
- N/A (not present)
- Asynchronous
- Synchronous
Functions without unwind tables don't need CFI fixup (since they don't
care about CFI).
Functions with asynchronous unwind tables need to be accurate for each
individual instruction, so full CFI fixup is necessary.
Functions with synchronous unwind tables only need to be accurate at
specific points where they may trigger unwinding. This property relaxes
the requirements for these functions, and
6e54fccede402c9ed0e8038aa258a99c5a2773e5 takes advantage of the relaxed
requirements to emit fewer CFI instructions and skip CFI fixup in this
case. However, disabling CFI fixup entirely for functions with
synchronous uwtables may break CFI for a function split between two
sections. The portion in the first section may have valid CFI, while the
portion in the second section is missing a call frame.
Ex:
```
(.text.hot)
Foo (BB1):
<Call frame information>
...
BB2:
...
(.text.split)
BB3:
...
BB4:
<epilogue>
```
Even if `Foo` has a synchronous unwind table, we still need to insert
call frame information into `BB3` so that unwinding the call stack from
`BB3` or `BB4` works properly.
---
llvm/include/llvm/CodeGen/TargetFrameLowering.h | 11 +++++++++--
llvm/lib/CodeGen/CFIFixup.cpp | 6 ++++++
llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp | 2 +-
llvm/lib/Target/AArch64/AArch64FrameLowering.cpp | 7 ++++++-
llvm/lib/Target/AArch64/AArch64FrameLowering.h | 4 +++-
llvm/test/CodeGen/AArch64/cfi-fixup-multi-section.mir | 4 ++++
6 files changed, 29 insertions(+), 5 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/TargetFrameLowering.h b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
index 97de0197da9b400..cdbefb36c00c766 100644
--- a/llvm/include/llvm/CodeGen/TargetFrameLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
@@ -229,10 +229,17 @@ class TargetFrameLowering {
/// Returns true if we may need to fix the unwind information for the
/// function.
- virtual bool enableCFIFixup(MachineFunction &MF) const;
+ virtual bool enableCFIFixup(const MachineFunction &MF) const;
+
+ /// enableFullCFIFixup - Returns true if we may need to fix the unwind
+ /// information such that it is accurate for *every* instruction in the
+ /// function (e.g. if the function has an async unwind table).
+ virtual bool enableFullCFIFixup(const MachineFunction &MF) const {
+ return enableCFIFixup(MF);
+ };
/// Emit CFI instructions that recreate the state of the unwind information
- /// upon fucntion entry.
+ /// upon function entry.
virtual void resetCFIToInitialState(MachineBasicBlock &MBB) const {}
/// Replace a StackProbe stub (if any) with the actual probe code inline
diff --git a/llvm/lib/CodeGen/CFIFixup.cpp b/llvm/lib/CodeGen/CFIFixup.cpp
index 7986f7d2134542d..eaef14574385ab1 100644
--- a/llvm/lib/CodeGen/CFIFixup.cpp
+++ b/llvm/lib/CodeGen/CFIFixup.cpp
@@ -80,6 +80,7 @@
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCDwarf.h"
+#include "llvm/Support/CodeGen.h"
#include "llvm/Target/TargetMachine.h"
#include <iterator>
@@ -252,6 +253,11 @@ fixupBlock(MachineBasicBlock &CurrBB, const BlockFlagsVector &BlockInfo,
if (!Info.Reachable)
return false;
+ // If we don't need to perform full CFI fix up, we only need to fix up the
+ // first basic block in the section.
+ if (!TFL.enableFullCFIFixup(MF) && !CurrBB.isBeginSection())
+ return false;
+
// If the previous block and the current block are in the same section,
// the frame info will propagate from the previous block to the current one.
const BlockFlags &PrevInfo =
diff --git a/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp b/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
index 08e86c705786c74..5784974cd8ed985 100644
--- a/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
+++ b/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
@@ -35,7 +35,7 @@ bool TargetFrameLowering::enableCalleeSaveSkip(const MachineFunction &MF) const
return false;
}
-bool TargetFrameLowering::enableCFIFixup(MachineFunction &MF) const {
+bool TargetFrameLowering::enableCFIFixup(const MachineFunction &MF) const {
return MF.needsFrameMoves() &&
!MF.getTarget().getMCAsmInfo()->usesWindowsCFI();
}
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index d3abd79b85a75f7..d118022395762f7 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -2612,8 +2612,13 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
}
}
-bool AArch64FrameLowering::enableCFIFixup(MachineFunction &MF) const {
+bool AArch64FrameLowering::enableCFIFixup(const MachineFunction &MF) const {
return TargetFrameLowering::enableCFIFixup(MF) &&
+ MF.getInfo<AArch64FunctionInfo>()->needsDwarfUnwindInfo(MF);
+}
+
+bool AArch64FrameLowering::enableFullCFIFixup(const MachineFunction &MF) const {
+ return enableCFIFixup(MF) &&
MF.getInfo<AArch64FunctionInfo>()->needsAsyncDwarfUnwindInfo(MF);
}
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.h b/llvm/lib/Target/AArch64/AArch64FrameLowering.h
index 8f84702f4d2baff..e7d52bb350f1363 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.h
@@ -36,7 +36,9 @@ class AArch64FrameLowering : public TargetFrameLowering {
void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
- bool enableCFIFixup(MachineFunction &MF) const override;
+ bool enableCFIFixup(const MachineFunction &MF) const override;
+
+ bool enableFullCFIFixup(const MachineFunction &MF) const override;
bool canUseAsPrologue(const MachineBasicBlock &MBB) const override;
diff --git a/llvm/test/CodeGen/AArch64/cfi-fixup-multi-section.mir b/llvm/test/CodeGen/AArch64/cfi-fixup-multi-section.mir
index fbced223429e8fa..a4c88be375c0148 100644
--- a/llvm/test/CodeGen/AArch64/cfi-fixup-multi-section.mir
+++ b/llvm/test/CodeGen/AArch64/cfi-fixup-multi-section.mir
@@ -285,6 +285,10 @@ body: |
; CHECK-NEXT: successors: %bb.5(0x80000000)
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: frame-setup CFI_INSTRUCTION escape 0x16, 0x12, 0x02, 0x82, 0x78
+ ; CHECK-NEXT: frame-setup CFI_INSTRUCTION negate_ra_sign_state
+ ; CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
+ ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $w30, -16
; CHECK-NEXT: renamable $w0 = nsw SUBWri killed renamable $w0, 1, 0
; CHECK-NEXT: BL @g, csr_aarch64_aapcs_scs, implicit-def dead $lr, implicit $sp, implicit killed $w0, implicit-def $sp, implicit-def $w0
; CHECK-NEXT: renamable $w0 = nsw ADDWri killed renamable $w0, 1, 0
More information about the llvm-commits
mailing list