[llvm] aad3641 - [FunctionPropertiesAnalysis] Add CFG and call properties

Aiden Grossman via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 25 15:02:48 PDT 2023


Author: Aiden Grossman
Date: 2023-08-25T15:02:09-07:00
New Revision: aad3641e80de0de149135e7ee1b5cf585c79b187

URL: https://github.com/llvm/llvm-project/commit/aad3641e80de0de149135e7ee1b5cf585c79b187
DIFF: https://github.com/llvm/llvm-project/commit/aad3641e80de0de149135e7ee1b5cf585c79b187.diff

LOG: [FunctionPropertiesAnalysis] Add CFG and call properties

This patch adds in a couple more properties related to call instructions
and the CFG within the function that should expose a little bit more
about the characteristics of the function.

Reviewed By: jdoerfert

Differential Revision: https://reviews.llvm.org/D158681

Added: 
    

Modified: 
    llvm/include/llvm/Analysis/FunctionPropertiesAnalysis.h
    llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp
    llvm/test/Analysis/FunctionPropertiesAnalysis/matmul.ll
    llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Analysis/FunctionPropertiesAnalysis.h b/llvm/include/llvm/Analysis/FunctionPropertiesAnalysis.h
index bce390be6dc7a0..310c369d9d4811 100644
--- a/llvm/include/llvm/Analysis/FunctionPropertiesAnalysis.h
+++ b/llvm/include/llvm/Analysis/FunctionPropertiesAnalysis.h
@@ -117,6 +117,24 @@ class FunctionPropertiesInfo {
   int64_t InlineAsmOperandCount = 0;
   int64_t ArgumentOperandCount = 0;
   int64_t UnknownOperandCount = 0;
+
+  // Additional CFG Properties
+  int64_t CriticalEdgeCount = 0;
+  int64_t ControlFlowEdgeCount = 0;
+  int64_t UnconditionalBranchCount = 0;
+
+  // Call related instructions
+  int64_t IntrinsicCount = 0;
+  int64_t DirectCallCount = 0;
+  int64_t IndirectCallCount = 0;
+  int64_t CallReturnsIntegerCount = 0;
+  int64_t CallReturnsFloatCount = 0;
+  int64_t CallReturnsPointerCount = 0;
+  int64_t CallReturnsVectorIntCount = 0;
+  int64_t CallReturnsVectorFloatCount = 0;
+  int64_t CallReturnsVectorPointerCount = 0;
+  int64_t CallWithManyArgumentsCount = 0;
+  int64_t CallWithPointerArgumentCount = 0;
 };
 
 // Analysis pass

diff  --git a/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp b/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp
index 55d5312b106606..97c54943ab6db6 100644
--- a/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp
+++ b/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp
@@ -19,6 +19,7 @@
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
 #include "llvm/Support/CommandLine.h"
 #include <deque>
 
@@ -38,6 +39,11 @@ cl::opt<unsigned> MediumBasicBlockInstructionThreshold(
     cl::desc("The minimum number of instructions a basic block should contain "
              "before being considered medium-sized."));
 
+cl::opt<unsigned> CallWithManyArgumentsThreshold(
+    "call-with-many-arguments-threshold", cl::Hidden, cl::init(4),
+    cl::desc("The minimum number of arguments a function call must have before "
+             "it is considered having many arguments."));
+
 namespace {
 int64_t getNrBlocksFromCond(const BasicBlock &BB) {
   int64_t Ret = 0;
@@ -103,6 +109,23 @@ void FunctionPropertiesInfo::updateForBB(const BasicBlock &BB,
     else
       SmallBasicBlocks += Direction;
 
+    // Calculate critical edges by looking through all successors of a basic
+    // block that has multiple successors and finding ones that have multiple
+    // predecessors, which represent critical edges.
+    if (SuccessorCount > 1) {
+      for (const auto *Successor : successors(&BB)) {
+        if (pred_size(Successor) > 1)
+          CriticalEdgeCount += Direction;
+      }
+    }
+
+    ControlFlowEdgeCount += Direction * SuccessorCount;
+
+    if (const auto *BI = dyn_cast<BranchInst>(BB.getTerminator())) {
+      if (!BI->isConditional())
+        UnconditionalBranchCount += Direction;
+    }
+
     for (const Instruction &I : BB.instructionsWithoutDebug()) {
       if (I.isCast())
         CastInstructionCount += Direction;
@@ -112,6 +135,41 @@ void FunctionPropertiesInfo::updateForBB(const BasicBlock &BB,
       else if (I.getType()->isIntegerTy())
         IntegerInstructionCount += Direction;
 
+      if (isa<IntrinsicInst>(I))
+        ++IntrinsicCount;
+
+      if (const auto *Call = dyn_cast<CallInst>(&I)) {
+        if (Call->isIndirectCall())
+          IndirectCallCount += Direction;
+        else
+          DirectCallCount += Direction;
+
+        if (Call->getType()->isIntegerTy())
+          CallReturnsIntegerCount += Direction;
+        else if (Call->getType()->isFloatingPointTy())
+          CallReturnsFloatCount += Direction;
+        else if (Call->getType()->isPointerTy())
+          CallReturnsPointerCount += Direction;
+        else if (Call->getType()->isVectorTy()) {
+          if (Call->getType()->getScalarType()->isIntegerTy())
+            CallReturnsVectorIntCount += Direction;
+          else if (Call->getType()->getScalarType()->isFloatingPointTy())
+            CallReturnsVectorFloatCount += Direction;
+          else if (Call->getType()->getScalarType()->isPointerTy())
+            CallReturnsVectorPointerCount += Direction;
+        }
+
+        if (Call->arg_size() > CallWithManyArgumentsThreshold)
+          CallWithManyArgumentsCount += Direction;
+
+        for (const auto &Arg : Call->args()) {
+          if (Arg->getType()->isPointerTy()) {
+            CallWithPointerArgumentCount += Direction;
+            break;
+          }
+        }
+      }
+
 #define COUNT_OPERAND(OPTYPE)                                                  \
   if (isa<OPTYPE>(Operand)) {                                                  \
     OPTYPE##OperandCount += Direction;                                         \
@@ -209,6 +267,20 @@ void FunctionPropertiesInfo::print(raw_ostream &OS) const {
     PRINT_PROPERTY(InlineAsmOperandCount)
     PRINT_PROPERTY(ArgumentOperandCount)
     PRINT_PROPERTY(UnknownOperandCount)
+    PRINT_PROPERTY(CriticalEdgeCount)
+    PRINT_PROPERTY(ControlFlowEdgeCount)
+    PRINT_PROPERTY(UnconditionalBranchCount)
+    PRINT_PROPERTY(IntrinsicCount)
+    PRINT_PROPERTY(DirectCallCount)
+    PRINT_PROPERTY(IndirectCallCount)
+    PRINT_PROPERTY(CallReturnsIntegerCount)
+    PRINT_PROPERTY(CallReturnsFloatCount)
+    PRINT_PROPERTY(CallReturnsPointerCount)
+    PRINT_PROPERTY(CallReturnsVectorIntCount)
+    PRINT_PROPERTY(CallReturnsVectorFloatCount)
+    PRINT_PROPERTY(CallReturnsVectorPointerCount)
+    PRINT_PROPERTY(CallWithManyArgumentsCount)
+    PRINT_PROPERTY(CallWithPointerArgumentCount)
   }
 
 #undef PRINT_PROPERTY

diff  --git a/llvm/test/Analysis/FunctionPropertiesAnalysis/matmul.ll b/llvm/test/Analysis/FunctionPropertiesAnalysis/matmul.ll
index 49b15e938080dc..500cbbc7622bfd 100644
--- a/llvm/test/Analysis/FunctionPropertiesAnalysis/matmul.ll
+++ b/llvm/test/Analysis/FunctionPropertiesAnalysis/matmul.ll
@@ -57,6 +57,19 @@ entry:
 ; DETAILED-PROPERTIES-DAG: InlineAsmOperandCount: 0
 ; DETAILED-PROPERTIES-DAG: ArgumentOperandCount: 0
 ; DETAILED-PROPERTIES-DAG: UnknownOperandCount: 0
+; DETAILED-PROPERTIES-DAG: CriticalEdgeCount: 0
+; DETAILED-PROPERTIES-DAG: ControlFlowEdgeCount: 0
+; DETAILED-PROPERTIES-DAG: UnconditionalBranchCount: 0
+; DETAILED-PROPERTIES-DAG: DirectCallCount: 1
+; DETAILED-PROPERTIES-DAG: IndirectCallCount: 0
+; DETAILED-PROPERTIES-DAG: CallReturnsIntegerCount: 0
+; DETAILED-PROPERTIES-DAG: CallReturnsFloatCount: 0
+; DETAILED-PROPERTIES-DAG: CallReturnsPointerCount: 0
+; DETAILED-PROPERTIES-DAG: CallReturnsVectorIntCount: 0
+; DETAILED-PROPERTIES-DAG: CallReturnsVectorFloatCount: 0
+; DETAILED-PROPERTIES-DAG: CallReturnsVectorPointerCount: 0
+; DETAILED-PROPERTIES-DAG: CallWithManyArgumentsCount: 0
+; DETAILED-PROPERTIES-DAG: CallWithPointerArgumentCount: 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':
@@ -201,4 +214,17 @@ for.end26:                                        ; preds = %for.cond
 ; DETAILED-PROPERTIES-DAG: InlineAsmOperandCount: 0
 ; DETAILED-PROPERTIES-DAG: ArgumentOperandCount: 3
 ; DETAILED-PROPERTIES-DAG: UnknownOperandCount: 0
+; DETAILED-PROPERTIES-DAG: DirectCallCount: 0
+; DETAILED-PROPERTIES-DAG: IndirectCallCount: 0
+; DETAILED-PROPERTIES-DAG: CriticalEdgeCount: 0
+; DETAILED-PROPERTIES-DAG: ControlFlowEdgeCount: 15
+; DETAILED-PROPERTIES-DAG: UnconditionalBranchCount: 9
+; DETAILED-PROPERTIES-DAG: CallReturnsIntegerCount: 0
+; DETAILED-PROPERTIES-DAG: CallReturnsFloatCount: 0
+; DETAILED-PROPERTIES-DAG: CallReturnsPointerCount: 0
+; DETAILED-PROPERTIES-DAG: CallReturnsVectorIntCount: 0
+; DETAILED-PROPERTIES-DAG: CallReturnsVectorFloatCount: 0
+; DETAILED-PROPERTIES-DAG: CallReturnsVectorPointerCount: 0
+; DETAILED-PROPERTIES-DAG: CallWithManyArgumentsCount: 0
+; DETAILED-PROPERTIES-DAG: CallWithPointerArgumentCount: 0
 

diff  --git a/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp b/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp
index 39c0d05911e2ea..f5f4a54ae08316 100644
--- a/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp
+++ b/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp
@@ -146,6 +146,17 @@ define internal i32 @top() {
   EXPECT_EQ(DetailedBranchesFeatures.InlineAsmOperandCount, 0);
   EXPECT_EQ(DetailedBranchesFeatures.ArgumentOperandCount, 3);
   EXPECT_EQ(DetailedBranchesFeatures.UnknownOperandCount, 0);
+  EXPECT_EQ(DetailedBranchesFeatures.CriticalEdgeCount, 0);
+  EXPECT_EQ(DetailedBranchesFeatures.ControlFlowEdgeCount, 4);
+  EXPECT_EQ(DetailedBranchesFeatures.UnconditionalBranchCount, 2);
+  EXPECT_EQ(DetailedBranchesFeatures.IntrinsicCount, 0);
+  EXPECT_EQ(DetailedBranchesFeatures.DirectCallCount, 2);
+  EXPECT_EQ(DetailedBranchesFeatures.IndirectCallCount, 0);
+  EXPECT_EQ(DetailedBranchesFeatures.CallReturnsIntegerCount, 2);
+  EXPECT_EQ(DetailedBranchesFeatures.CallReturnsFloatCount, 0);
+  EXPECT_EQ(DetailedBranchesFeatures.CallReturnsPointerCount, 0);
+  EXPECT_EQ(DetailedBranchesFeatures.CallWithManyArgumentsCount, 0);
+  EXPECT_EQ(DetailedBranchesFeatures.CallWithPointerArgumentCount, 0);
   EnableDetailedFunctionProperties.setValue(false);
 }
 
@@ -186,6 +197,17 @@ define i64 @f1() {
   EXPECT_EQ(DetailedF1Properties.InlineAsmOperandCount, 0);
   EXPECT_EQ(DetailedF1Properties.ArgumentOperandCount, 0);
   EXPECT_EQ(DetailedF1Properties.UnknownOperandCount, 0);
+  EXPECT_EQ(DetailedF1Properties.CriticalEdgeCount, 0);
+  EXPECT_EQ(DetailedF1Properties.ControlFlowEdgeCount, 2);
+  EXPECT_EQ(DetailedF1Properties.UnconditionalBranchCount, 0);
+  EXPECT_EQ(DetailedF1Properties.IntrinsicCount, 0);
+  EXPECT_EQ(DetailedF1Properties.DirectCallCount, 0);
+  EXPECT_EQ(DetailedF1Properties.IndirectCallCount, 0);
+  EXPECT_EQ(DetailedF1Properties.CallReturnsIntegerCount, 0);
+  EXPECT_EQ(DetailedF1Properties.CallReturnsFloatCount, 0);
+  EXPECT_EQ(DetailedF1Properties.CallReturnsPointerCount, 0);
+  EXPECT_EQ(DetailedF1Properties.CallWithManyArgumentsCount, 0);
+  EXPECT_EQ(DetailedF1Properties.CallWithPointerArgumentCount, 0);
   EnableDetailedFunctionProperties.setValue(false);
 }
 
@@ -850,6 +872,130 @@ define i64 @f1(i64 %e) {
   EXPECT_EQ(DetailedF1Properties.InlineAsmOperandCount, 1);
   EXPECT_EQ(DetailedF1Properties.ArgumentOperandCount, 1);
   EXPECT_EQ(DetailedF1Properties.UnknownOperandCount, 0);
+  EXPECT_EQ(DetailedF1Properties.CriticalEdgeCount, 0);
+  EXPECT_EQ(DetailedF1Properties.ControlFlowEdgeCount, 0);
+  EXPECT_EQ(DetailedF1Properties.UnconditionalBranchCount, 0);
+  EXPECT_EQ(DetailedF1Properties.IntrinsicCount, 0);
+  EXPECT_EQ(DetailedF1Properties.DirectCallCount, 1);
+  EXPECT_EQ(DetailedF1Properties.IndirectCallCount, 0);
+  EXPECT_EQ(DetailedF1Properties.CallReturnsIntegerCount, 1);
+  EXPECT_EQ(DetailedF1Properties.CallReturnsFloatCount, 0);
+  EXPECT_EQ(DetailedF1Properties.CallReturnsPointerCount, 0);
+  EXPECT_EQ(DetailedF1Properties.CallWithManyArgumentsCount, 0);
+  EXPECT_EQ(DetailedF1Properties.CallWithPointerArgumentCount, 0);
+  EnableDetailedFunctionProperties.setValue(false);
+}
+
+TEST_F(FunctionPropertiesAnalysisTest, IntrinsicCount) {
+  LLVMContext C;
+  std::unique_ptr<Module> M = makeLLVMModule(C,
+                                             R"IR(
+define float @f1(float %a) {
+  %b = call float @llvm.cos.f32(float %a)
+  ret float %b
+}
+declare float @llvm.cos.f32(float)
+)IR");
+
+  Function *F1 = M->getFunction("f1");
+  EnableDetailedFunctionProperties.setValue(true);
+  FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);
+  EXPECT_EQ(DetailedF1Properties.IntrinsicCount, 1);
+  EXPECT_EQ(DetailedF1Properties.DirectCallCount, 1);
+  EXPECT_EQ(DetailedF1Properties.IndirectCallCount, 0);
+  EXPECT_EQ(DetailedF1Properties.CallReturnsIntegerCount, 0);
+  EXPECT_EQ(DetailedF1Properties.CallReturnsFloatCount, 1);
+  EXPECT_EQ(DetailedF1Properties.CallReturnsPointerCount, 0);
+  EXPECT_EQ(DetailedF1Properties.CallWithManyArgumentsCount, 0);
+  EXPECT_EQ(DetailedF1Properties.CallWithPointerArgumentCount, 0);
+  EnableDetailedFunctionProperties.setValue(false);
+}
+
+TEST_F(FunctionPropertiesAnalysisTest, FunctionCallMetrics) {
+  LLVMContext C;
+  std::unique_ptr<Module> M = makeLLVMModule(C,
+                                             R"IR(
+define i64 @f1(i64 %a) {
+  %b = call i64 @f2(i64 %a, i64 %a, i64 %a, i64 %a, i64 %a)
+  %c = call ptr @f3()
+  call void @f4(ptr %c)
+  %d = call float @f5()
+  %e = call i64 %c(i64 %b)
+  ret i64 %b
+}
+
+declare i64 @f2(i64,i64,i64,i64,i64)
+declare ptr @f3()
+declare void @f4(ptr)
+declare float @f5()
+)IR");
+
+  Function *F1 = M->getFunction("f1");
+  EnableDetailedFunctionProperties.setValue(true);
+  FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);
+  EXPECT_EQ(DetailedF1Properties.IntrinsicCount, 0);
+  EXPECT_EQ(DetailedF1Properties.DirectCallCount, 4);
+  EXPECT_EQ(DetailedF1Properties.IndirectCallCount, 1);
+  EXPECT_EQ(DetailedF1Properties.CallReturnsIntegerCount, 2);
+  EXPECT_EQ(DetailedF1Properties.CallReturnsFloatCount, 1);
+  EXPECT_EQ(DetailedF1Properties.CallReturnsPointerCount, 1);
+  EXPECT_EQ(DetailedF1Properties.CallWithManyArgumentsCount, 1);
+  EXPECT_EQ(DetailedF1Properties.CallWithPointerArgumentCount, 1);
+  EnableDetailedFunctionProperties.setValue(false);
+}
+
+TEST_F(FunctionPropertiesAnalysisTest, CriticalEdge) {
+  LLVMContext C;
+  std::unique_ptr<Module> M = makeLLVMModule(C,
+                                             R"IR(
+define i64 @f1(i64 %a) {
+  %b = icmp eq i64 %a, 1
+  br i1 %b, label %TopBlock1, label %TopBlock2
+TopBlock1:
+  %c = add i64 %a, 1
+  %e = icmp eq i64 %c, 2
+  br i1 %e, label %BottomBlock1, label %BottomBlock2
+TopBlock2:
+  %d = add i64 %a, 2
+  br label %BottomBlock2
+BottomBlock1:
+  ret i64 0
+BottomBlock2:
+  %f = phi i64 [ %c, %TopBlock1 ], [ %d, %TopBlock2 ]
+  ret i64 %f
+}
+)IR");
+
+  Function *F1 = M->getFunction("f1");
+  EnableDetailedFunctionProperties.setValue(true);
+  FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);
+  EXPECT_EQ(DetailedF1Properties.CriticalEdgeCount, 1);
+  EnableDetailedFunctionProperties.setValue(false);
+}
+
+
+TEST_F(FunctionPropertiesAnalysisTest, FunctionReturnVectors) {
+  LLVMContext C;
+  std::unique_ptr<Module> M = makeLLVMModule(C,
+                                             R"IR(
+define <4 x i64> @f1(<4 x i64> %a) {
+  %b = call <4 x i64> @f2()
+  %c = call <4 x float> @f3()
+  %d = call <4 x ptr> @f4()
+  ret <4 x i64> %b
+}
+
+declare <4 x i64> @f2()
+declare <4 x float> @f3()
+declare <4 x ptr> @f4()
+)IR");
+
+  Function *F1 = M->getFunction("f1");
+  EnableDetailedFunctionProperties.setValue(true);
+  FunctionPropertiesInfo DetailedF1Properties = buildFPI(*F1);
+  EXPECT_EQ(DetailedF1Properties.CallReturnsVectorIntCount, 1);
+  EXPECT_EQ(DetailedF1Properties.CallReturnsVectorFloatCount, 1);
+  EXPECT_EQ(DetailedF1Properties.CallReturnsVectorPointerCount, 1);
   EnableDetailedFunctionProperties.setValue(false);
 }
 } // end anonymous namespace


        


More information about the llvm-commits mailing list