[llvm] [SFrames] Implement .cfi_restore, remember_state, and restore_state (PR #159832)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 19 11:45:55 PDT 2025
https://github.com/Sterling-Augustine created https://github.com/llvm/llvm-project/pull/159832
As in the description. Very straightforward.
>From 2b24cc6a3337490f12aac32582b218097d37da42 Mon Sep 17 00:00:00 2001
From: Sterling Augustine <saugustine at google.com>
Date: Fri, 19 Sep 2025 11:44:05 -0700
Subject: [PATCH] [SFrames] Implement .cfi_restore, .cfi_remember_state, and
.cfi_restore_state
As in the description. Very straightforward.
---
llvm/lib/MC/MCSFrame.cpp | 30 +++++--
llvm/test/MC/ELF/cfi-sframe-fre-cases.s | 110 +++++++++++++++++++-----
2 files changed, 115 insertions(+), 25 deletions(-)
diff --git a/llvm/lib/MC/MCSFrame.cpp b/llvm/lib/MC/MCSFrame.cpp
index 066d1a34e1548..ef6700fb1dccf 100644
--- a/llvm/lib/MC/MCSFrame.cpp
+++ b/llvm/lib/MC/MCSFrame.cpp
@@ -111,6 +111,8 @@ struct SFrameFDE {
MCFragment *Frag;
// Unwinding fres
SmallVector<SFrameFRE> FREs;
+ // .cfi_remember_state stack
+ SmallVector<SFrameFRE> SaveState;
SFrameFDE(const MCDwarfFrameInfo &DF, MCSymbol *FRES)
: DFrame(DF), FREStart(FRES), Frag(nullptr) {}
@@ -237,13 +239,31 @@ class SFrameEmitterImpl {
case MCCFIInstruction::OpAdjustCfaOffset:
return setCFAOffset(FRE, CFI.getLoc(), FRE.CFAOffset + CFI.getOffset());
case MCCFIInstruction::OpRememberState:
- // TODO: Implement. Will use FDE.
+ if (FDE.FREs.size() == 1) {
+ // Error for gas compatibility: If the initial FRE isn't complete,
+ // then any state is incomplete. FIXME: Dwarf doesn't error here.
+ // Why should sframe?
+ Streamer.getContext().reportWarning(
+ CFI.getLoc(), "skipping SFrame FDE; .cfi_remember_state without "
+ "prior SFrame FRE state");
+ return false;
+ }
+ FDE.SaveState.push_back(FRE);
return true;
case MCCFIInstruction::OpRestore:
- // TODO: Implement. Will use FDE.
+ // The first FRE generated has the original state.
+ if (CFI.getRegister() == FPReg)
+ FRE.FPOffset = FDE.FREs.front().FPOffset;
+ else if (CFI.getRegister() == RAReg)
+ FRE.RAOffset = FDE.FREs.front().RAOffset;
return true;
case MCCFIInstruction::OpRestoreState:
- // TODO: Implement. Will use FDE.
+ // The cfi parser will have caught unbalanced directives earlier, so a
+ // mismatch here is an implementation error.
+ assert(!FDE.SaveState.empty() &&
+ "cfi_restore_state without cfi_save_state");
+ FRE = FDE.SaveState.back();
+ FDE.SaveState.pop_back();
return true;
case MCCFIInstruction::OpEscape:
// TODO: Implement. Will use FDE.
@@ -394,8 +414,8 @@ class SFrameEmitterImpl {
// shf_fdeoff. With no sfh_auxhdr, these immediately follow this header.
Streamer.emitInt32(0);
// shf_freoff
- Streamer.emitAbsoluteSymbolDiff(FRESubSectionStart, FDESubSectionStart,
- sizeof(uint32_t));
+ Streamer.emitInt32(FDEs.size() *
+ sizeof(sframe::FuncDescEntry<endianness::native>));
}
void emitFDEs() {
diff --git a/llvm/test/MC/ELF/cfi-sframe-fre-cases.s b/llvm/test/MC/ELF/cfi-sframe-fre-cases.s
index 6d9e8c1b6480f..eeaa4021ceefd 100644
--- a/llvm/test/MC/ELF/cfi-sframe-fre-cases.s
+++ b/llvm/test/MC/ELF/cfi-sframe-fre-cases.s
@@ -17,7 +17,7 @@ fde4_fre_offset_sizes:
# CHECK: FuncDescEntry [0] {
# CHECK: Start FRE Offset: 0
# CHECK: FRE Type: Addr1 (0x0)
- .cfi_startproc
+ .cfi_startproc
# CHECK: Frame Row Entry {
# CHECK-NEXT: Start Address: 0x0
# CHECK-NEXT: Return Address Signed: No
@@ -27,9 +27,9 @@ fde4_fre_offset_sizes:
# CHECK-NEXT: RA Offset: -8
.long 0
# Uninteresting register no new fre, no effect on cfa
- .cfi_offset 0, 8
+ .cfi_offset 0, 8
.long 0
- .cfi_def_cfa_offset 0x78
+ .cfi_def_cfa_offset 0x78
# CHECK: Frame Row Entry {
# CHECK-NEXT: Start Address: 0x8
# CHECK-NEXT: Return Address Signed: No
@@ -37,11 +37,11 @@ fde4_fre_offset_sizes:
# CHECK-NEXT: Base Register: SP (0x1)
# CHECK-NEXT: CFA Offset: 120
# CHECK-NEXT: RA Offset: -8
- .long 0
+ .long 0
# Uninteresting register no new fre, no effect on cfa
.cfi_rel_offset 1, 8
.long 0
- .cfi_def_cfa_offset 0x80
+ .cfi_def_cfa_offset 0x80
# CHECK: Frame Row Entry {
# CHECK-NEXT: Start Address: 0x10
# CHECK-NEXT: Return Address Signed: No
@@ -49,11 +49,11 @@ fde4_fre_offset_sizes:
# CHECK-NEXT: Base Register: SP (0x1)
# CHECK-NEXT: CFA Offset: 128
# CHECK-NEXT: RA Offset: -8
- .long 0
+ .long 0
# Uninteresting register no new fre, no effect on cfa
.cfi_val_offset 1, 8
.long 0
- .cfi_def_cfa_offset 0x7FFF
+ .cfi_def_cfa_offset 0x7FFF
# CHECK: Frame Row Entry {
# CHECK-NEXT: Start Address: 0x18
# CHECK-NEXT: Return Address Signed: No
@@ -61,8 +61,8 @@ fde4_fre_offset_sizes:
# CHECK-NEXT: Base Register: SP (0x1)
# CHECK-NEXT: CFA Offset: 32767
# CHECK-NEXT: RA Offset: -8
- .long 0
- .cfi_def_cfa_offset 0x8000
+ .long 0
+ .cfi_def_cfa_offset 0x8000
# CHECK: Frame Row Entry {
# CHECK-NEXT: Start Address: 0x1C
# CHECK-NEXT: Return Address Signed: No
@@ -70,8 +70,8 @@ fde4_fre_offset_sizes:
# CHECK-NEXT: Base Register: SP (0x1)
# CHECK-NEXT: CFA Offset: 32768
# CHECK-NEXT: RA Offset: -8
- .long 0
- .cfi_def_cfa_offset 0x8
+ .long 0
+ .cfi_def_cfa_offset 0x8
# CHECK: Frame Row Entry {
# CHECK-NEXT: Start Address: 0x20
# CHECK-NEXT: Return Address Signed: No
@@ -79,8 +79,8 @@ fde4_fre_offset_sizes:
# CHECK-NEXT: Base Register: SP (0x1)
# CHECK-NEXT: CFA Offset: 8
# CHECK-NEXT: RA Offset: -8
- .long 0
- .cfi_adjust_cfa_offset 0x8
+ .long 0
+ .cfi_adjust_cfa_offset 0x8
# CHECK: Frame Row Entry {
# CHECK-NEXT: Start Address: 0x24
# CHECK-NEXT: Return Address Signed: No
@@ -88,8 +88,8 @@ fde4_fre_offset_sizes:
# CHECK-NEXT: Base Register: SP (0x1)
# CHECK-NEXT: CFA Offset: 16
# CHECK-NEXT: RA Offset: -8
- .long 0
- .cfi_def_cfa_register 6 # switch to fp
+ .long 0
+ .cfi_def_cfa_register 6 # switch to fp
# CHECK: Frame Row Entry {
# CHECK-NEXT: Start Address: 0x28
# CHECK-NEXT: Return Address Signed: No
@@ -97,10 +97,10 @@ fde4_fre_offset_sizes:
# CHECK-NEXT: Base Register: FP (0x0)
# CHECK-NEXT: CFA Offset: 16
# CHECK-NEXT: RA Offset: -8
- .long 0
- .cfi_offset 7, 32
- # sp not the cfa but with large offset still changes encoding.
- .cfi_offset 6, 0x7FF8
+ .long 0
+ .cfi_offset 7, 32
+ # sp not the cfa but with large offset still changes encoding.
+ .cfi_offset 6, 0x7FF8
# CHECK: Frame Row Entry {
# CHECK-NEXT: Start Address: 0x2C
# CHECK-NEXT: Return Address Signed: No
@@ -109,5 +109,75 @@ fde4_fre_offset_sizes:
# CHECK-NEXT: CFA Offset: 16
# CHECK-NEXT: RA Offset: -8
# CHECK-NEXT: FP Offset: 32760
- .long 0
+ .long 0
+ .cfi_endproc
+
+ .align 1024
+restore_reg:
+# CHECK: FuncDescEntry [1] {
+# CHECK: Start FRE Offset: 0x23
+# CHECK-NEXT: Num FREs: 3
+ .cfi_startproc
+# CHECK: Frame Row Entry {
+# CHECK-NEXT: Start Address: 0x400
+# CHECK-NOT FP Offset{{.*}}
+# CHECK: }
+ .long 0
+ .cfi_offset 6, 32
+# CHECK Frame Row Entry {
+# CHECK-NEXT Start Address: 0x404
+# CHECK: FP Offset: 32
+ .long 0
+ .cfi_restore 6
+# CHECK: Frame Row Entry {
+# CHECK-NEXT: Start Address: 0x408
+# CHECK-NOT FP Offset{{.*}}
+# CHECK: }
+ .long 0
+ .cfi_endproc
+
+ .align 1024
+remember_restore_state:
+# CHECK: FuncDescEntry [2] {
+# CHECK: Start FRE Offset: 0x2D
+# CHECK-NEXT: Num FREs: 4
+ .cfi_startproc
+# CHECK: Frame Row Entry {
+# CHECK-NEXT: Start Address: 0x800
+# CHECK-NOT FP Offset{{.*}}
+# CHECK: }
+ .long 0
+ .cfi_offset 6, 8
+ .cfi_offset 7, 16
+ .cfi_offset 8, 24
+# CHECK: Frame Row Entry {
+# CHECK-NEXT: Start Address: 0x804
+# CHECK: Base Register: SP (0x1)
+# CHECK-NEXT: CFA Offset: 8
+# CHECK-NEXT: RA Offset: -8
+# CHECK-NEXT: FP Offset: 8
+# CHECK-NEXT: }
+ .long 0
+ .cfi_remember_state
+# CHECK: Frame Row Entry {
+# CHECK-NEXT: Start Address: 0x808
+# CHECK: Base Register: SP (0x1)
+# CHECK-NEXT: CFA Offset: 8
+# CHECK-NEXT: RA Offset: -8
+# CHECK-NEXT: FP Offset: 32
+# CHECK-NEXT: }
+ .cfi_offset 6, 32
+ .cfi_offset 7, 40
+ .cfi_offset 8, 48
+ .long 0
+# CHECK: Frame Row Entry {
+# CHECK-NEXT: Start Address: 0x80C
+# CHECK: Base Register: SP (0x1)
+# CHECK-NEXT: CFA Offset: 8
+# CHECK-NEXT: RA Offset: -8
+# CHECK-NEXT: FP Offset: 8
+# CHECK-NEXT: }
+ .cfi_restore_state
+ .long 0
+
.cfi_endproc
More information about the llvm-commits
mailing list