[funcattrs] check reachability to improve noreturn
authorNick Desaulniers <ndesaulniers@google.com>
Mon, 14 Feb 2022 21:47:00 +0000 (13:47 -0800)
committerNick Desaulniers <ndesaulniers@google.com>
Mon, 14 Feb 2022 22:01:59 +0000 (14:01 -0800)
There was a fixme in the code pertaining to attributing functions as
noreturn.  By using reachability, if none of the blocks that are
reachable from the entry return, then the function is noreturn.

Previously, the code only checked if any blocks returned. If they're
unreachable, then they don't matter.

This improves codegen for the Linux kernel.

Fixes: https://github.com/ClangBuiltLinux/linux/issues/1563

Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D119571

llvm/lib/Transforms/IPO/FunctionAttrs.cpp
llvm/test/Transforms/FunctionAttrs/noreturn.ll

index 213a998..e2f1944 100644 (file)
@@ -1614,6 +1614,26 @@ static bool basicBlockCanReturn(BasicBlock &BB) {
   return none_of(BB, instructionDoesNotReturn);
 }
 
+// FIXME: this doesn't handle recursion.
+static bool canReturn(Function &F) {
+  SmallVector<BasicBlock *, 16> Worklist;
+  SmallPtrSet<BasicBlock *, 16> Visited;
+
+  Visited.insert(&F.front());
+  Worklist.push_back(&F.front());
+
+  do {
+    BasicBlock *BB = Worklist.pop_back_val();
+    if (basicBlockCanReturn(*BB))
+      return true;
+    for (BasicBlock *Succ : successors(BB))
+      if (Visited.insert(Succ).second)
+        Worklist.push_back(Succ);
+  } while (!Worklist.empty());
+
+  return false;
+}
+
 // Set the noreturn function attribute if possible.
 static void addNoReturnAttrs(const SCCNodeSet &SCCNodes,
                              SmallSet<Function *, 8> &Changed) {
@@ -1622,9 +1642,7 @@ static void addNoReturnAttrs(const SCCNodeSet &SCCNodes,
         F->doesNotReturn())
       continue;
 
-    // The function can return if any basic blocks can return.
-    // FIXME: this doesn't handle recursion or unreachable blocks.
-    if (none_of(*F, basicBlockCanReturn)) {
+    if (!canReturn(*F)) {
       F->setDoesNotReturn();
       Changed.insert(F);
     }
index eba56c9..6bc1e32 100644 (file)
@@ -40,9 +40,8 @@ end:
   ret i32 %c
 }
 
-; CHECK-NOT: Function Attrs: {{.*}}noreturn
+; CHECK: Function Attrs: {{.*}}noreturn
 ; CHECK: @caller5()
-; We currently don't handle unreachable blocks.
 define i32 @caller5() {
 entry:
   %c = call i32 @noreturn()
@@ -87,4 +86,4 @@ define void @coro() "coroutine.presplit"="1" {
 }
 
 declare token @llvm.coro.id.retcon.once(i32 %size, i32 %align, i8* %buffer, i8* %prototype, i8* %alloc, i8* %free)
-declare i1 @llvm.coro.end(i8*, i1)
\ No newline at end of file
+declare i1 @llvm.coro.end(i8*, i1)