206 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			206 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C++
		
	
	
	
//===- llvm/unittest/Analysis/LoopPassManagerTest.cpp - LPM tests ---------===//
 | 
						|
//
 | 
						|
//                     The LLVM Compiler Infrastructure
 | 
						|
//
 | 
						|
// This file is distributed under the University of Illinois Open Source
 | 
						|
// License. See LICENSE.TXT for details.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "gtest/gtest.h"
 | 
						|
#include "llvm/Analysis/LoopPassManager.h"
 | 
						|
#include "llvm/AsmParser/Parser.h"
 | 
						|
#include "llvm/IR/Dominators.h"
 | 
						|
#include "llvm/IR/Function.h"
 | 
						|
#include "llvm/IR/LLVMContext.h"
 | 
						|
#include "llvm/IR/Module.h"
 | 
						|
#include "llvm/IR/PassManager.h"
 | 
						|
#include "llvm/Support/SourceMgr.h"
 | 
						|
 | 
						|
using namespace llvm;
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
class TestLoopAnalysis {
 | 
						|
  /// \brief Private static data to provide unique ID.
 | 
						|
  static char PassID;
 | 
						|
 | 
						|
  int &Runs;
 | 
						|
 | 
						|
public:
 | 
						|
  struct Result {
 | 
						|
    Result(int Count) : BlockCount(Count) {}
 | 
						|
    int BlockCount;
 | 
						|
  };
 | 
						|
 | 
						|
  /// \brief Returns an opaque, unique ID for this pass type.
 | 
						|
  static void *ID() { return (void *)&PassID; }
 | 
						|
 | 
						|
  /// \brief Returns the name of the analysis.
 | 
						|
  static StringRef name() { return "TestLoopAnalysis"; }
 | 
						|
 | 
						|
  TestLoopAnalysis(int &Runs) : Runs(Runs) {}
 | 
						|
 | 
						|
  /// \brief Run the analysis pass over the loop and return a result.
 | 
						|
  Result run(Loop &L, AnalysisManager<Loop> &AM) {
 | 
						|
    ++Runs;
 | 
						|
    int Count = 0;
 | 
						|
 | 
						|
    for (auto I = L.block_begin(), E = L.block_end(); I != E; ++I)
 | 
						|
      ++Count;
 | 
						|
    return Result(Count);
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
char TestLoopAnalysis::PassID;
 | 
						|
 | 
						|
class TestLoopPass {
 | 
						|
  std::vector<StringRef> &VisitedLoops;
 | 
						|
  int &AnalyzedBlockCount;
 | 
						|
  bool OnlyUseCachedResults;
 | 
						|
 | 
						|
public:
 | 
						|
  TestLoopPass(std::vector<StringRef> &VisitedLoops, int &AnalyzedBlockCount,
 | 
						|
               bool OnlyUseCachedResults = false)
 | 
						|
      : VisitedLoops(VisitedLoops), AnalyzedBlockCount(AnalyzedBlockCount),
 | 
						|
        OnlyUseCachedResults(OnlyUseCachedResults) {}
 | 
						|
 | 
						|
  PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &AM) {
 | 
						|
    VisitedLoops.push_back(L.getName());
 | 
						|
 | 
						|
    if (OnlyUseCachedResults) {
 | 
						|
      // Hack to force the use of the cached interface.
 | 
						|
      if (auto *AR = AM.getCachedResult<TestLoopAnalysis>(L))
 | 
						|
        AnalyzedBlockCount += AR->BlockCount;
 | 
						|
    } else {
 | 
						|
      // Typical path just runs the analysis as needed.
 | 
						|
      auto &AR = AM.getResult<TestLoopAnalysis>(L);
 | 
						|
      AnalyzedBlockCount += AR.BlockCount;
 | 
						|
    }
 | 
						|
 | 
						|
    return PreservedAnalyses::all();
 | 
						|
  }
 | 
						|
 | 
						|
  static StringRef name() { return "TestLoopPass"; }
 | 
						|
};
 | 
						|
 | 
						|
// A test loop pass that invalidates the analysis for loops with the given name.
 | 
						|
class TestLoopInvalidatingPass {
 | 
						|
  StringRef Name;
 | 
						|
 | 
						|
public:
 | 
						|
  TestLoopInvalidatingPass(StringRef LoopName) : Name(LoopName) {}
 | 
						|
 | 
						|
  PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &AM) {
 | 
						|
    return L.getName() == Name ? getLoopPassPreservedAnalyses()
 | 
						|
                               : PreservedAnalyses::all();
 | 
						|
  }
 | 
						|
 | 
						|
  static StringRef name() { return "TestLoopInvalidatingPass"; }
 | 
						|
};
 | 
						|
 | 
						|
std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
 | 
						|
  SMDiagnostic Err;
 | 
						|
  return parseAssemblyString(IR, Err, C);
 | 
						|
}
 | 
						|
 | 
						|
class LoopPassManagerTest : public ::testing::Test {
 | 
						|
protected:
 | 
						|
  LLVMContext Context;
 | 
						|
  std::unique_ptr<Module> M;
 | 
						|
 | 
						|
public:
 | 
						|
  LoopPassManagerTest()
 | 
						|
      : M(parseIR(Context, "define void @f() {\n"
 | 
						|
                           "entry:\n"
 | 
						|
                           "  br label %loop.0\n"
 | 
						|
                           "loop.0:\n"
 | 
						|
                           "  br i1 undef, label %loop.0.0, label %end\n"
 | 
						|
                           "loop.0.0:\n"
 | 
						|
                           "  br i1 undef, label %loop.0.0, label %loop.0.1\n"
 | 
						|
                           "loop.0.1:\n"
 | 
						|
                           "  br i1 undef, label %loop.0.1, label %loop.0\n"
 | 
						|
                           "end:\n"
 | 
						|
                           "  ret void\n"
 | 
						|
                           "}\n"
 | 
						|
                           "\n"
 | 
						|
                           "define void @g() {\n"
 | 
						|
                           "entry:\n"
 | 
						|
                           "  br label %loop.g.0\n"
 | 
						|
                           "loop.g.0:\n"
 | 
						|
                           "  br i1 undef, label %loop.g.0, label %end\n"
 | 
						|
                           "end:\n"
 | 
						|
                           "  ret void\n"
 | 
						|
                           "}\n")) {}
 | 
						|
};
 | 
						|
 | 
						|
#define EXPECT_N_ELEMENTS_EQ(N, EXPECTED, ACTUAL)                              \
 | 
						|
  do {                                                                         \
 | 
						|
    EXPECT_EQ(N##UL, ACTUAL.size());                                           \
 | 
						|
    for (int I = 0; I < N; ++I)                                                \
 | 
						|
      EXPECT_TRUE(EXPECTED[I] == ACTUAL[I]) << "Element " << I << " is "       \
 | 
						|
                                            << ACTUAL[I] << ". Expected "      \
 | 
						|
                                            << EXPECTED[I] << ".";             \
 | 
						|
  } while (0)
 | 
						|
 | 
						|
TEST_F(LoopPassManagerTest, Basic) {
 | 
						|
  LoopAnalysisManager LAM(true);
 | 
						|
  int LoopAnalysisRuns = 0;
 | 
						|
  LAM.registerPass([&] { return TestLoopAnalysis(LoopAnalysisRuns); });
 | 
						|
 | 
						|
  FunctionAnalysisManager FAM(true);
 | 
						|
  // We need DominatorTreeAnalysis for LoopAnalysis.
 | 
						|
  FAM.registerPass([&] { return DominatorTreeAnalysis(); });
 | 
						|
  FAM.registerPass([&] { return LoopAnalysis(); });
 | 
						|
  FAM.registerPass([&] { return LoopAnalysisManagerFunctionProxy(LAM); });
 | 
						|
  LAM.registerPass([&] { return FunctionAnalysisManagerLoopProxy(FAM); });
 | 
						|
 | 
						|
  ModuleAnalysisManager MAM(true);
 | 
						|
  MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
 | 
						|
  FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
 | 
						|
 | 
						|
  ModulePassManager MPM(true);
 | 
						|
  FunctionPassManager FPM(true);
 | 
						|
 | 
						|
  // Visit all of the loops.
 | 
						|
  std::vector<StringRef> VisitedLoops1;
 | 
						|
  int AnalyzedBlockCount1 = 0;
 | 
						|
  {
 | 
						|
    LoopPassManager LPM;
 | 
						|
    LPM.addPass(TestLoopPass(VisitedLoops1, AnalyzedBlockCount1));
 | 
						|
 | 
						|
    FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM)));
 | 
						|
  }
 | 
						|
 | 
						|
  // Only use cached analyses.
 | 
						|
  std::vector<StringRef> VisitedLoops2;
 | 
						|
  int AnalyzedBlockCount2 = 0;
 | 
						|
  {
 | 
						|
    LoopPassManager LPM;
 | 
						|
    LPM.addPass(TestLoopInvalidatingPass("loop.g.0"));
 | 
						|
    LPM.addPass(TestLoopPass(VisitedLoops2, AnalyzedBlockCount2,
 | 
						|
                             /*OnlyUseCachedResults=*/true));
 | 
						|
 | 
						|
    FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM)));
 | 
						|
  }
 | 
						|
 | 
						|
  MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
 | 
						|
  MPM.run(*M, MAM);
 | 
						|
 | 
						|
  StringRef ExpectedLoops[] = {"loop.0.0", "loop.0.1", "loop.0", "loop.g.0"};
 | 
						|
 | 
						|
  // Validate the counters and order of loops visited.
 | 
						|
  // loop.0 has 3 blocks whereas loop.0.0, loop.0.1, and loop.g.0 each have 1.
 | 
						|
  EXPECT_N_ELEMENTS_EQ(4, ExpectedLoops, VisitedLoops1);
 | 
						|
  EXPECT_EQ(6, AnalyzedBlockCount1);
 | 
						|
 | 
						|
  EXPECT_N_ELEMENTS_EQ(4, ExpectedLoops, VisitedLoops2);
 | 
						|
  // The block from loop.g.0 won't be counted, since it wasn't cached.
 | 
						|
  EXPECT_EQ(5, AnalyzedBlockCount2);
 | 
						|
 | 
						|
  // The first LPM runs the loop analysis for all four loops, the second uses
 | 
						|
  // cached results for everything.
 | 
						|
  EXPECT_EQ(4, LoopAnalysisRuns);
 | 
						|
}
 | 
						|
}
 |