[llvm] 8cf1cc5 - [FuncAttrs] Infer noreturn

Philip Reames via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 7 10:28:01 PST 2021


On 1/7/21 9:28 AM, Nikita Popov wrote:
> On Thu, Jan 7, 2021 at 6:07 PM Philip Reames via llvm-commits 
> <llvm-commits at lists.llvm.org <mailto:llvm-commits at lists.llvm.org>> wrote:
>
>     Artur,
>
>     I see a serious factoring problem with this change. Specifically,
>     existing passes (instcombine, simplifycfg) should have pruned
>     instructions after noreturn calls leaving only a unreachable
>     terminator.  Given that, scanning the terminator block should not be
>     required at all here.
>
>     Are you sure your motivating test requires handling noreturn calls
>     explicitly?  (As opposed to simply checking for a lack of return
>     instructions?)
>
>     The only solid argument I see for handling no return calls is
>     analysis
>     of SCCs, but your patch doesn't appear to do that, so it's no
>     relevant.
>     Unless you're planning to support that in the near future?
>
>     At the moment, I am not asking for a revert.  Depending on your
>     answer
>     and resulting discussion, I may.
>
>     Philip
>
>
> I think the problem here might be that under the NewPM, SimplifyCFG 
> (which does the noreturn unreachable fold) does not run before 
> FunctionAttrs. On the legacy PM it does.
This feels like something we need to fix.
>
> Nikita
>
>     On 1/5/21 1:26 PM, Arthur Eubanks via llvm-commits wrote:
>     > Author: Arthur Eubanks
>     > Date: 2021-01-05T13:25:42-08:00
>     > New Revision: 8cf1cc578d3288f5b9cfe1584e524f8b1517dc97
>     >
>     > URL:
>     https://github.com/llvm/llvm-project/commit/8cf1cc578d3288f5b9cfe1584e524f8b1517dc97
>     > DIFF:
>     https://github.com/llvm/llvm-project/commit/8cf1cc578d3288f5b9cfe1584e524f8b1517dc97.diff
>     >
>     > LOG: [FuncAttrs] Infer noreturn
>     >
>     > A function is noreturn if all blocks terminating with a ReturnInst
>     > contain a call to a noreturn function. Skip looking at naked
>     functions
>     > since there may be asm that returns.
>     >
>     > This can be further refined in the future by checking
>     unreachable blocks
>     > and taking into account recursion. It looks like the attributor pass
>     > does this, but that is not yet enabled by default.
>     >
>     > This seems to help with code size under the new PM since PruneEH
>     does
>     > not run under the new PM, missing opportunities to mark some
>     functions
>     > noreturn, which in turn doesn't allow simplifycfg to clean up
>     dead code.
>     > https://bugs.llvm.org/show_bug.cgi?id=46858.
>     >
>     > Reviewed By: rnk
>     >
>     > Differential Revision: https://reviews.llvm.org/D93946
>     >
>     > Added:
>     >      llvm/test/Transforms/FunctionAttrs/noreturn.ll
>     >
>     > Modified:
>     >      llvm/lib/Transforms/IPO/FunctionAttrs.cpp
>     >      llvm/test/Transforms/PruneEH/simplenoreturntest.ll
>     >
>     > Removed:
>     >
>     >
>     >
>     >
>     ################################################################################
>     > diff  --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
>     b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
>     > index 0d25d5d319e7..62e3e5ad0a52 100644
>     > --- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
>     > +++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
>     > @@ -1388,6 +1388,42 @@ static bool addNoRecurseAttrs(const
>     SCCNodeSet &SCCNodes) {
>     >     return true;
>     >   }
>     >
>     > +static bool instructionDoesNotReturn(Instruction &I) {
>     > +  if (auto *CB = dyn_cast<CallBase>(&I)) {
>     > +    Function *Callee = CB->getCalledFunction();
>     > +    return Callee && Callee->doesNotReturn();
>     > +  }
>     > +  return false;
>     > +}
>     > +
>     > +// A basic block can only return if it terminates with a
>     ReturnInst and does not
>     > +// contain calls to noreturn functions.
>     > +static bool basicBlockCanReturn(BasicBlock &BB) {
>     > +  if (!isa<ReturnInst>(BB.getTerminator()))
>     > +    return false;
>     > +  return none_of(BB, instructionDoesNotReturn);
>     > +}
>     > +
>     > +// Set the noreturn function attribute if possible.
>     > +static bool addNoReturnAttrs(const SCCNodeSet &SCCNodes) {
>     > +  bool Changed = false;
>     > +
>     > +  for (Function *F : SCCNodes) {
>     > +    if (!F || !F->hasExactDefinition() ||
>     F->hasFnAttribute(Attribute::Naked) ||
>     > +        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)) {
>     > +      F->setDoesNotReturn();
>     > +      Changed = true;
>     > +    }
>     > +  }
>     > +
>     > +  return Changed;
>     > +}
>     > +
>     >   static SCCNodesResult createSCCNodeSet(ArrayRef<Function *>
>     Functions) {
>     >     SCCNodesResult Res;
>     >     Res.HasUnknownCall = false;
>     > @@ -1431,6 +1467,7 @@ static bool
>     deriveAttrsInPostOrder(ArrayRef<Function *> Functions,
>     >     Changed |= addReadAttrs(Nodes.SCCNodes, AARGetter);
>     >     Changed |= addArgumentAttrs(Nodes.SCCNodes);
>     >     Changed |= inferConvergent(Nodes.SCCNodes);
>     > +  Changed |= addNoReturnAttrs(Nodes.SCCNodes);
>     >
>     >     // If we have no external nodes participating in the SCC, we
>     can deduce some
>     >     // more precise attributes as well.
>     >
>     > diff  --git a/llvm/test/Transforms/FunctionAttrs/noreturn.ll
>     b/llvm/test/Transforms/FunctionAttrs/noreturn.ll
>     > new file mode 100644
>     > index 000000000000..acc538d3ccee
>     > --- /dev/null
>     > +++ b/llvm/test/Transforms/FunctionAttrs/noreturn.ll
>     > @@ -0,0 +1,66 @@
>     > +; RUN: opt < %s -passes='function-attrs' -S | FileCheck %s
>     > +
>     > +declare i32 @f()
>     > +
>     > +; CHECK: Function Attrs: noreturn
>     > +; CHECK-NEXT: @noreturn()
>     > +declare i32 @noreturn() noreturn
>     > +
>     > +; CHECK: Function Attrs: noreturn
>     > +; CHECK-NEXT: @caller()
>     > +define i32 @caller() {
>     > +  %c = call i32 @noreturn()
>     > +  ret i32 %c
>     > +}
>     > +
>     > +; CHECK: Function Attrs: noreturn
>     > +; CHECK-NEXT: @caller2()
>     > +define i32 @caller2() {
>     > +  %c = call i32 @caller()
>     > +  ret i32 %c
>     > +}
>     > +
>     > +; CHECK: Function Attrs: noreturn
>     > +; CHECK-NEXT: @caller3()
>     > +define i32 @caller3() {
>     > +entry:
>     > +  br label %end
>     > +end:
>     > +  %c = call i32 @noreturn()
>     > +  ret i32 %c
>     > +}
>     > +
>     > +; CHECK-NOT: Function Attrs: {{.*}}noreturn
>     > +; CHECK: define i32 @caller4()
>     > +define i32 @caller4() {
>     > +entry:
>     > +  br label %end
>     > +end:
>     > +  %c = call i32 @f()
>     > +  ret i32 %c
>     > +}
>     > +
>     > +; CHECK-NOT: Function Attrs: {{.*}}noreturn
>     > +; CHECK: @caller5()
>     > +; We currently don't handle unreachable blocks.
>     > +define i32 @caller5() {
>     > +entry:
>     > +  %c = call i32 @noreturn()
>     > +  ret i32 %c
>     > +unreach:
>     > +  %d = call i32 @f()
>     > +  ret i32 %d
>     > +}
>     > +
>     > +; CHECK-NOT: Function Attrs: {{.*}}noreturn
>     > +; CHECK: @caller6()
>     > +define i32 @caller6() naked {
>     > +  %c = call i32 @noreturn()
>     > +  ret i32 %c
>     > +}
>     > +
>     > +; CHECK: Function Attrs: {{.*}}noreturn
>     > +; CHECK-NEXT: @alreadynoreturn()
>     > +define i32 @alreadynoreturn() noreturn {
>     > +  unreachable
>     > +}
>     >
>     > diff  --git a/llvm/test/Transforms/PruneEH/simplenoreturntest.ll
>     b/llvm/test/Transforms/PruneEH/simplenoreturntest.ll
>     > index 814f8b4a686f..ccb9f5eb6f59 100644
>     > --- a/llvm/test/Transforms/PruneEH/simplenoreturntest.ll
>     > +++ b/llvm/test/Transforms/PruneEH/simplenoreturntest.ll
>     > @@ -1,4 +1,5 @@
>     >   ; RUN: opt < %s -prune-eh -S -enable-new-pm=0 | not grep "ret i32"
>     > +; RUN: opt < %s -passes='function-attrs,function(simplifycfg)'
>     -S | not grep "ret i32"
>     >
>     >   declare void @noreturn() noreturn
>     >
>     >
>     >
>     >
>     > _______________________________________________
>     > llvm-commits mailing list
>     > llvm-commits at lists.llvm.org <mailto:llvm-commits at lists.llvm.org>
>     > https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>     _______________________________________________
>     llvm-commits mailing list
>     llvm-commits at lists.llvm.org <mailto:llvm-commits at lists.llvm.org>
>     https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20210107/4907ea76/attachment.html>


More information about the llvm-commits mailing list