diff --git a/llvm/include/llvm/Analysis/FunctionPropertiesAnalysis.h b/llvm/include/llvm/Analysis/FunctionPropertiesAnalysis.h --- a/llvm/include/llvm/Analysis/FunctionPropertiesAnalysis.h +++ b/llvm/include/llvm/Analysis/FunctionPropertiesAnalysis.h @@ -14,6 +14,7 @@ #ifndef LLVM_FUNCTIONPROPERTIESANALYSIS_H_ #define LLVM_FUNCTIONPROPERTIESANALYSIS_H_ +#include "llvm/Analysis/LoopInfo.h" #include "llvm/IR/PassManager.h" namespace llvm { @@ -21,6 +22,11 @@ class FunctionPropertiesInfo { public: + static FunctionPropertiesInfo getFunctionPropertiesInfo(const Function &F, + const LoopInfo &LI); + + void print(raw_ostream &OS) const; + /// Number of basic blocks int64_t BasicBlockCount = 0; @@ -40,9 +46,17 @@ /// defined in this module. int64_t DirectCallsToDefinedFunctions = 0; - static FunctionPropertiesInfo getFunctionPropertiesInfo(const Function &F); + // Load Instruction Count + int64_t LoadInstCount = 0; - void print(raw_ostream &OS) const; + // Store Instruction Count + int64_t StoreInstCount = 0; + + // Maximum Loop Depth in the Function + int64_t MaxLoopDepth = 0; + + // Number of Top Level Loops in the Function + int64_t TopLevelLoopCount = 0; }; // Analysis pass diff --git a/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp b/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp --- a/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp +++ b/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp @@ -17,7 +17,8 @@ using namespace llvm; FunctionPropertiesInfo -FunctionPropertiesInfo::getFunctionPropertiesInfo(const Function &F) { +FunctionPropertiesInfo::getFunctionPropertiesInfo(const Function &F, + const LoopInfo &LI) { FunctionPropertiesInfo FPI; @@ -40,7 +41,20 @@ if (Callee && !Callee->isIntrinsic() && !Callee->isDeclaration()) ++FPI.DirectCallsToDefinedFunctions; } + if (I.getOpcode() == Instruction::Load) { + ++FPI.LoadInstCount; + } else if (I.getOpcode() == Instruction::Store) { + ++FPI.StoreInstCount; + } } + // Loop Depth of the Basic Block + int64_t LoopDepth; + LoopDepth = LI.getLoopDepth(&BB); + if (FPI.MaxLoopDepth < LoopDepth) + FPI.MaxLoopDepth = LoopDepth; + } + for (Loop *L : LI) { + ++FPI.TopLevelLoopCount; } return FPI; } @@ -51,14 +65,19 @@ << BlocksReachedFromConditionalInstruction << "\n" << "Uses: " << Uses << "\n" << "DirectCallsToDefinedFunctions: " << DirectCallsToDefinedFunctions - << "\n\n"; + << "\n" + << "LoadInstCount: " << LoadInstCount << "\n" + << "StoreInstCount: " << StoreInstCount << "\n" + << "MaxLoopDepth: " << MaxLoopDepth << "\n" + << "TopLevelLoopCount: " << TopLevelLoopCount << "\n\n"; } AnalysisKey FunctionPropertiesAnalysis::Key; FunctionPropertiesInfo FunctionPropertiesAnalysis::run(Function &F, FunctionAnalysisManager &FAM) { - return FunctionPropertiesInfo::getFunctionPropertiesInfo(F); + return FunctionPropertiesInfo::getFunctionPropertiesInfo( + F, FAM.getResult(F)); } PreservedAnalyses diff --git a/llvm/test/Analysis/FunctionPropertiesAnalysis/matmul.ll b/llvm/test/Analysis/FunctionPropertiesAnalysis/matmul.ll --- a/llvm/test/Analysis/FunctionPropertiesAnalysis/matmul.ll +++ b/llvm/test/Analysis/FunctionPropertiesAnalysis/matmul.ll @@ -21,6 +21,10 @@ ; CHECK-DAG: BlocksReachedFromConditionalInstruction: 0 ; CHECK-DAG: Uses: 1 ; CHECK-DAG: DirectCallsToDefinedFunctions: 1 +; CHECK-DAG: LoadInstCount: 0 +; CHECK-DAG: StoreInstCount: 1 +; CHECK-DAG: MaxLoopDepth: 0 +; CHECK-DAG: TopLevelLoopCount: 0 define void @multiply([2 x i32]* %mat1, [2 x i32]* %mat2, [2 x i32]* %res) { ; CHECK-DAG: Printing analysis results of CFA for function 'multiply': @@ -129,4 +133,8 @@ ; CHECK-DAG: BasicBlockCount: 13 ; CHECK-DAG: BlocksReachedFromConditionalInstruction: 6 ; CHECK-DAG: Uses: 2 -; CHECK-DAG: DirectCallsToDefinedFunctions: 0 \ No newline at end of file +; CHECK-DAG: DirectCallsToDefinedFunctions: 0 +; CHECK-DAG: LoadInstCount: 21 +; CHECK-DAG: StoreInstCount: 11 +; CHECK-DAG: MaxLoopDepth: 3 +; CHECK-DAG: TopLevelLoopCount: 1 \ No newline at end of file diff --git a/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp b/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp --- a/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp +++ b/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp @@ -8,6 +8,7 @@ #include "llvm/Analysis/FunctionPropertiesAnalysis.h" #include "llvm/AsmParser/Parser.h" +#include "llvm/IR/Dominators.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" @@ -15,42 +16,49 @@ #include "gtest/gtest.h" using namespace llvm; +namespace { -static std::unique_ptr parseIR(LLVMContext &C, const char *IR) { - SMDiagnostic Err; - std::unique_ptr Mod = parseAssemblyString(IR, Err, C); - if (!Mod) - Err.print("MLAnalysisTests", errs()); - return Mod; -} +class FunctionPropertiesAnalysisTest : public testing::Test { +protected: + std::unique_ptr DT; + std::unique_ptr LI; + + FunctionPropertiesInfo buildFPI(Function &F) { + DT.reset(new DominatorTree(F)); + LI.reset(new LoopInfo(*DT)); + return FunctionPropertiesInfo::getFunctionPropertiesInfo(F, *LI); + } -TEST(FunctionPropertiesTest, BasicTest) { + std::unique_ptr makeLLVMModule(LLVMContext &C, const char *IR) { + SMDiagnostic Err; + std::unique_ptr Mod = parseAssemblyString(IR, Err, C); + if (!Mod) + Err.print("MLAnalysisTests", errs()); + return Mod; + } +}; + +TEST_F(FunctionPropertiesAnalysisTest, BasicTest) { LLVMContext C; - std::unique_ptr M = parseIR(C, - R"IR( + std::unique_ptr M = makeLLVMModule(C, + R"IR( target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-pc-linux-gnu" - declare i32 @f1(i32) declare i32 @f2(i32) - define i32 @branches(i32) { %cond = icmp slt i32 %0, 3 br i1 %cond, label %then, label %else - then: %ret.1 = call i32 @f1(i32 %0) br label %last.block - else: %ret.2 = call i32 @f2(i32 %0) br label %last.block - last.block: %ret = phi i32 [%ret.1, %then], [%ret.2, %else] ret i32 %ret } - define internal i32 @top() { %1 = call i32 @branches(i32 2) %2 = call i32 @f1(i32 %1) @@ -58,20 +66,28 @@ } )IR"); - FunctionAnalysisManager FAM; - FunctionPropertiesAnalysis FPA; - - auto BranchesFeatures = FPA.run(*M->getFunction("branches"), FAM); + Function *BranchesFunction = M->getFunction("branches"); + FunctionPropertiesInfo BranchesFeatures = buildFPI(*BranchesFunction); EXPECT_EQ(BranchesFeatures.BasicBlockCount, 4); EXPECT_EQ(BranchesFeatures.BlocksReachedFromConditionalInstruction, 2); - EXPECT_EQ(BranchesFeatures.DirectCallsToDefinedFunctions, 0); // 2 Users: top is one. The other is added because @branches is not internal, // so it may have external callers. EXPECT_EQ(BranchesFeatures.Uses, 2); + EXPECT_EQ(BranchesFeatures.DirectCallsToDefinedFunctions, 0); + EXPECT_EQ(BranchesFeatures.LoadInstCount, 0); + EXPECT_EQ(BranchesFeatures.StoreInstCount, 0); + EXPECT_EQ(BranchesFeatures.MaxLoopDepth, 0); + EXPECT_EQ(BranchesFeatures.TopLevelLoopCount, 0); - auto TopFeatures = FPA.run(*M->getFunction("top"), FAM); + Function *TopFunction = M->getFunction("top"); + FunctionPropertiesInfo TopFeatures = buildFPI(*TopFunction); EXPECT_EQ(TopFeatures.BasicBlockCount, 1); EXPECT_EQ(TopFeatures.BlocksReachedFromConditionalInstruction, 0); - EXPECT_EQ(TopFeatures.DirectCallsToDefinedFunctions, 1); EXPECT_EQ(TopFeatures.Uses, 0); + EXPECT_EQ(TopFeatures.DirectCallsToDefinedFunctions, 1); + EXPECT_EQ(BranchesFeatures.LoadInstCount, 0); + EXPECT_EQ(BranchesFeatures.StoreInstCount, 0); + EXPECT_EQ(BranchesFeatures.MaxLoopDepth, 0); + EXPECT_EQ(BranchesFeatures.TopLevelLoopCount, 0); } +} // end anonymous namespace \ No newline at end of file