Index: lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp @@ -246,6 +246,12 @@ case MCCFIInstruction::OpRestore: OutStreamer->EmitCFIRestore(Inst.getRegister()); break; + case MCCFIInstruction::OpRememberState: + OutStreamer->EmitCFIRememberState(); + break; + case MCCFIInstruction::OpRestoreState: + OutStreamer->EmitCFIRestoreState(); + break; } } Index: lib/CodeGen/CFIInstrInserter.cpp =================================================================== --- lib/CodeGen/CFIInstrInserter.cpp +++ lib/CodeGen/CFIInstrInserter.cpp @@ -162,6 +162,13 @@ const std::vector &Instrs = MBBInfo.MBB->getParent()->getFrameInstructions(); + // Remembered cfa register and offset, for cfi_remember_state + // and cfi_restore_state. Currently we only support at most + // one pair of cfi_remember_state and cfi_restore_state in a + // block. + unsigned RememberedReg = ~0u; + int RememberedOffset = 0; + // Determine cfa offset and register set by the block. for (MachineInstr &MI : *MBBInfo.MBB) { if (MI.isCFIInstruction()) { @@ -182,19 +189,27 @@ SetOffset = CFI.getOffset(); break; case MCCFIInstruction::OpRememberState: - // TODO: Add support for handling cfi_remember_state. + if (RememberedReg == ~0u) { + RememberedReg = SetRegister; + RememberedOffset = SetOffset; + break; + } #ifndef NDEBUG report_fatal_error( - "Support for cfi_remember_state not implemented! Value of CFA " - "may be incorrect!\n"); + "Support for multiple cfi_remember_state not implemented! " + "Value of CFA may be incorrect!\n"); #endif break; case MCCFIInstruction::OpRestoreState: - // TODO: Add support for handling cfi_restore_state. + if (RememberedReg != ~0u) { + SetRegister = RememberedReg; + SetOffset = RememberedOffset; + break; + } #ifndef NDEBUG report_fatal_error( - "Support for cfi_restore_state not implemented! Value of CFA may " - "be incorrect!\n"); + "Support for cfi_restore_state without cfi_remember_state not " + "implemented! Value of CFA may be incorrect!\n"); #endif break; // Other CFI directives do not affect CFA value. Index: lib/Target/X86/X86FrameLowering.cpp =================================================================== --- lib/Target/X86/X86FrameLowering.cpp +++ lib/Target/X86/X86FrameLowering.cpp @@ -2575,6 +2575,47 @@ else BuildMI(allocMBB, DL, TII.get(X86::MORESTACK_RET)); + // allocMBB is still in the function prologue, and we haven't pushed + // callee-save registers and the frame pointer (if used) yet. But it + // may be laid out in the middle or the end of the function. We need + // to restore the unwind info for pushed registers. + // We use cfi_remember_state and cfi_restore_state to ensure blocks + // laid out before and after it are not affected. + const Function &Fn = MF.getFunction(); + MachineModuleInfo &MMI = MF.getMMI(); + bool IsWin64Prologue = MF.getTarget().getMCAsmInfo()->usesWindowsCFI(); + bool NeedsDwarfCFI = + !IsWin64Prologue && (MMI.hasDebugInfo() || Fn.needsUnwindTableEntry()); + if (NeedsDwarfCFI) { + auto MBBI = allocMBB->begin(); + BuildCFI(*allocMBB, MBBI, DL, + MCCFIInstruction::createRememberState(nullptr)); + + // Restore the frame pointer + bool HasFP = hasFP(MF); + if (HasFP) { + unsigned FramePtr = TRI->getFrameRegister(MF); + const unsigned MachineFramePtr = STI.isTarget64BitILP32() ? + getX86SubSuperRegister(FramePtr, 64) : FramePtr; + unsigned DwarfFramePtr = TRI->getDwarfRegNum(MachineFramePtr, true); + BuildCFI(*allocMBB, MBBI, DL, + MCCFIInstruction::createRestore(nullptr, DwarfFramePtr)); + } + + // Restore callee-save registers. + const std::vector &CSI = MFI.getCalleeSavedInfo(); + for (std::vector::const_iterator + I = CSI.begin(), E = CSI.end(); I != E; ++I) { + unsigned Reg = I->getReg(); + unsigned DwarfReg = TRI->getDwarfRegNum(Reg, true); + BuildCFI(*allocMBB, MBBI, DL, + MCCFIInstruction::createRestore(nullptr, DwarfReg)); + } + + BuildCFI(*allocMBB, allocMBB->end(), DL, + MCCFIInstruction::createRestoreState(nullptr)); + } + allocMBB->addSuccessor(&PrologueMBB); checkMBB->addSuccessor(allocMBB, BranchProbability::getZero()); Index: test/CodeGen/X86/segmented-stacks.ll =================================================================== --- test/CodeGen/X86/segmented-stacks.ll +++ test/CodeGen/X86/segmented-stacks.ll @@ -727,7 +727,74 @@ } +; Test that we have correct unwind info for the block +; that calls morestack. + +define void @test_cfi(i32 %x) #1 { + %mem = alloca i32, i32 10 + call void @dummy_use (i32* %mem, i32 %x) + ret void + +; X32-Linux-LABEL: test_cfi: +; X32-Linux: .cfi_remember_state +; X32-Linux: .cfi_restore %ebp +; X32-Linux: calll __morestack +; X32-Linux: retl +; X32-Linux: .cfi_restore_state + +; X64-Linux-LABEL: test_cfi: +; X64-Linux: .cfi_remember_state +; X64-Linux: .cfi_restore %rbp +; X64-Linux: callq __morestack +; X64-Linux: retq +; X64-Linux: .cfi_restore_state + +; X32ABI-Linux-LABEL: test_cfi: +; X32ABI-Linux: .cfi_remember_state +; X32ABI-Linux: .cfi_restore %rbp +; X32ABI-Linux: callq __morestack +; X32ABI-Linux: retq +; X32ABI-Linux: .cfi_restore_state + +; X32-Darwin-LABEL: test_cfi: +; X32-Darwin: .cfi_remember_state +; X32-Darwin: .cfi_restore %ebp +; X32-Darwin: calll ___morestack +; X32-Darwin: retl +; X32-Darwin: .cfi_restore_state + +; X64-Darwin-LABEL: test_cfi: +; X64-Darwin: .cfi_remember_state +; X64-Darwin: .cfi_restore %rbp +; X64-Darwin: callq ___morestack +; X64-Darwin: retq +; X64-Darwin: .cfi_restore_state + +; X64-FreeBSD-LABEL: test_cfi: +; X64-FreeBSD: .cfi_remember_state +; X64-FreeBSD: .cfi_restore %rbp +; X64-FreeBSD: callq __morestack +; X64-FreeBSD: retq +; X64-FreeBSD: .cfi_restore_state + +; X32-DFlyBSD-LABEL: test_cfi: +; X32-DFlyBSD: .cfi_remember_state +; X32-DFlyBSD: .cfi_restore %ebp +; X32-DFlyBSD: calll __morestack +; X32-DFlyBSD: retl +; X32-DFlyBSD: .cfi_restore_state + +; X64-DFlyBSD-LABEL: test_cfi: +; X64-DFlyBSD: .cfi_remember_state +; X64-DFlyBSD: .cfi_restore %rbp +; X64-DFlyBSD: callq __morestack +; X64-DFlyBSD: retq +; X64-DFlyBSD: .cfi_restore_state + +} + attributes #0 = { "split-stack" } +attributes #1 = { "split-stack" "no-frame-pointer-elim"="true" } ; X64-Linux-Large: .rodata ; X64-Linux-Large-NEXT: __morestack_addr: