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 @@ -1,4 +1,4 @@ -//==- FunctionPropertiesAnalysis.h - Function Properties Analysis -*-C++ -*-==// +//=- FunctionPropertiesAnalysis.h - Function Properties Analysis --*- C++ -*-=// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -41,6 +41,8 @@ int64_t DirectCallsToDefinedFunctions = 0; static FunctionPropertiesInfo getFunctionPropertiesInfo(const Function &F); + + void print(raw_ostream &OS) const; }; // Analysis pass @@ -55,5 +57,16 @@ Result run(Function &F, FunctionAnalysisManager &FAM); }; +/// Printer pass for the FunctionPropertiesAnalysis results. +class FunctionPropertiesPrinterPass + : public PassInfoMixin { + raw_ostream &OS; + +public: + explicit FunctionPropertiesPrinterPass(raw_ostream &OS) : OS(OS) {} + + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; + } // namespace llvm #endif // LLVM_FUNCTIONPROPERTIESANALYSIS_H_ \ No newline at end of file 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 @@ -1,4 +1,4 @@ -//===- FunctionPropertiesAnalysis.cpp - Function properties extraction ----===// +//===- FunctionPropertiesAnalysis.cpp - Function Properties Analysis ------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// // -// This file implements an analysis extracting function properties, which may be -// used by ML-driven policies, for example. +// This file defines the FunctionPropertiesInfo and FunctionPropertiesAnalysis +// classes used to extract function properties. // //===----------------------------------------------------------------------===// @@ -45,9 +45,27 @@ return FPI; } +void FunctionPropertiesInfo::print(raw_ostream &OS) const { + OS << "BasicBlockCount: " << BasicBlockCount << "\n" + << "BlocksReachedFromConditionalInstruction: " + << BlocksReachedFromConditionalInstruction << "\n" + << "Uses: " << Uses << "\n" + << "DirectCallsToDefinedFunctions: " << DirectCallsToDefinedFunctions + << "\n\n"; +} + AnalysisKey FunctionPropertiesAnalysis::Key; FunctionPropertiesInfo FunctionPropertiesAnalysis::run(Function &F, FunctionAnalysisManager &FAM) { return FunctionPropertiesInfo::getFunctionPropertiesInfo(F); +} + +PreservedAnalyses +FunctionPropertiesPrinterPass::run(Function &F, FunctionAnalysisManager &AM) { + OS << "Printing analysis results of CFA for function " + << "'" << F.getName() << "':" + << "\n"; + AM.getResult(F).print(OS); + return PreservedAnalyses::all(); } \ No newline at end of file diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -129,10 +129,10 @@ FUNCTION_ANALYSIS("postdomtree", PostDominatorTreeAnalysis()) FUNCTION_ANALYSIS("demanded-bits", DemandedBitsAnalysis()) FUNCTION_ANALYSIS("domfrontier", DominanceFrontierAnalysis()) +FUNCTION_ANALYSIS("func-properties", FunctionPropertiesAnalysis()) FUNCTION_ANALYSIS("loops", LoopAnalysis()) FUNCTION_ANALYSIS("lazy-value-info", LazyValueAnalysis()) FUNCTION_ANALYSIS("da", DependenceAnalysis()) -FUNCTION_ANALYSIS("func-properties", FunctionPropertiesAnalysis()) FUNCTION_ANALYSIS("inliner-size-estimator", InlineSizeEstimatorAnalysis()) FUNCTION_ANALYSIS("memdep", MemoryDependenceAnalysis()) FUNCTION_ANALYSIS("memoryssa", MemorySSAAnalysis()) @@ -234,6 +234,7 @@ FUNCTION_PASS("print", PostDominatorTreePrinterPass(dbgs())) FUNCTION_PASS("print", DemandedBitsPrinterPass(dbgs())) FUNCTION_PASS("print", DominanceFrontierPrinterPass(dbgs())) +FUNCTION_PASS("print", FunctionPropertiesPrinterPass(dbgs())) FUNCTION_PASS("print", InlineCostAnnotationPrinterPass(dbgs())) FUNCTION_PASS("print", InlineSizeEstimatorAnalysisPrinterPass(dbgs())) diff --git a/llvm/test/Analysis/FunctionPropertiesAnalysis/matmul.ll b/llvm/test/Analysis/FunctionPropertiesAnalysis/matmul.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Analysis/FunctionPropertiesAnalysis/matmul.ll @@ -0,0 +1,132 @@ +; RUN: opt < %s -passes='print' -disable-output 2>&1 | FileCheck %s + +define i32 @main() { +; CHECK-DAG: Printing analysis results of CFA for function 'main': + +entry: + %retval = alloca i32, align 4 + %mat1 = alloca [2 x [2 x i32]], align 16 + %mat2 = alloca [2 x [2 x i32]], align 16 + %res = alloca [2 x [2 x i32]], align 16 + %i = alloca i32, align 4 + %j = alloca i32, align 4 + store i32 0, i32* %retval, align 4 + %arraydecay = getelementptr inbounds [2 x [2 x i32]], [2 x [2 x i32]]* %mat1, i64 0, i64 0 + %arraydecay1 = getelementptr inbounds [2 x [2 x i32]], [2 x [2 x i32]]* %mat2, i64 0, i64 0 + %arraydecay2 = getelementptr inbounds [2 x [2 x i32]], [2 x [2 x i32]]* %res, i64 0, i64 0 + call void @multiply([2 x i32]* %arraydecay, [2 x i32]* %arraydecay1, [2 x i32]* %arraydecay2) + ret i32 0 +} +; CHECK-DAG: BasicBlockCount: 1 +; CHECK-DAG: BlocksReachedFromConditionalInstruction: 0 +; CHECK-DAG: Uses: 1 +; CHECK-DAG: DirectCallsToDefinedFunctions: 1 + +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': +entry: + %mat1.addr = alloca [2 x i32]*, align 8 + %mat2.addr = alloca [2 x i32]*, align 8 + %res.addr = alloca [2 x i32]*, align 8 + %i = alloca i32, align 4 + %j = alloca i32, align 4 + %k = alloca i32, align 4 + store [2 x i32]* %mat1, [2 x i32]** %mat1.addr, align 8 + store [2 x i32]* %mat2, [2 x i32]** %mat2.addr, align 8 + store [2 x i32]* %res, [2 x i32]** %res.addr, align 8 + store i32 0, i32* %i, align 4 + br label %for.cond + +for.cond: ; preds = %for.inc24, %entry + %0 = load i32, i32* %i, align 4 + %cmp = icmp slt i32 %0, 2 + br i1 %cmp, label %for.body, label %for.end26 + +for.body: ; preds = %for.cond + store i32 0, i32* %j, align 4 + br label %for.cond1 + +for.cond1: ; preds = %for.inc21, %for.body + %1 = load i32, i32* %j, align 4 + %cmp2 = icmp slt i32 %1, 2 + br i1 %cmp2, label %for.body3, label %for.end23 + +for.body3: ; preds = %for.cond1 + %2 = load [2 x i32]*, [2 x i32]** %res.addr, align 8 + %3 = load i32, i32* %i, align 4 + %idxprom = sext i32 %3 to i64 + %arrayidx = getelementptr inbounds [2 x i32], [2 x i32]* %2, i64 %idxprom + %4 = load i32, i32* %j, align 4 + %idxprom4 = sext i32 %4 to i64 + %arrayidx5 = getelementptr inbounds [2 x i32], [2 x i32]* %arrayidx, i64 0, i64 %idxprom4 + store i32 0, i32* %arrayidx5, align 4 + store i32 0, i32* %k, align 4 + br label %for.cond6 + +for.cond6: ; preds = %for.inc, %for.body3 + %5 = load i32, i32* %k, align 4 + %cmp7 = icmp slt i32 %5, 2 + br i1 %cmp7, label %for.body8, label %for.end + +for.body8: ; preds = %for.cond6 + %6 = load [2 x i32]*, [2 x i32]** %mat1.addr, align 8 + %7 = load i32, i32* %i, align 4 + %idxprom9 = sext i32 %7 to i64 + %arrayidx10 = getelementptr inbounds [2 x i32], [2 x i32]* %6, i64 %idxprom9 + %8 = load i32, i32* %k, align 4 + %idxprom11 = sext i32 %8 to i64 + %arrayidx12 = getelementptr inbounds [2 x i32], [2 x i32]* %arrayidx10, i64 0, i64 %idxprom11 + %9 = load i32, i32* %arrayidx12, align 4 + %10 = load [2 x i32]*, [2 x i32]** %mat2.addr, align 8 + %11 = load i32, i32* %k, align 4 + %idxprom13 = sext i32 %11 to i64 + %arrayidx14 = getelementptr inbounds [2 x i32], [2 x i32]* %10, i64 %idxprom13 + %12 = load i32, i32* %j, align 4 + %idxprom15 = sext i32 %12 to i64 + %arrayidx16 = getelementptr inbounds [2 x i32], [2 x i32]* %arrayidx14, i64 0, i64 %idxprom15 + %13 = load i32, i32* %arrayidx16, align 4 + %mul = mul nsw i32 %9, %13 + %14 = load [2 x i32]*, [2 x i32]** %res.addr, align 8 + %15 = load i32, i32* %i, align 4 + %idxprom17 = sext i32 %15 to i64 + %arrayidx18 = getelementptr inbounds [2 x i32], [2 x i32]* %14, i64 %idxprom17 + %16 = load i32, i32* %j, align 4 + %idxprom19 = sext i32 %16 to i64 + %arrayidx20 = getelementptr inbounds [2 x i32], [2 x i32]* %arrayidx18, i64 0, i64 %idxprom19 + %17 = load i32, i32* %arrayidx20, align 4 + %add = add nsw i32 %17, %mul + store i32 %add, i32* %arrayidx20, align 4 + br label %for.inc + +for.inc: ; preds = %for.body8 + %18 = load i32, i32* %k, align 4 + %inc = add nsw i32 %18, 1 + store i32 %inc, i32* %k, align 4 + br label %for.cond6 + +for.end: ; preds = %for.cond6 + br label %for.inc21 + +for.inc21: ; preds = %for.end + %19 = load i32, i32* %j, align 4 + %inc22 = add nsw i32 %19, 1 + store i32 %inc22, i32* %j, align 4 + br label %for.cond1 + +for.end23: ; preds = %for.cond1 + br label %for.inc24 + +for.inc24: ; preds = %for.end23 + %20 = load i32, i32* %i, align 4 + %inc25 = add nsw i32 %20, 1 + store i32 %inc25, i32* %i, align 4 + br label %for.cond + +for.end26: ; preds = %for.cond + ret void +} + +; CHECK-DAG: BasicBlockCount: 13 +; CHECK-DAG: BlocksReachedFromConditionalInstruction: 6 +; CHECK-DAG: Uses: 2 +; CHECK-DAG: DirectCallsToDefinedFunctions: 0 \ 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 @@ -59,9 +59,9 @@ )IR"); FunctionAnalysisManager FAM; - FunctionPropertiesAnalysis FA; + FunctionPropertiesAnalysis FPA; - auto BranchesFeatures = FA.run(*M->getFunction("branches"), FAM); + auto BranchesFeatures = FPA.run(*M->getFunction("branches"), FAM); EXPECT_EQ(BranchesFeatures.BasicBlockCount, 4); EXPECT_EQ(BranchesFeatures.BlocksReachedFromConditionalInstruction, 2); EXPECT_EQ(BranchesFeatures.DirectCallsToDefinedFunctions, 0); @@ -69,7 +69,7 @@ // so it may have external callers. EXPECT_EQ(BranchesFeatures.Uses, 2); - auto TopFeatures = FA.run(*M->getFunction("top"), FAM); + auto TopFeatures = FPA.run(*M->getFunction("top"), FAM); EXPECT_EQ(TopFeatures.BasicBlockCount, 1); EXPECT_EQ(TopFeatures.BlocksReachedFromConditionalInstruction, 0); EXPECT_EQ(TopFeatures.DirectCallsToDefinedFunctions, 1);