[llvm] r328004 - Add an analysis printer for must execute reasoning

David Blaikie via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 28 16:16:50 PDT 2018


On Tue, Mar 20, 2018 at 10:11 AM Philip Reames via llvm-commits <
llvm-commits at lists.llvm.org> wrote:

> Author: reames
> Date: Tue Mar 20 10:09:21 2018
> New Revision: 328004
>
> URL: http://llvm.org/viewvc/llvm-project?rev=328004&view=rev
> Log:
> Add an analysis printer for must execute reasoning
>
> Many of our loop passes make use of so called "must execute" or
> "guaranteed to execute" facts to prove the legality of code motion. The
> basic notion is that we know (by assumption) an instruction didn't fault at
> it's original location, so if the location we move it to is strictly post
> dominated by the original, then we can't have introduced a new fault.
>
> At the moment, the testing for this logic is somewhat adhoc and done
> mostly through LICM. Since I'm working on that code, I want to improve the
> testing. This patch is the first step in that direction. It doesn't
> actually test the variant used by the loop passes - I need to move that to
> the Analysis library first - but instead exercises an alternate
> implementation used by SCEV. (I plan on merging both implementations.)
>
> Note: I'll be replacing the printing logic within this with an annotation
> based version in the near future.  Anna suggested this in review, and it
> seems like a strictly better format.
>
> Differential Revision: https://reviews.llvm.org/D44524
>
>
> Added:
>     llvm/trunk/lib/Analysis/MustExecute.cpp
>     llvm/trunk/test/Analysis/MustExecute/
>     llvm/trunk/test/Analysis/MustExecute/loop-header.ll
> Modified:
>     llvm/trunk/include/llvm/Analysis/Passes.h
>     llvm/trunk/include/llvm/InitializePasses.h
>     llvm/trunk/include/llvm/LinkAllPasses.h
>     llvm/trunk/lib/Analysis/Analysis.cpp
>     llvm/trunk/lib/Analysis/CMakeLists.txt
>
> Modified: llvm/trunk/include/llvm/Analysis/Passes.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/Passes.h?rev=328004&r1=328003&r2=328004&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/Analysis/Passes.h (original)
> +++ llvm/trunk/include/llvm/Analysis/Passes.h Tue Mar 20 10:09:21 2018
> @@ -96,6 +96,14 @@ namespace llvm {
>    //
>    FunctionPass *createMemDerefPrinter();
>
> +
> //===--------------------------------------------------------------------===//
> +  //
> +  // createMustExecutePrinter - This pass collects information about which
> +  // instructions within a loop are guaranteed to execute if the loop
> header is
> +  // entered and prints it with -analyze.
> +  //
> +  FunctionPass *createMustExecutePrinter();
> +
>  }
>
>  #endif
>
> Modified: llvm/trunk/include/llvm/InitializePasses.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/InitializePasses.h?rev=328004&r1=328003&r2=328004&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/InitializePasses.h (original)
> +++ llvm/trunk/include/llvm/InitializePasses.h Tue Mar 20 10:09:21 2018
> @@ -268,6 +268,7 @@ void initializeMergedLoadStoreMotionLega
>  void initializeMetaRenamerPass(PassRegistry&);
>  void initializeModuleDebugInfoPrinterPass(PassRegistry&);
>  void initializeModuleSummaryIndexWrapperPassPass(PassRegistry&);
> +void initializeMustExecutePrinterPass(PassRegistry&);
>  void initializeNameAnonGlobalLegacyPassPass(PassRegistry&);
>  void initializeNaryReassociateLegacyPassPass(PassRegistry&);
>  void initializeNewGVNLegacyPassPass(PassRegistry&);
>
> Modified: llvm/trunk/include/llvm/LinkAllPasses.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/LinkAllPasses.h?rev=328004&r1=328003&r2=328004&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/LinkAllPasses.h (original)
> +++ llvm/trunk/include/llvm/LinkAllPasses.h Tue Mar 20 10:09:21 2018
> @@ -207,6 +207,7 @@ namespace {
>        (void) llvm::createRewriteSymbolsPass();
>        (void) llvm::createStraightLineStrengthReducePass();
>        (void) llvm::createMemDerefPrinter();
> +      (void) llvm::createMustExecutePrinter();
>        (void) llvm::createFloat2IntPass();
>        (void) llvm::createEliminateAvailableExternallyPass();
>        (void) llvm::createScalarizeMaskedMemIntrinPass();
>
> Modified: llvm/trunk/lib/Analysis/Analysis.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/Analysis.cpp?rev=328004&r1=328003&r2=328004&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Analysis/Analysis.cpp (original)
> +++ llvm/trunk/lib/Analysis/Analysis.cpp Tue Mar 20 10:09:21 2018
> @@ -65,6 +65,7 @@ void llvm::initializeAnalysis(PassRegist
>    initializeMemoryDependenceWrapperPassPass(Registry);
>    initializeModuleDebugInfoPrinterPass(Registry);
>    initializeModuleSummaryIndexWrapperPassPass(Registry);
> +  initializeMustExecutePrinterPass(Registry);
>    initializeObjCARCAAWrapperPassPass(Registry);
>    initializeOptimizationRemarkEmitterWrapperPassPass(Registry);
>    initializePostDominatorTreeWrapperPassPass(Registry);
>
> Modified: llvm/trunk/lib/Analysis/CMakeLists.txt
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CMakeLists.txt?rev=328004&r1=328003&r2=328004&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Analysis/CMakeLists.txt (original)
> +++ llvm/trunk/lib/Analysis/CMakeLists.txt Tue Mar 20 10:09:21 2018
> @@ -58,6 +58,7 @@ add_llvm_library(LLVMAnalysis
>    MemorySSAUpdater.cpp
>    ModuleDebugInfoPrinter.cpp
>    ModuleSummaryAnalysis.cpp
> +  MustExecute.cpp
>    ObjCARCAliasAnalysis.cpp
>    ObjCARCAnalysisUtils.cpp
>    ObjCARCInstKind.cpp
>
> Added: llvm/trunk/lib/Analysis/MustExecute.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/MustExecute.cpp?rev=328004&view=auto
>
> ==============================================================================
> --- llvm/trunk/lib/Analysis/MustExecute.cpp (added)
> +++ llvm/trunk/lib/Analysis/MustExecute.cpp Tue Mar 20 10:09:21 2018
> @@ -0,0 +1,102 @@
> +//===- MustExecute.cpp - Printer for isGuaranteedToExecute
> ----------------===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "llvm/Analysis/LoopInfo.h"
> +#include "llvm/Analysis/Passes.h"
> +#include "llvm/Analysis/ValueTracking.h"
> +#include "llvm/IR/DataLayout.h"
> +#include "llvm/IR/InstIterator.h"
> +#include "llvm/IR/LLVMContext.h"
> +#include "llvm/IR/Module.h"
> +#include "llvm/Support/ErrorHandling.h"
> +#include "llvm/Support/raw_ostream.h"
> +#include "llvm/Transforms/Utils/LoopUtils.h"
>

This looks like a circular/invalid dependency? Transforms depend on
Analysis, not the other way around?

Would be great to get this fixed - happy to help, if you've some ideas.

Moving the whole LoopUtils isn't immediately possible, its implementation
depends on BasicBlockUtils. (& also many of these utilities seem more for
mutation, which isn't relevant to Analysis - so maybe it needs to be split
up?)


> +using namespace llvm;
> +
> +namespace {
> +  struct MustExecutePrinter : public FunctionPass {
> +    DenseMap<Value*, SmallVector<Loop*, 4> > MustExec;
> +    SmallVector<Value *, 4> Ordering;
> +
> +    static char ID; // Pass identification, replacement for typeid
> +    MustExecutePrinter() : FunctionPass(ID) {
> +      initializeMustExecutePrinterPass(*PassRegistry::getPassRegistry());
> +    }
> +    void getAnalysisUsage(AnalysisUsage &AU) const override {
> +      AU.setPreservesAll();
> +      AU.addRequired<DominatorTreeWrapperPass>();
> +      AU.addRequired<LoopInfoWrapperPass>();
> +    }
> +    bool runOnFunction(Function &F) override;
> +    void print(raw_ostream &OS, const Module * = nullptr) const override;
> +    void releaseMemory() override {
> +      MustExec.clear();
> +      Ordering.clear();
> +    }
> +  };
> +}
> +
> +char MustExecutePrinter::ID = 0;
> +INITIALIZE_PASS_BEGIN(MustExecutePrinter, "print-mustexecute",
> +                      "Instructions which execute on loop entry", false,
> true)
> +INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
> +INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
> +INITIALIZE_PASS_END(MustExecutePrinter, "print-mustexecute",
> +                    "Instructions which execute on loop entry", false,
> true)
> +
> +FunctionPass *llvm::createMustExecutePrinter() {
> +  return new MustExecutePrinter();
> +}
> +
> +bool isMustExecuteIn(Instruction &I, Loop *L, DominatorTree *DT) {
> +  // TODO: move loop specific code to analysis
> +  //LoopSafetyInfo LSI;
> +  //computeLoopSafetyInfo(&LSI, L);
> +  //return isGuaranteedToExecute(I, DT, L, &LSI);
> +  return isGuaranteedToExecuteForEveryIteration(&I, L);
> +}
> +
> +bool MustExecutePrinter::runOnFunction(Function &F) {
> +  auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
> +  auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
> +  for (auto &I: instructions(F)) {
> +    Loop *L = LI.getLoopFor(I.getParent());
> +    while (L) {
> +      if (isMustExecuteIn(I, L, &DT)) {
> +        if (!MustExec.count(&I))
> +          Ordering.push_back(&I);
> +        MustExec[&I].push_back(L);
> +      }
> +      L = L->getParentLoop();
> +    };
> +  }
> +  return false;
> +}
> +
> +void MustExecutePrinter::print(raw_ostream &OS, const Module *M) const {
> +  OS << "The following are guaranteed to execute (for the respective
> loops):\n";
> +  for (Value *V: Ordering) {
> +    V->printAsOperand(OS);
> +    auto NumLoops = MustExec.lookup(V).size();
> +    if (NumLoops > 1)
> +      OS << "\t(mustexec in " << NumLoops << " loops: ";
> +    else
> +      OS << "\t(mustexec in: ";
> +
> +    bool first = true;
> +    for (const Loop *L : MustExec.lookup(V)) {
> +      if (!first)
> +        OS << ", ";
> +      first = false;
> +      OS << L->getHeader()->getName();
> +    }
> +    OS << ")\n";
> +  }
> +  OS << "\n";
> +}
>
> Added: llvm/trunk/test/Analysis/MustExecute/loop-header.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/MustExecute/loop-header.ll?rev=328004&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/Analysis/MustExecute/loop-header.ll (added)
> +++ llvm/trunk/test/Analysis/MustExecute/loop-header.ll Tue Mar 20
> 10:09:21 2018
> @@ -0,0 +1,80 @@
> +; RUN: opt -analyze -print-mustexecute %s
> +
> +; CHECK: Printing analysis 'Instructions which execute on loop entry' for
> function 'header_with_icf':
> +; CHECK: The following are guaranteed to execute (for the respective
> loops):
> +; CHECK:   %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]    (mustexec
> in: loop)
> +; CHECK:   %v = load i32, i32* %p      (mustexec in: loop)
> +; CHECK:   call void @maythrow_and_use(i32 %v) (mustexec in: loop)
> +; CHECK-NOT: add
> +define i1 @header_with_icf(i32* noalias %p, i32 %high) {
> +entry:
> +  br label %loop
> +
> +loop:
> +  %iv = phi i32 [0, %entry], [%iv.next, %loop]
> +  %v = load i32, i32* %p
> +  call void @maythrow_and_use(i32 %v)
> +  %iv.next = add nsw nuw i32 %iv, 1
> +  %exit.test = icmp slt i32 %iv, %high
> +  br i1 %exit.test, label %exit, label %loop
> +
> +exit:
> +  ret i1 false
> +}
> +
> +; CHECK: Printing analysis 'Instructions which execute on loop entry' for
> function 'test':
> +; CHECK: The following are guaranteed to execute (for the respective
> loops):
> +; CHECK:   %iv = phi i32 [ 0, %entry ], [ %iv.next, %next ]    (mustexec
> in: loop)
> +; CHECK:   %v = load i32, i32* %p      (mustexec in: loop)
> +; CHECK:   br label %next      (mustexec in: loop)
> +define i1 @test(i32* noalias %p, i32 %high) {
> +entry:
> +  br label %loop
> +
> +loop:
> +  %iv = phi i32 [0, %entry], [%iv.next, %next]
> +  %v = load i32, i32* %p
> +  br label %next
> +next:
> +  call void @maythrow_and_use(i32 %v)
> +  %iv.next = add nsw nuw i32 %iv, 1
> +  %exit.test = icmp slt i32 %iv, %high
> +  br i1 %exit.test, label %exit, label %loop
> +
> +exit:
> +  ret i1 false
> +}
> +
> +; CHECK: Printing analysis 'Instructions which execute on loop entry' for
> function 'nested':
> +; CHECK: The following are guaranteed to execute (for the respective
> loops):
> +; CHECK:   %iv = phi i32 [ 0, %entry ], [ %iv.next, %next ]    (mustexec
> in: loop)
> +; CHECK:   br label %inner_loop        (mustexec in: loop)
> +; FIXME: These three are also must execute for the outer loop.
> +; CHECK:   %v = load i32, i32* %p      (mustexec in: inner_loop)
> +; CHECK:   %inner.test = icmp eq i32 %v, 0     (mustexec in: inner_loop)
> +; CHECK:   br i1 %inner.test, label %inner_loop, label %next   (mustexec
> in: inner_loop)
> +define i1 @nested(i32* noalias %p, i32 %high) {
> +entry:
> +  br label %loop
> +
> +loop:
> +  %iv = phi i32 [0, %entry], [%iv.next, %next]
> +  br label %inner_loop
> +
> +inner_loop:
> +  %v = load i32, i32* %p
> +  %inner.test = icmp eq i32 %v, 0
> +  br i1 %inner.test, label %inner_loop, label %next
> +
> +next:
> +  call void @maythrow_and_use(i32 %v)
> +  %iv.next = add nsw nuw i32 %iv, 1
> +  %exit.test = icmp slt i32 %iv, %high
> +  br i1 %exit.test, label %exit, label %loop
> +
> +exit:
> +  ret i1 false
> +}
> +
> +
> +declare void @maythrow_and_use(i32)
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://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/20180328/dcba06b2/attachment.html>


More information about the llvm-commits mailing list