Index: llvm/include/llvm/Analysis/ML/FunctionPropertiesAnalysis.h
===================================================================
--- llvm/include/llvm/Analysis/ML/FunctionPropertiesAnalysis.h
+++ llvm/include/llvm/Analysis/ML/FunctionPropertiesAnalysis.h
@@ -1,3 +1,16 @@
+//===- 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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the FunctionPropertiesInfo and FunctionPropertiesAnalysis 
+// classes used to extract function properties. 
+//
+//===----------------------------------------------------------------------===//
+
 #ifndef LLVM_FUNCTIONPROPERTIESANALYSIS_H_
 #define LLVM_FUNCTIONPROPERTIESANALYSIS_H_
 
@@ -6,11 +19,8 @@
 namespace llvm {
 class Function;
 
-class FunctionPropertiesAnalysis
-    : public AnalysisInfoMixin<FunctionPropertiesAnalysis> {
-public:
-  static AnalysisKey Key;
-  struct Result {
+class FunctionPropertiesInfo{
+  public:
     /// Number of basic blocks
     int64_t BasicBlockCount = 0;
 
@@ -29,8 +39,33 @@
     /// Number of direct calls made from this function to other functions
     /// defined in this module.
     int64_t DirectCallsToDefinedFunctions = 0;
-  };
-  Result run(const Function &F, FunctionAnalysisManager &FAM);
+
+    void analyze(const Function &F);
+
+    void print(raw_ostream &OS) const;
+};
+
+//Analysis pass
+class FunctionPropertiesAnalysis 
+    : public AnalysisInfoMixin<FunctionPropertiesAnalysis> {
+
+  public:
+    static AnalysisKey Key;
+
+    using Result = FunctionPropertiesInfo;
+    
+    Result run(Function &F, FunctionAnalysisManager &FAM);
+};
+
+/// Printer pass for the FunctionPropertiesAnalysis results.
+class FunctionPropertiesPrinterPass
+    : public PassInfoMixin<FunctionPropertiesPrinterPass> {
+  raw_ostream &OS;
+
+public:
+  explicit FunctionPropertiesPrinterPass(raw_ostream &OS) : OS(OS) {}
+
+  PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
 };
 
 } // namespace llvm
Index: llvm/lib/Analysis/ML/FunctionPropertiesAnalysis.cpp
===================================================================
--- llvm/lib/Analysis/ML/FunctionPropertiesAnalysis.cpp
+++ llvm/lib/Analysis/ML/FunctionPropertiesAnalysis.cpp
@@ -1,28 +1,69 @@
+//===- 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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the FunctionPropertiesInfo and FunctionPropertiesAnalysis 
+// classes used to extract function properties. 
+//
+//===----------------------------------------------------------------------===//
+
 #include "llvm/Analysis/ML/FunctionPropertiesAnalysis.h"
 #include "llvm/IR/Instructions.h"
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/Passes/PassPlugin.h"
+#include "llvm/Support/raw_ostream.h"
 
 using namespace llvm;
 
-AnalysisKey FunctionPropertiesAnalysis::Key;
+void FunctionPropertiesInfo::analyze(const Function &F) {
+  
+  Uses = ((!F.hasLocalLinkage()) ? 1 : 0) + F.getNumUses();
 
-FunctionPropertiesAnalysis::Result
-FunctionPropertiesAnalysis::run(const Function &F, FunctionAnalysisManager &FAM) {
-  Result Ret;
-  Ret.Uses = ((!F.hasLocalLinkage()) ? 1 : 0) + F.getNumUses();
   for (const auto &BB : F) {
-    ++Ret.BasicBlockCount;
+    ++BasicBlockCount;
+    
     if (const auto *BI = dyn_cast<BranchInst>(BB.getTerminator())) {
       if (BI->isConditional())
-        Ret.BlocksReachedFromConditionalInstruction += BI->getNumSuccessors();
-    } else if (const auto *SI = dyn_cast<SwitchInst>(BB.getTerminator()))
-      Ret.BlocksReachedFromConditionalInstruction +=
+        BlocksReachedFromConditionalInstruction += BI->getNumSuccessors();
+    } else if (const auto *SI = dyn_cast<SwitchInst>(BB.getTerminator())) {
+      BlocksReachedFromConditionalInstruction +=
           (SI->getNumCases() + (nullptr != SI->getDefaultDest()));
-    for (const auto &I : BB)
+    }
+
+    for (const auto &I : BB) {
       if (auto *CS = dyn_cast<CallBase>(&I)) {
         const auto *Callee = CS->getCalledFunction();
         if (Callee && !Callee->isIntrinsic() && !Callee->isDeclaration())
-          ++Ret.DirectCallsToDefinedFunctions;
+          ++DirectCallsToDefinedFunctions;
       }
+    }
   }
-  return Ret;
-}
\ No newline at end of file
+}
+
+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) {
+  FunctionPropertiesInfo FPI;
+  FPI.analyze(F);
+  return FPI;
+}
+
+
+PreservedAnalyses FunctionPropertiesPrinterPass::run(Function &F, FunctionAnalysisManager &AM) {
+  OS << "Printing analysis results of CFA for function "
+     << "'" << F.getName() << "':"
+     << "\n";
+  AM.getResult<FunctionPropertiesAnalysis>(F).print(OS);
+  return PreservedAnalyses::all();
+}
Index: llvm/lib/Passes/PassRegistry.def
===================================================================
--- llvm/lib/Passes/PassRegistry.def
+++ llvm/lib/Passes/PassRegistry.def
@@ -130,10 +130,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("memdep", MemoryDependenceAnalysis())
 FUNCTION_ANALYSIS("memoryssa", MemorySSAAnalysis())
 FUNCTION_ANALYSIS("phi-values", PhiValuesAnalysis())
@@ -233,6 +233,7 @@
 FUNCTION_PASS("print<postdomtree>", PostDominatorTreePrinterPass(dbgs()))
 FUNCTION_PASS("print<demanded-bits>", DemandedBitsPrinterPass(dbgs()))
 FUNCTION_PASS("print<domfrontier>", DominanceFrontierPrinterPass(dbgs()))
+FUNCTION_PASS("print<func-properties>", FunctionPropertiesPrinterPass(dbgs()))
 FUNCTION_PASS("print<loops>", LoopPrinterPass(dbgs()))
 FUNCTION_PASS("print<memoryssa>", MemorySSAPrinterPass(dbgs()))
 FUNCTION_PASS("print<phi-values>", PhiValuesPrinterPass(dbgs()))
Index: llvm/test/Analysis/ML/FunctionPropertiesAnalysis/matmul.ll
===================================================================
--- /dev/null
+++ llvm/test/Analysis/ML/FunctionPropertiesAnalysis/matmul.ll
@@ -0,0 +1,132 @@
+; RUN: opt < %s -passes='print<func-properties>' -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
Index: llvm/unittests/Analysis/ML/FunctionPropertiesAnalysisTest.cpp
===================================================================
--- llvm/unittests/Analysis/ML/FunctionPropertiesAnalysisTest.cpp
+++ llvm/unittests/Analysis/ML/FunctionPropertiesAnalysisTest.cpp
@@ -1,4 +1,4 @@
-//===- FunctionPropertiesAnalysisTest.cpp - function properties unit tests --------===//
+//===- FunctionPropertiesAnalysisTest.cpp - Function Properties Unit Tests -===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.