diff --git a/llvm/lib/MC/MCSFrame.cpp b/llvm/lib/MC/MCSFrame.cpp index 066d1a34e1548..910fcab7b4d75 100644 --- a/llvm/lib/MC/MCSFrame.cpp +++ b/llvm/lib/MC/MCSFrame.cpp @@ -111,6 +111,8 @@ struct SFrameFDE { MCFragment *Frag; // Unwinding fres SmallVector FREs; + // .cfi_remember_state stack + SmallVector SaveState; SFrameFDE(const MCDwarfFrameInfo &DF, MCSymbol *FRES) : DFrame(DF), FREStart(FRES), Frag(nullptr) {} @@ -237,13 +239,30 @@ 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.pop_back_val(); return true; case MCCFIInstruction::OpEscape: // TODO: Implement. Will use FDE. @@ -394,8 +413,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)); } 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