From: Adrian Prantl Date: Mon, 24 Apr 2017 18:45:59 +0000 (+0000) Subject: Don't emit CFI instructions at the end of a function X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=83092adef9bb1e3d31cb4ae5baa1ae8d36778f93;p=llvm Don't emit CFI instructions at the end of a function When functions are terminated by unreachable instructions, the last instruction might trigger a CFI instruction to be generated. However, emitting it would be be illegal since the function (and thus the FDE the CFI is in) has already ended with the previous instruction. Darwin's dwarfdump --verify --eh-frame complains about this and the specification supports this. Relevant bits from the DWARF 5 standard (6.4 Call Frame Information): "[The] address_range [field in an FDE]: The number of bytes of program instructions described by this entry." "Row creation instructions: [...] The new location value is always greater than the current one." The first quotation implies that a CFI cannot describe a target address outside of the enclosing FDE's range. rdar://problem/26244988 Differential Revision: https://reviews.llvm.org/D32246 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@301219 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 8bce12aaa4d..a7e1d566c04 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -938,6 +938,16 @@ void AsmPrinter::emitCFIInstruction(const MachineInstr &MI) { if (needsCFIMoves() == CFI_M_None) return; + // If there is no "real" instruction following this CFI instruction, skip + // emitting it; it would be beyond the end of the function's FDE range. + auto *MBB = MI.getParent(); + auto I = std::next(MI.getIterator()); + while (I != MBB->end() && I->isTransient()) + ++I; + if (I == MBB->instr_end() && + MBB->getReverseIterator() == MBB->getParent()->rbegin()) + return; + const std::vector &Instrs = MF->getFrameInstructions(); unsigned CFIIndex = MI.getOperand(0).getCFIIndex(); const MCCFIInstruction &CFI = Instrs[CFIIndex]; diff --git a/test/CodeGen/PowerPC/empty-functions.ll b/test/CodeGen/PowerPC/empty-functions.ll index 56db8f39bff..b8394e14318 100644 --- a/test/CodeGen/PowerPC/empty-functions.ll +++ b/test/CodeGen/PowerPC/empty-functions.ll @@ -24,9 +24,7 @@ entry: ; LINUX-NO-FP-NEXT: .size func, .L[[END]]-.L[[BEGIN]] ; LINUX-NO-FP-NEXT: .cfi_endproc -; A cfi directive can point to the end of a function. It (and in fact the -; entire body) could be optimized out because of the unreachable, but we -; don't do it right now. +; A cfi directive cannot point to the end of a function. ; LINUX-FP: func: ; LINUX-FP-NEXT: {{^}}.L[[BEGIN:.*]]:{{$}} ; LINUX-FP-NEXT: .cfi_startproc @@ -38,8 +36,6 @@ entry: ; LINUX-FP-NEXT: {{^}}.L{{.*}}:{{$}} ; LINUX-FP-NEXT: .cfi_offset r31, -4 ; LINUX-FP-NEXT: mr 31, 1 -; LINUX-FP-NEXT:{{^}}.L{{.*}}:{{$}} -; LINUX-FP-NEXT: .cfi_def_cfa_register r31 ; LINUX-FP-NEXT: {{^}}.L[[END:.*]]:{{$}} ; LINUX-FP-NEXT: .size func, .L[[END]]-.L[[BEGIN]] ; LINUX-FP-NEXT: .cfi_endproc diff --git a/test/CodeGen/SPARC/empty-functions.ll b/test/CodeGen/SPARC/empty-functions.ll index 1f8c5e3a312..974df232033 100644 --- a/test/CodeGen/SPARC/empty-functions.ll +++ b/test/CodeGen/SPARC/empty-functions.ll @@ -14,19 +14,11 @@ entry: ; LINUX-NO-FP-NEXT: .size func, .L{{.*}}-func ; LINUX-NO-FP-NEXT: .cfi_endproc -; A cfi directive can point to the end of a function. It (and in fact the -; entire body) could be optimized out because of the unreachable, but we -; don't do it right now. +; A cfi directive cannot point to the end of a function. ; LINUX-FP: func: ; LINUX-FP-NEXT: .cfi_startproc ; LINUX-FP-NEXT: {{^}}! ; LINUX-FP-NEXT: save %sp, -96, %sp ; LINUX-FP-NEXT: {{^}}.L{{.*}}:{{$}} -; LINUX-FP-NEXT: .cfi_def_cfa_register %fp -; LINUX-FP-NEXT: {{^}}.L{{.*}}:{{$}} -; LINUX-FP-NEXT: .cfi_window_save -; LINUX-FP-NEXT: {{^}}.L{{.*}}:{{$}} -; LINUX-FP-NEXT: .cfi_register 15, 31 -; LINUX-FP-NEXT: {{^}}.L{{.*}}:{{$}} ; LINUX-FP-NEXT: .size func, .Lfunc_end0-func ; LINUX-FP-NEXT: .cfi_endproc diff --git a/test/CodeGen/X86/eh-frame-unreachable.ll b/test/CodeGen/X86/eh-frame-unreachable.ll new file mode 100644 index 00000000000..a7abc8a057f --- /dev/null +++ b/test/CodeGen/X86/eh-frame-unreachable.ll @@ -0,0 +1,11 @@ +; RUN: llc < %s -mtriple=x86_64-apple-darwin | FileCheck %s +; Test that we don't emit a row that extends beyond the FDE's range_size. +; +; CHECK: movq %rsp, %rbp +; CHECK-NEXT: .cfi_endproc +; CHECK-NOT: .cfi + +define void @f() #0 { + unreachable +} +attributes #0 = { "no-frame-pointer-elim"="true" } diff --git a/test/CodeGen/X86/empty-functions.ll b/test/CodeGen/X86/empty-functions.ll index 735df2a4196..0c139534e56 100644 --- a/test/CodeGen/X86/empty-functions.ll +++ b/test/CodeGen/X86/empty-functions.ll @@ -23,8 +23,6 @@ entry: ; CHECK-FP-NEXT: : ; CHECK-FP-NEXT: .cfi_offset %rbp, -16 ; CHECK-FP-NEXT: movq %rsp, %rbp -; CHECK-FP-NEXT: : -; CHECK-FP-NEXT: .cfi_def_cfa_register %rbp ; CHECK-FP-NEXT: .cfi_endproc ; An empty function is perfectly fine on ELF. @@ -35,9 +33,7 @@ entry: ; LINUX-NO-FP-NEXT: .size func, .L{{.*}}-func ; LINUX-NO-FP-NEXT: .cfi_endproc -; A cfi directive can point to the end of a function. It (and in fact the -; entire body) could be optimized out because of the unreachable, but we -; don't do it right now. +; A cfi directive cannot point to the end of a function. ; LINUX-FP: func: ; LINUX-FP-NEXT: .cfi_startproc ; LINUX-FP-NEXT: {{^}}# @@ -48,7 +44,5 @@ entry: ; LINUX-FP-NEXT: .cfi_offset %rbp, -16 ; LINUX-FP-NEXT: movq %rsp, %rbp ; LINUX-FP-NEXT:{{^}}.L{{.*}}:{{$}} -; LINUX-FP-NEXT: .cfi_def_cfa_register %rbp -; LINUX-FP-NEXT:{{^}}.L{{.*}}:{{$}} ; LINUX-FP-NEXT: .size func, .Lfunc_end0-func ; LINUX-FP-NEXT: .cfi_endproc