Skip to content

Commit

Permalink
[Analysis] Add OpCount Analysis (#7644)
Browse files Browse the repository at this point in the history
  • Loading branch information
TaoBi22 authored Oct 1, 2024
1 parent e66d680 commit 8f2a791
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 0 deletions.
50 changes: 50 additions & 0 deletions include/circt/Analysis/OpCountAnalysis.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//===- OpCountAnalysis.h - operation count analyses -----------------------===//
//
// 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 header file defines prototypes for methods that perform analysis
// involving the frequency of different kinds of operations found in a
// builtin.module.
//
//===----------------------------------------------------------------------===//

#ifndef CIRCT_ANALYSIS_OPCOUNT_ANALYSIS_H
#define CIRCT_ANALYSIS_OPCOUNT_ANALYSIS_H

#include "circt/Support/LLVM.h"
#include "mlir/IR/Operation.h"
#include "llvm/ADT/DenseMap.h"

namespace mlir {
class AnalysisManager;
} // namespace mlir
namespace circt {
namespace analysis {

class OpCountAnalysis {
public:
OpCountAnalysis(Operation *moduleOp, mlir::AnalysisManager &am);

/// Get the frequency of operations of a specific name
size_t getOpCount(OperationName opName);

/// Get the names of all distinct operations found by the analysis
SmallVector<OperationName> getFoundOpNames();

/// Get a map from number of operands to corresponding frequency for the given
/// operation
DenseMap<size_t, size_t> getOperandCountMap(OperationName opName);

private:
DenseMap<OperationName, size_t> opCounts;
DenseMap<OperationName, DenseMap<size_t, size_t>> operandCounts;
};

} // namespace analysis
} // namespace circt

#endif // CIRCT_ANALYSIS_OPCOUNT_ANALYSIS_H
9 changes: 9 additions & 0 deletions lib/Analysis/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ set(LLVM_OPTIONAL_SOURCES
DebugInfo.cpp
DependenceAnalysis.cpp
FIRRTLInstanceInfo.cpp
OpCountAnalysis.cpp
SchedulingAnalysis.cpp
TestPasses.cpp
)
Expand All @@ -27,6 +28,13 @@ add_circt_library(CIRCTDependenceAnalysis
MLIRTransformUtils
)

add_circt_library(CIRCTOpCountAnalysis
OpCountAnalysis.cpp

LINK_LIBS PUBLIC
MLIRIR
)

add_circt_library(CIRCTSchedulingAnalysis
SchedulingAnalysis.cpp

Expand All @@ -50,6 +58,7 @@ add_circt_library(CIRCTAnalysisTestPasses
LINK_LIBS PUBLIC
CIRCTDebugAnalysis
CIRCTDependenceAnalysis
CIRCTOpCountAnalysis
CIRCTFIRRTLAnalysis
CIRCTSchedulingAnalysis
CIRCTHW
Expand Down
47 changes: 47 additions & 0 deletions lib/Analysis/OpCountAnalysis.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//===- OpCountAnalysis.cpp - operation count analyses -----------*- 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 op count analysis. This is an analysis that
// provides information about the frequency of different kinds of operations
// found in a builtin.module.
//
//===----------------------------------------------------------------------===//

#include "circt/Analysis/OpCountAnalysis.h"
#include "mlir/IR/Operation.h"

using namespace circt;
using namespace analysis;

OpCountAnalysis::OpCountAnalysis(Operation *moduleOp,
mlir::AnalysisManager &am) {
moduleOp->walk([&](Operation *op) {
auto opName = op->getName();
// Update opCounts
opCounts[opName]++;

// Update operandCounts
operandCounts[opName][op->getNumOperands()]++;
});
}

SmallVector<OperationName> OpCountAnalysis::getFoundOpNames() {
SmallVector<OperationName> opNames;
for (auto pair : opCounts)
opNames.push_back(pair.first);
return opNames;
}

size_t OpCountAnalysis::getOpCount(OperationName opName) {
return opCounts[opName];
}

DenseMap<size_t, size_t>
OpCountAnalysis::getOperandCountMap(OperationName opName) {
return operandCounts[opName];
}
47 changes: 47 additions & 0 deletions lib/Analysis/TestPasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "circt/Analysis/DebugAnalysis.h"
#include "circt/Analysis/DependenceAnalysis.h"
#include "circt/Analysis/FIRRTLInstanceInfo.h"
#include "circt/Analysis/OpCountAnalysis.h"
#include "circt/Analysis/SchedulingAnalysis.h"
#include "circt/Dialect/FIRRTL/FIRRTLInstanceGraph.h"
#include "circt/Dialect/HW/HWInstanceGraph.h"
Expand Down Expand Up @@ -254,6 +255,49 @@ void FIRRTLInstanceInfoPass::runOnOperation() {
printModuleInfo(op, iInfo);
}

//===----------------------------------------------------------------------===//
// Op Count
//===----------------------------------------------------------------------===//

namespace {
struct TestOpCountAnalysisPass
: public PassWrapper<TestOpCountAnalysisPass, OperationPass<ModuleOp>> {
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestOpCountAnalysisPass)

void runOnOperation() override;
StringRef getArgument() const override { return "test-op-count-analysis"; }
StringRef getDescription() const override {
return "Run OpCountAnalysis and show the results. This pass "
"is intended to be used for testing purposes only.";
}
};
} // namespace

void printOpAndOperandCounts(OpCountAnalysis &opCount) {
auto opNames = opCount.getFoundOpNames();
// Sort to account for non-deterministic DenseMap ordering
llvm::sort(opNames, [](OperationName name1, OperationName name2) {
return name1.getStringRef() < name2.getStringRef();
});
for (auto opName : opNames) {
llvm::errs() << opName << ": " << opCount.getOpCount(opName) << "\n";
auto operandMap = opCount.getOperandCountMap(opName);
// Sort for determinism again
llvm::SmallVector<size_t> keys;
for (auto pair : operandMap)
keys.push_back(pair.first);
llvm::sort(keys);
for (auto num : keys)
llvm::errs() << " with " << num << " operands: " << operandMap[num]
<< "\n";
}
}

void TestOpCountAnalysisPass::runOnOperation() {
auto &opCount = getAnalysis<OpCountAnalysis>();
printOpAndOperandCounts(opCount);
}

//===----------------------------------------------------------------------===//
// Pass registration
//===----------------------------------------------------------------------===//
Expand All @@ -276,6 +320,9 @@ void registerAnalysisTestPasses() {
registerPass([]() -> std::unique_ptr<Pass> {
return std::make_unique<FIRRTLInstanceInfoPass>();
});
registerPass([]() -> std::unique_ptr<Pass> {
return std::make_unique<TestOpCountAnalysisPass>();
});
}
} // namespace test
} // namespace circt
36 changes: 36 additions & 0 deletions test/Analysis/op-count-analysis.mlir
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// RUN: circt-opt -test-op-count-analysis %s 2>&1 | FileCheck %s

// CHECK: builtin.module: 1
// CHECK: with 0 operands: 1
// CHECK: comb.add: 4
// CHECK: with 1 operands: 1
// CHECK: with 2 operands: 1
// CHECK: with 3 operands: 2
// CHECK: comb.icmp: 1
// CHECK: with 2 operands: 1
// CHECK: comb.xor: 1
// CHECK: with 1 operands: 1
// CHECK: hw.module: 1
// CHECK: with 0 operands: 1
// CHECK: hw.output: 1
// CHECK: with 0 operands: 1
// CHECK: scf.if: 1
// CHECK: with 1 operands: 1
// CHECK: scf.yield: 2
// CHECK: with 1 operands: 2

module {
hw.module @bar(in %in1: i8, in %in2: i8, in %in3: i8) {
%add2 = comb.add %in1, %in2 : i8
%add3 = comb.add %in1, %in2, %in3 : i8
%add3again = comb.add %in1, %in3, %in3 : i8
%gt = comb.icmp ult %in1, %in2 : i8
%x = scf.if %gt -> (i8) {
%add1 = comb.add %in1 : i8
scf.yield %add1 : i8
} else {
%xor = comb.xor %add2 : i8
scf.yield %xor : i8
}
}
}

0 comments on commit 8f2a791

Please sign in to comment.