[llvm] r336419 - CallGraphSCCPass: iterate over all functions.

Mikael Holmén via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 9 01:21:21 PDT 2018


Hi Tim,

I found a case which started going wrong with this patch. I don't know 
if it's the patch itself that is the problem or if it's just exposing 
somethng already existing.

With

  opt -S -o - foo.ll -argpromotion -instcombine

I get

DISubprogram attached to more than one function
!1 = distinct !DISubprogram(name: "func_27", scope: !2, file: !2, line: 
251, type: !3, isLocal: true, isDefinition: true, scopeLine: 252, 
isOptimized: false, unit: !5)
i64 ()* @func_27
LLVM ERROR: Broken module found, compilation aborted!

If I add -print-before-all -print-after-all -print-module-scope I get 
this as the last printouts:

*** IR Dump Before Module Verifier *** (function: func_27)
; ModuleID = 'foo.ll'
source_filename = "foo.ll"

@g_280 = external global i32

define i32 @func_1() {
bb1:
   %l_55.115 = alloca i32*, align 8
   %_tmp555 = load i32*, i32** %l_55.115, align 8
   %0 = call i64 @func_27()
   ret i32 undef
}

define internal i64 @func_27() !dbg !1 {
   store i32* @g_280, i32** undef, align 8
   ret i64 undef
}

define i16 @func_28() {
   %_tmp5791 = call i32 @func_1()
   ret i16 undef
}

!llvm.dbg.cu = !{}
!llvm.module.flags = !{!0}

!0 = !{i32 2, !"Debug Info Version", i32 3}
!1 = distinct !DISubprogram(name: "func_27", scope: !2, file: !2, line: 
251, type: !3, isLocal: true, isDefinition: true, scopeLine: 252, 
isOptimized: false, unit: !5)
!2 = !DIFile(filename: "foo.c", directory: "/bar")
!3 = !DISubroutineType(types: !4)
!4 = !{}
!5 = distinct !DICompileUnit(language: DW_LANG_C, file: !2, producer: 
"My compiler", isOptimized: false, runtimeVersion: 0, emissionKind: 
LineTablesOnly)
DISubprogram attached to more than one function
!1 = distinct !DISubprogram(name: "func_27", scope: !2, file: !2, line: 
251, type: !3, isLocal: true, isDefinition: true, scopeLine: 252, 
isOptimized: false, unit: !5)
i64 ()* @func_27
*** IR Dump After Module Verifier *** (function: func_27)
; ModuleID = 'foo.ll'
source_filename = "foo.ll"

@g_280 = external global i32

define i32 @func_1() {
bb1:
   %l_55.115 = alloca i32*, align 8
   %_tmp555 = load i32*, i32** %l_55.115, align 8
   %0 = call i64 @func_27()
   ret i32 undef
}

define internal i64 @func_27() !dbg !1 {
   store i32* @g_280, i32** undef, align 8
   ret i64 undef
}

define i16 @func_28() {
   %_tmp5791 = call i32 @func_1()
   ret i16 undef
}

!llvm.dbg.cu = !{}
!llvm.module.flags = !{!0}

!0 = !{i32 2, !"Debug Info Version", i32 3}
!1 = distinct !DISubprogram(name: "func_27", scope: !2, file: !2, line: 
251, type: !3, isLocal: true, isDefinition: true, scopeLine: 252, 
isOptimized: false, unit: !5)
!2 = !DIFile(filename: "foo.c", directory: "/bar")
!3 = !DISubroutineType(types: !4)
!4 = !{}
!5 = distinct !DICompileUnit(language: DW_LANG_C, file: !2, producer: 
"My compiler", isOptimized: false, runtimeVersion: 0, emissionKind: 
LineTablesOnly)
LLVM ERROR: Broken module found, compilation aborted!

As far as I can see in the printouts !1 is only used on func_27 and 
still it complains.

func27 was changed during argpromotion:

ARG PROMOTION:  Promoting to:
declare !dbg !0 internal i64 @func_27(i32*)

From:
define internal i64 @func_27(i32* %p1, i32* %p2) {
   store i32* %p1, i32** undef
   store i32* @g_280, i32** undef
   ret i64 undef
}

so I'm not sure if the old func_27 is still hanging around in some way?

Should I write a PR on this or do you understand what's going on?

Regards,
Mikael

On 07/06/2018 10:04 AM, Tim Northover via llvm-commits wrote:
> Author: tnorthover
> Date: Fri Jul  6 01:04:47 2018
> New Revision: 336419
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=336419&view=rev
> Log:
> CallGraphSCCPass: iterate over all functions.
> 
> Previously we only iterated over functions reachable from the set of
> external functions in the module. But since some of the passes under
> this (notably the always-inliner and coroutine lowerer) are required for
> correctness, they need to run over everything.
> 
> This just adds an extra layer of iteration over the CallGraph to keep
> track of which functions we've already visited and get the next batch of
> SCCs.
> 
> Should fix PR38029.
> 
> Modified:
>      llvm/trunk/include/llvm/ADT/SCCIterator.h
>      llvm/trunk/lib/Analysis/CallGraphSCCPass.cpp
>      llvm/trunk/test/Transforms/Inline/always-inline.ll
> 
> Modified: llvm/trunk/include/llvm/ADT/SCCIterator.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/SCCIterator.h?rev=336419&r1=336418&r2=336419&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/ADT/SCCIterator.h (original)
> +++ llvm/trunk/include/llvm/ADT/SCCIterator.h Fri Jul  6 01:04:47 2018
> @@ -90,6 +90,7 @@ class scc_iterator : public iterator_fac
>     /// Compute the next SCC using the DFS traversal.
>     void GetNextSCC();
>   
> +public:
>     scc_iterator(NodeRef entryN) : visitNum(0) {
>       DFSVisitOne(entryN);
>       GetNextSCC();
> @@ -98,12 +99,6 @@ class scc_iterator : public iterator_fac
>     /// End is when the DFS stack is empty.
>     scc_iterator() = default;
>   
> -public:
> -  static scc_iterator begin(const GraphT &G) {
> -    return scc_iterator(GT::getEntryNode(G));
> -  }
> -  static scc_iterator end(const GraphT &) { return scc_iterator(); }
> -
>     /// Direct loop termination test which is more efficient than
>     /// comparison with \c end().
>     bool isAtEnd() const {
> @@ -222,16 +217,25 @@ bool scc_iterator<GraphT, GT>::hasLoop()
>       return false;
>     }
>   
> -/// Construct the begin iterator for a deduced graph type T.
> +/// Construct the begin iterator for a deduced graph type T, starting from its
> +/// entry node.
>   template <class T> scc_iterator<T> scc_begin(const T &G) {
> -  return scc_iterator<T>::begin(G);
> +  return scc_iterator<T>(GraphTraits<T>::getEntryNode(G));
>   }
>   
> -/// Construct the end iterator for a deduced graph type T.
> +/// Construct the begin iterator for a graph type T, starting from the specified
> +/// node.
> +template <class T, class U = GraphTraits<T>>
> +scc_iterator<T, U> scc_begin(typename U::NodeRef N) {
> +  return scc_iterator<T>(N);
> +}
> +
> +  /// Construct the end iterator for a deduced graph type T.
>   template <class T> scc_iterator<T> scc_end(const T &G) {
> -  return scc_iterator<T>::end(G);
> +  return scc_iterator<T>();
>   }
>   
> +
>   } // end namespace llvm
>   
>   #endif // LLVM_ADT_SCCITERATOR_H
> 
> Modified: llvm/trunk/lib/Analysis/CallGraphSCCPass.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CallGraphSCCPass.cpp?rev=336419&r1=336418&r2=336419&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Analysis/CallGraphSCCPass.cpp (original)
> +++ llvm/trunk/lib/Analysis/CallGraphSCCPass.cpp Fri Jul  6 01:04:47 2018
> @@ -17,6 +17,7 @@
>   
>   #include "llvm/Analysis/CallGraphSCCPass.h"
>   #include "llvm/ADT/DenseMap.h"
> +#include "llvm/ADT/DenseSet.h"
>   #include "llvm/ADT/SCCIterator.h"
>   #include "llvm/ADT/Statistic.h"
>   #include "llvm/Analysis/CallGraph.h"
> @@ -63,6 +64,10 @@ public:
>     /// whether any of the passes modifies the module, and if so, return true.
>     bool runOnModule(Module &M) override;
>   
> +  /// Execute all of the passes scheduled for execution on a given SCC. Return
> +  /// true if any passes modify the module.
> +  bool runOnSCC(CallGraphSCC &SCC, CallGraph &CG);
> +
>     using ModulePass::doInitialization;
>     using ModulePass::doFinalization;
>   
> @@ -448,51 +453,78 @@ bool CGPassManager::RunAllPassesOnSCC(Ca
>   bool CGPassManager::runOnModule(Module &M) {
>     CallGraph &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph();
>     bool Changed = doInitialization(CG);
> -
> -  // Walk the callgraph in bottom-up SCC order.
> -  scc_iterator<CallGraph*> CGI = scc_begin(&CG);
>   
> -  CallGraphSCC CurSCC(CG, &CGI);
> -  while (!CGI.isAtEnd()) {
> -    // Copy the current SCC and increment past it so that the pass can hack
> -    // on the SCC if it wants to without invalidating our iterator.
> -    const std::vector<CallGraphNode *> &NodeVec = *CGI;
> -    CurSCC.initialize(NodeVec);
> -    ++CGI;
> -
> -    // At the top level, we run all the passes in this pass manager on the
> -    // functions in this SCC.  However, we support iterative compilation in the
> -    // case where a function pass devirtualizes a call to a function.  For
> -    // example, it is very common for a function pass (often GVN or instcombine)
> -    // to eliminate the addressing that feeds into a call.  With that improved
> -    // information, we would like the call to be an inline candidate, infer
> -    // mod-ref information etc.
> -    //
> -    // Because of this, we allow iteration up to a specified iteration count.
> -    // This only happens in the case of a devirtualized call, so we only burn
> -    // compile time in the case that we're making progress.  We also have a hard
> -    // iteration count limit in case there is crazy code.
> -    unsigned Iteration = 0;
> -    bool DevirtualizedCall = false;
> -    do {
> -      LLVM_DEBUG(if (Iteration) dbgs()
> -                 << "  SCCPASSMGR: Re-visiting SCC, iteration #" << Iteration
> -                 << '\n');
> -      DevirtualizedCall = false;
> -      Changed |= RunAllPassesOnSCC(CurSCC, CG, DevirtualizedCall);
> -    } while (Iteration++ < MaxIterations && DevirtualizedCall);
> -
> -    if (DevirtualizedCall)
> -      LLVM_DEBUG(dbgs() << "  CGSCCPASSMGR: Stopped iteration after "
> -                        << Iteration
> -                        << " times, due to -max-cg-scc-iterations\n");
> +  DenseSet<const Function *> Visited;
>   
> -    MaxSCCIterations.updateMax(Iteration);
> +  CallGraph::iterator INext;
> +  for (auto I = CG.begin(), E = CG.end(); I != E;) {
> +    // Walk the callgraph in bottom-up SCC order.
> +    auto CGI = scc_begin<CallGraph *>(I->second.get());
> +
> +    CallGraphSCC CurSCC(CG, &CGI);
> +    while (!CGI.isAtEnd()) {
> +      const std::vector<CallGraphNode *> &NodeVec = *CGI;
> +
> +      // Record that we've seen this set of functions so we don't run the pass
> +      // twice.
> +      for (auto *Elt : NodeVec)
> +        Visited.insert(Elt->getFunction());
> +
> +      // Copy the current SCC and increment past it so that the pass can hack
> +      // on the SCC if it wants to without invalidating our iterator.
> +      CurSCC.initialize(NodeVec);
> +      ++CGI;
> +
> +      // If we've got all functions reachable from our chosen initial node,
> +      // calculate the next node we need to search from now before parts of the
> +      // graph are invalidated.
> +      if (CGI.isAtEnd()) {
> +        do
> +          ++I;
> +        while (I != E && Visited.count(I->first));
> +      }
> +
> +      Changed |= runOnSCC(CurSCC, CG);
> +    }
>     }
> +
>     Changed |= doFinalization(CG);
>     return Changed;
>   }
>   
> +bool CGPassManager::runOnSCC(CallGraphSCC &CurSCC, CallGraph &CG) {
> +  bool Changed = false;
> +
> +  // At the top level, we run all the passes in this pass manager on the
> +  // functions in this SCC.  However, we support iterative compilation in the
> +  // case where a function pass devirtualizes a call to a function.  For
> +  // example, it is very common for a function pass (often GVN or instcombine)
> +  // to eliminate the addressing that feeds into a call.  With that improved
> +  // information, we would like the call to be an inline candidate, infer
> +  // mod-ref information etc.
> +  //
> +  // Because of this, we allow iteration up to a specified iteration count.
> +  // This only happens in the case of a devirtualized call, so we only burn
> +  // compile time in the case that we're making progress.  We also have a hard
> +  // iteration count limit in case there is crazy code.
> +  unsigned Iteration = 0;
> +  bool DevirtualizedCall = false;
> +  do {
> +    LLVM_DEBUG(if (Iteration) dbgs()
> +               << "  SCCPASSMGR: Re-visiting SCC, iteration #" << Iteration
> +               << '\n');
> +    DevirtualizedCall = false;
> +    Changed |= RunAllPassesOnSCC(CurSCC, CG, DevirtualizedCall);
> +  } while (Iteration++ < MaxIterations && DevirtualizedCall);
> +
> +  if (DevirtualizedCall)
> +    LLVM_DEBUG(dbgs() << "  CGSCCPASSMGR: Stopped iteration after " << Iteration
> +                      << " times, due to -max-cg-scc-iterations\n");
> +
> +  MaxSCCIterations.updateMax(Iteration);
> +  return Changed;
> +}
> +
>   /// Initialize CG
>   bool CGPassManager::doInitialization(CallGraph &CG) {
>     bool Changed = false;
> 
> Modified: llvm/trunk/test/Transforms/Inline/always-inline.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Inline/always-inline.ll?rev=336419&r1=336418&r2=336419&view=diff
> ==============================================================================
> --- llvm/trunk/test/Transforms/Inline/always-inline.ll (original)
> +++ llvm/trunk/test/Transforms/Inline/always-inline.ll Fri Jul  6 01:04:47 2018
> @@ -316,3 +316,10 @@ define void @outer14() {
>     call void @inner14()
>     ret void
>   }
> +
> +define internal i32 @outer15() {
> +; CHECK-LABEL: @outer15
> +; CHECK: ret i32 1
> +  %res = call i32 @inner1()
> +  ret i32 %res
> +}
> 
> 
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
> 
-------------- next part --------------

@g_280 = external global i32

define i32 @func_1() {
bb1:
  %l_55.115 = alloca i32*
  %_tmp555 = load i32*, i32** %l_55.115
  %_tmp565 = call i64 @func_27(i32* %_tmp555, i32* undef)
  ret i32 undef
}

define internal i64 @func_27(i32* %p1, i32* %p2) !dbg !8 {
  store i32* %p1, i32** undef
  store i32* @g_280, i32** undef
  ret i64 undef
}

define i16 @func_28() {
  %_tmp5791 = call i32 @func_1()
  ret i16 undef
}

!llvm.dbg.cu = !{}
!llvm.module.flags = !{!0}

!0 = !{i32 2, !"Debug Info Version", i32 3}
!1 = distinct !DISubprogram(name: "func_1", scope: !2, file: !2, line: 119, type: !3, isLocal: true, isDefinition: true, scopeLine: 120, isOptimized: false, unit: !5)
!2 = !DIFile(filename: "foo.c", directory: "/bar")
!3 = !DISubroutineType(types: !4)
!4 = !{}
!5 = distinct !DICompileUnit(language: DW_LANG_C, file: !2, producer: "My compiler", isOptimized: false, runtimeVersion: 0, emissionKind: LineTablesOnly)
!8 = distinct !DISubprogram(name: "func_27", scope: !2, file: !2, line: 251, type: !3, isLocal: true, isDefinition: true, scopeLine: 252, isOptimized: false, unit: !5)


More information about the llvm-commits mailing list