]> granicus.if.org Git - llvm/commitdiff
Don't emit CFI instructions at the end of a function
authorAdrian Prantl <aprantl@apple.com>
Mon, 24 Apr 2017 18:45:59 +0000 (18:45 +0000)
committerAdrian Prantl <aprantl@apple.com>
Mon, 24 Apr 2017 18:45:59 +0000 (18:45 +0000)
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

lib/CodeGen/AsmPrinter/AsmPrinter.cpp
test/CodeGen/PowerPC/empty-functions.ll
test/CodeGen/SPARC/empty-functions.ll
test/CodeGen/X86/eh-frame-unreachable.ll [new file with mode: 0644]
test/CodeGen/X86/empty-functions.ll

index 8bce12aaa4d0433f1e162e5cffb05fbb4d476085..a7e1d566c040f698198a01c0c50e9cea8abc92e1 100644 (file)
@@ -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<MCCFIInstruction> &Instrs = MF->getFrameInstructions();
   unsigned CFIIndex = MI.getOperand(0).getCFIIndex();
   const MCCFIInstruction &CFI = Instrs[CFIIndex];
index 56db8f39bffdd76d92ccea29d01e9e693677bbc3..b8394e14318fb0eac8e06d2efd7da75828137857 100644 (file)
@@ -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
index 1f8c5e3a312d0fe6659eb0d06df47a0a85da6a68..974df232033a5e0dc04beade97a4f88df845d7ef 100644 (file)
@@ -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 (file)
index 0000000..a7abc8a
--- /dev/null
@@ -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" }
index 735df2a4196d585fb077028d20357e2c7d2e337b..0c139534e567da894b60cc7ace6054ddb6d0db1e 100644 (file)
@@ -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