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 @@ -117,6 +117,24 @@ 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 --- 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 @@ -38,6 +39,11 @@ cl::desc("The minimum number of instructions a basic block should contain " "before being considered medium-sized.")); +cl::opt 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 @@ 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(BB.getTerminator())) { + if (!BI->isConditional()) + UnconditionalBranchCount += Direction; + } + for (const Instruction &I : BB.instructionsWithoutDebug()) { if (I.isCast()) CastInstructionCount += Direction; @@ -112,6 +135,41 @@ else if (I.getType()->isIntegerTy()) IntegerInstructionCount += Direction; + if (isa(I)) + ++IntrinsicCount; + + if (const auto *Call = dyn_cast(&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(Operand)) { \ OPTYPE##OperandCount += Direction; \ @@ -209,6 +267,20 @@ 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 --- a/llvm/test/Analysis/FunctionPropertiesAnalysis/matmul.ll +++ b/llvm/test/Analysis/FunctionPropertiesAnalysis/matmul.ll @@ -57,6 +57,19 @@ ; 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 @@ ; 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 --- a/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp +++ b/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp @@ -146,6 +146,17 @@ 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 @@ 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 @@ 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 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 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 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 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