From 4ab27b1cf59dd930c349f268aa08efa8bc5d155c Mon Sep 17 00:00:00 2001 From: Mohamed Atef Date: Fri, 19 Jul 2024 08:08:08 +0300 Subject: [PATCH 1/5] [Arc] Add Initial Cost Model --- include/circt/Dialect/Arc/ArcCostModel.h | 67 +++++++++++++ lib/Dialect/Arc/ArcCostModel.cpp | 120 +++++++++++++++++++++++ lib/Dialect/Arc/CMakeLists.txt | 3 + 3 files changed, 190 insertions(+) create mode 100644 include/circt/Dialect/Arc/ArcCostModel.h create mode 100644 lib/Dialect/Arc/ArcCostModel.cpp diff --git a/include/circt/Dialect/Arc/ArcCostModel.h b/include/circt/Dialect/Arc/ArcCostModel.h new file mode 100644 index 000000000000..7f11896f7e67 --- /dev/null +++ b/include/circt/Dialect/Arc/ArcCostModel.h @@ -0,0 +1,67 @@ +//===- ArcCostModel.h -----------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef CIRCT_DIALECT_ARC_ARCCOSTMODEL_H +#define CIRCT_DIALECT_ARC_ARCCOSTMODEL_H + +#include "circt/Dialect/Arc/ArcOps.h" +#include "mlir/IR/Operation.h" +#include "mlir/Pass/AnalysisManager.h" + +using namespace mlir; + +namespace circt { +namespace arc { + +// FIXME: May be refined and we have more accurate operation costs +enum class OperationCost : size_t { + NOCOST, + NORMALCOST, + PACKCOST = 2, + EXTRACTCOST = 3, + CONCATCOST = 3, + SAMEVECTORNOSHUFFLE = 0, + SAMEVECTORSHUFFLECOST = 2, + DIFFERENTVECTORNOSHUFFLE = 2, + DIFFERENTVECTORSHUFFLECOST = 3 +}; + +class ArcCostModel { +public: + size_t getCost(Operation *op); + size_t getPackingCost() const { return packingCost; } + // This is a public interface for other passes to call + size_t getShufflingCost() const { return shufflingCost; } + size_t getVectorizeOpsBodyCost()const { return vectoroizeOpsBodyCost; } + size_t getAllVectorizeOpsCost() const { return allVectorizeOpsCost; } + +private: + size_t computeOperationCost(Operation *op); + + // gets the cost to pack the vectors we have some cases we need to consider: + // 1: the input is scalar so we can give it a cost of 1 + // 2: the input is a result of another vector but with no shuffling so the + // is 0 + // 3: the input is a result of another vector but with some shuffling so + // the cost is the (number of out of order elements) * 2 + // 4: the input is a mix of some vectors: + // a) same order we multiply by 2 + // b) shuffling we multiply by 3 + size_t getInputVectorsCost(VectorizeOp vecOp); + size_t getShufflingCost(const ValueRange &inputVec, bool isSame = false); + DenseMap opCostCash; + size_t packingCost{0}; + size_t shufflingCost{0}; + size_t vectoroizeOpsBodyCost{0}; + size_t allVectorizeOpsCost{0}; +}; + +} // namespace arc +} // namespace circt + +#endif // CIRCT_DIALECT_ARC_ARCCOSTMODEL_H diff --git a/lib/Dialect/Arc/ArcCostModel.cpp b/lib/Dialect/Arc/ArcCostModel.cpp new file mode 100644 index 000000000000..27185044433b --- /dev/null +++ b/lib/Dialect/Arc/ArcCostModel.cpp @@ -0,0 +1,120 @@ +//===- ArcCostModel.cpp ---------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "circt/Dialect/Arc/ArcCostModel.h" +#include "circt/Dialect/Comb/CombOps.h" +#include "mlir/Dialect/Func/IR/FuncOps.h" +#include + +using namespace llvm; +using namespace circt; +using namespace arc; +using namespace std; + +size_t ArcCostModel::getCost(Operation *op) { return computeOperationCost(op); } + +size_t ArcCostModel::computeOperationCost(Operation *op) { + if (opCostCash.count(op)) + return opCostCash[op]; + if (isa(op)) + return opCostCash[op] = size_t(OperationCost::CONCATCOST); + if (isa(op)) + return opCostCash[op] = size_t(OperationCost::EXTRACTCOST); + // We have some other functions that need to be handled in a different way + // arc::StateOp, arc::CallOp, mlir::func::CallOp and arc::VectorizeOp, each of + // these functions have bodies so the cost of the op equals the cost of its + // body. + if (isa(op) || isa(op) || + isa(op)) { + size_t totalCost = 0; + const auto regions = + dyn_cast(op).resolveCallable()->getRegions(); + for (auto ®ion : regions) + for (auto &block : region) + for (auto &innerOp : block) + totalCost += computeOperationCost(&innerOp); + return opCostCash[op] = totalCost; + } + + if (isa(op)) { + size_t inputVecCost = getInputVectorsCost(dyn_cast(op)); + size_t vecOpBodyCost = 0; + auto regions = op->getRegions(); + for (auto ®ion : regions) + for (auto &block : region) + for (auto &innerOp : block) + vecOpBodyCost += computeOperationCost(&innerOp); + + vectoroizeOpsBodyCost += vecOpBodyCost; + allVectorizeOpsCost += inputVecCost + vecOpBodyCost; + return opCostCash[op] = inputVecCost + vecOpBodyCost; + } + + return opCostCash[op] = size_t(OperationCost::NORMALCOST); +} + +size_t ArcCostModel::getInputVectorsCost(VectorizeOp vecOp) { + // per VectorizeOp packing and shuffling costs + size_t localPackCost = 0; + size_t localShufflingCost = 0; + for (auto inputVec : vecOp.getInputs()) { + if (auto otherVecOp = inputVec[0].getDefiningOp(); + all_of(inputVec.begin(), inputVec.end(), [&](auto element) { + return element.template getDefiningOp() == otherVecOp; + })) { + // This means that they came from the same vector or + // VectorizeOp == null so they are all scalars + + // Check if they all scalars we multiply by the PACKCOST (SHL/R + OR) + if (!otherVecOp) + localPackCost += inputVec.size() * size_t(OperationCost::PACKCOST); + else + localShufflingCost += inputVec == otherVecOp.getResults() + ? size_t(OperationCost::SAMEVECTORNOSHUFFLE) + : getShufflingCost(inputVec, true); + } else + // inputVector consists of elements from different vectotrize ops and + // may have scalars as well. + localShufflingCost += getShufflingCost(inputVec); + } + packingCost += localPackCost; + shufflingCost += localShufflingCost; + return localShufflingCost + localPackCost; +} + +size_t ArcCostModel::getShufflingCost(const ValueRange &inputVec, bool isSame) { + size_t totalCost = 0; + if (isSame) { + auto vecOp = inputVec[0].getDefiningOp(); + for (auto [elem, orig] : llvm::zip(inputVec, vecOp.getResults())) + if (elem != orig) + ++totalCost; + + return totalCost * size_t(OperationCost::SAMEVECTORSHUFFLECOST); + } + + for (size_t i = 0; i < inputVec.size(); ++i) { + auto otherVecOp = inputVec[i].getDefiningOp(); + // If the element is not a result of a vector operation then it's a result + // of a scalar operation, then it just needs to be packed into the vector. + if (!otherVecOp) + totalCost += size_t(OperationCost::PACKCOST); + else { + // If it's a result of a vector operation, then we have two cases: + // (1) Its order in `inputVec` is the same as its order in the result of + // the defining op. + // (2) the order is different. + size_t idx = find(otherVecOp.getResults().begin(), + otherVecOp.getResults().end(), inputVec[i]) - + otherVecOp.getResults().begin(); + totalCost += i == idx ? size_t(OperationCost::DIFFERENTVECTORNOSHUFFLE) + : size_t(OperationCost::DIFFERENTVECTORSHUFFLECOST); + } + } + return totalCost; +} diff --git a/lib/Dialect/Arc/CMakeLists.txt b/lib/Dialect/Arc/CMakeLists.txt index 00a58eb30d41..e6ed7c9c4533 100644 --- a/lib/Dialect/Arc/CMakeLists.txt +++ b/lib/Dialect/Arc/CMakeLists.txt @@ -3,6 +3,7 @@ set(CIRCT_Arc_Sources ArcFolds.cpp ArcOps.cpp ArcTypes.cpp + ArcCostModel.cpp ModelInfo.cpp ) @@ -26,11 +27,13 @@ add_circt_dialect_library(CIRCTArc Support LINK_LIBS PUBLIC + CIRCTComb CIRCTHW CIRCTSeq MLIRIR MLIRInferTypeOpInterface MLIRSideEffectInterfaces + MLIRFuncDialect ) add_circt_library(CIRCTArcReductions From 08fead798d038507f79e18affc03f45ae4513d6e Mon Sep 17 00:00:00 2001 From: Mohamed Atef Date: Mon, 5 Aug 2024 20:58:28 +0300 Subject: [PATCH 2/5] [Arc] Add the DummyAnalysisTester pass --- include/circt/Dialect/Arc/ArcPasses.h | 1 + include/circt/Dialect/Arc/ArcPasses.td | 18 +++++ lib/Dialect/Arc/Transforms/CMakeLists.txt | 1 + .../Arc/Transforms/DummyAnalysisTester.cpp | 73 +++++++++++++++++++ 4 files changed, 93 insertions(+) create mode 100644 lib/Dialect/Arc/Transforms/DummyAnalysisTester.cpp diff --git a/include/circt/Dialect/Arc/ArcPasses.h b/include/circt/Dialect/Arc/ArcPasses.h index d8cbb6f0c19a..4d47bcef793e 100644 --- a/include/circt/Dialect/Arc/ArcPasses.h +++ b/include/circt/Dialect/Arc/ArcPasses.h @@ -30,6 +30,7 @@ createAddTapsPass(const AddTapsOptions &options = {}); std::unique_ptr createAllocateStatePass(); std::unique_ptr createArcCanonicalizerPass(); std::unique_ptr createDedupPass(); +std::unique_ptr createDummyAnalysisTesterPass(); std::unique_ptr createFindInitialVectorsPass(); std::unique_ptr createGroupResetsAndEnablesPass(); std::unique_ptr diff --git a/include/circt/Dialect/Arc/ArcPasses.td b/include/circt/Dialect/Arc/ArcPasses.td index 3a44ce80b354..a84519888e00 100644 --- a/include/circt/Dialect/Arc/ArcPasses.td +++ b/include/circt/Dialect/Arc/ArcPasses.td @@ -58,6 +58,24 @@ def Dedup : Pass<"arc-dedup", "mlir::ModuleOp"> { ]; } +def DummyAnalysisTester : Pass<"arc-dummy-analysis-tester", "mlir::ModuleOp"> { + let summary = "A dymmy pass to test analysis passes"; + let constructor = "circt::arc::createDummyAnalysisTesterPass()"; + let dependentDialects = ["arc::ArcDialect"]; + let statistics = [ + Statistic<"moduleCost", "Operation(s)", + "Number of operations in the module">, + Statistic<"packingCost", "Pack operations(s)", + "Number of scalar to vector packking in the module">, + Statistic<"shufflingCost", "Shuffle operation(s)", + "Number of shuffles done to set up the VectorizeOps">, + Statistic<"vectoroizeOpsBodyCost", "VectorizeOps Body Cost", + "Number of operations inside the body of the VectorizeOps">, + Statistic<"allVectorizeOpsCost", "All VectorizeOps Cost", + "Total Cost of all VectorizeOps in the module"> + ]; +} + def FindInitialVectors : Pass<"arc-find-initial-vectors", "mlir::ModuleOp"> { let summary = "Find initial groups of vectorizable ops"; let constructor = "circt::arc::createFindInitialVectorsPass()"; diff --git a/lib/Dialect/Arc/Transforms/CMakeLists.txt b/lib/Dialect/Arc/Transforms/CMakeLists.txt index fc8296c9dc64..ec63f08be71e 100644 --- a/lib/Dialect/Arc/Transforms/CMakeLists.txt +++ b/lib/Dialect/Arc/Transforms/CMakeLists.txt @@ -3,6 +3,7 @@ add_circt_dialect_library(CIRCTArcTransforms AllocateState.cpp ArcCanonicalizer.cpp Dedup.cpp + DummyAnalysisTester.cpp FindInitialVectors.cpp GroupResetsAndEnables.cpp InferMemories.cpp diff --git a/lib/Dialect/Arc/Transforms/DummyAnalysisTester.cpp b/lib/Dialect/Arc/Transforms/DummyAnalysisTester.cpp new file mode 100644 index 000000000000..4b11af425087 --- /dev/null +++ b/lib/Dialect/Arc/Transforms/DummyAnalysisTester.cpp @@ -0,0 +1,73 @@ +//===- DummyAnalysisTester.cpp --------------------------------------------===// +// +// 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 is a dummy pass to test the analysis passes it doesn't do any thing. It +// just walks over the ops to compute some statistics, you can add any +// statistics you need to compute. +// +//===----------------------------------------------------------------------===// + +#include "circt/Dialect/Arc/ArcCostModel.h" +#include "circt/Dialect/Arc/ArcPasses.h" +#include "circt/Dialect/HW/HWOps.h" +#include "mlir/IR/MLIRContext.h" +#include "mlir/Pass/Pass.h" + +#define DEBUG_TYPE "arc-dummy-analysis-tester" + +namespace circt { +namespace arc { +#define GEN_PASS_DEF_DUMMYANALYSISTESTER +#include "circt/Dialect/Arc/ArcPasses.h.inc" +} // namespace arc +} // namespace circt + +using namespace circt; +using namespace arc; + +namespace { +struct DummyAnalysisTesterPass + : public arc::impl::DummyAnalysisTesterBase { + void runOnOperation() override; + + // You can add any statistics you need to compute here. + struct StatisticVars { + size_t moduleCost{0}; + size_t packingCost{0}; + size_t shufflingCost{0}; + size_t vectoroizeOpsBodyCost{0}; + size_t allVectorizeOpsCost{0}; + }; + + StatisticVars statVars; +}; +} // namespace + + +void DummyAnalysisTesterPass::runOnOperation() { + for (auto moduleOp : getOperation().getOps()) { + ArcCostModel arcCostModel; + moduleOp.walk([&](Operation *op) { + statVars.moduleCost += arcCostModel.getCost(op); + }); + statVars.packingCost += arcCostModel.getPackingCost(); + statVars.shufflingCost += arcCostModel.getShufflingCost(); + statVars.vectoroizeOpsBodyCost += arcCostModel.getVectorizeOpsBodyCost(); + statVars.allVectorizeOpsCost += arcCostModel.getAllVectorizeOpsCost(); + } + + moduleCost = statVars.moduleCost; + packingCost = statVars.packingCost; + shufflingCost = statVars.shufflingCost; + vectoroizeOpsBodyCost = statVars.vectoroizeOpsBodyCost; + allVectorizeOpsCost = statVars.allVectorizeOpsCost; +} + +std::unique_ptr arc::createDummyAnalysisTesterPass() { + return std::make_unique(); +} From 91850f29bad1253cd7bbf08836bfe5c6e7d70939 Mon Sep 17 00:00:00 2001 From: Mohamed Atef Date: Mon, 5 Aug 2024 21:53:37 +0300 Subject: [PATCH 3/5] [Arc] Fix clang-format failure --- include/circt/Dialect/Arc/ArcCostModel.h | 2 +- lib/Dialect/Arc/Transforms/DummyAnalysisTester.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/circt/Dialect/Arc/ArcCostModel.h b/include/circt/Dialect/Arc/ArcCostModel.h index 7f11896f7e67..dda64f30f841 100644 --- a/include/circt/Dialect/Arc/ArcCostModel.h +++ b/include/circt/Dialect/Arc/ArcCostModel.h @@ -37,7 +37,7 @@ class ArcCostModel { size_t getPackingCost() const { return packingCost; } // This is a public interface for other passes to call size_t getShufflingCost() const { return shufflingCost; } - size_t getVectorizeOpsBodyCost()const { return vectoroizeOpsBodyCost; } + size_t getVectorizeOpsBodyCost() const { return vectoroizeOpsBodyCost; } size_t getAllVectorizeOpsCost() const { return allVectorizeOpsCost; } private: diff --git a/lib/Dialect/Arc/Transforms/DummyAnalysisTester.cpp b/lib/Dialect/Arc/Transforms/DummyAnalysisTester.cpp index 4b11af425087..92078ef9ff3c 100644 --- a/lib/Dialect/Arc/Transforms/DummyAnalysisTester.cpp +++ b/lib/Dialect/Arc/Transforms/DummyAnalysisTester.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// // // This is a dummy pass to test the analysis passes it doesn't do any thing. It -// just walks over the ops to compute some statistics, you can add any +// just walks over the ops to compute some statistics, you can add any // statistics you need to compute. // //===----------------------------------------------------------------------===// @@ -48,7 +48,6 @@ struct DummyAnalysisTesterPass }; } // namespace - void DummyAnalysisTesterPass::runOnOperation() { for (auto moduleOp : getOperation().getOps()) { ArcCostModel arcCostModel; From 6f3ce4f042ea04fbd0ee81e2414768e319600c98 Mon Sep 17 00:00:00 2001 From: Mohamed Atef Date: Mon, 12 Aug 2024 23:35:56 +0300 Subject: [PATCH 4/5] [Arc] Address @fabianschuiki comments --- include/circt/Dialect/Arc/ArcCostModel.h | 43 ++++---- include/circt/Dialect/Arc/ArcPasses.h | 2 +- include/circt/Dialect/Arc/ArcPasses.td | 4 +- lib/Dialect/Arc/ArcCostModel.cpp | 104 ++++++++++-------- lib/Dialect/Arc/Transforms/CMakeLists.txt | 2 +- lib/Dialect/Arc/Transforms/PrintCostModel.cpp | 56 ++++++++++ 6 files changed, 137 insertions(+), 74 deletions(-) create mode 100644 lib/Dialect/Arc/Transforms/PrintCostModel.cpp diff --git a/include/circt/Dialect/Arc/ArcCostModel.h b/include/circt/Dialect/Arc/ArcCostModel.h index dda64f30f841..769a3ceb5e2b 100644 --- a/include/circt/Dialect/Arc/ArcCostModel.h +++ b/include/circt/Dialect/Arc/ArcCostModel.h @@ -18,30 +18,29 @@ using namespace mlir; namespace circt { namespace arc { -// FIXME: May be refined and we have more accurate operation costs -enum class OperationCost : size_t { - NOCOST, - NORMALCOST, - PACKCOST = 2, - EXTRACTCOST = 3, - CONCATCOST = 3, - SAMEVECTORNOSHUFFLE = 0, - SAMEVECTORSHUFFLECOST = 2, - DIFFERENTVECTORNOSHUFFLE = 2, - DIFFERENTVECTORSHUFFLECOST = 3 +struct OperationCosts { + size_t normalCost{0}; + size_t packingCost{0}; + size_t shufflingCost{0}; + size_t vectorizeOpsBodyCost{0}; + size_t totalCost() const { + return normalCost + packingCost + shufflingCost + vectorizeOpsBodyCost; + } + OperationCosts &operator+=(const OperationCosts &other) { + this->normalCost += other.normalCost; + this->packingCost += other.packingCost; + this->shufflingCost += other.shufflingCost; + this->vectorizeOpsBodyCost += other.vectorizeOpsBodyCost; + return *this; + } }; class ArcCostModel { public: - size_t getCost(Operation *op); - size_t getPackingCost() const { return packingCost; } - // This is a public interface for other passes to call - size_t getShufflingCost() const { return shufflingCost; } - size_t getVectorizeOpsBodyCost() const { return vectoroizeOpsBodyCost; } - size_t getAllVectorizeOpsCost() const { return allVectorizeOpsCost; } + OperationCosts getCost(Operation *op); private: - size_t computeOperationCost(Operation *op); + OperationCosts computeOperationCost(Operation *op); // gets the cost to pack the vectors we have some cases we need to consider: // 1: the input is scalar so we can give it a cost of 1 @@ -52,13 +51,9 @@ class ArcCostModel { // 4: the input is a mix of some vectors: // a) same order we multiply by 2 // b) shuffling we multiply by 3 - size_t getInputVectorsCost(VectorizeOp vecOp); + OperationCosts getInputVectorsCost(VectorizeOp vecOp); size_t getShufflingCost(const ValueRange &inputVec, bool isSame = false); - DenseMap opCostCash; - size_t packingCost{0}; - size_t shufflingCost{0}; - size_t vectoroizeOpsBodyCost{0}; - size_t allVectorizeOpsCost{0}; + DenseMap opCostCache; }; } // namespace arc diff --git a/include/circt/Dialect/Arc/ArcPasses.h b/include/circt/Dialect/Arc/ArcPasses.h index 4d47bcef793e..bd185fa147ef 100644 --- a/include/circt/Dialect/Arc/ArcPasses.h +++ b/include/circt/Dialect/Arc/ArcPasses.h @@ -30,7 +30,6 @@ createAddTapsPass(const AddTapsOptions &options = {}); std::unique_ptr createAllocateStatePass(); std::unique_ptr createArcCanonicalizerPass(); std::unique_ptr createDedupPass(); -std::unique_ptr createDummyAnalysisTesterPass(); std::unique_ptr createFindInitialVectorsPass(); std::unique_ptr createGroupResetsAndEnablesPass(); std::unique_ptr @@ -47,6 +46,7 @@ std::unique_ptr createLowerVectorizationsPass( LowerVectorizationsModeEnum mode = LowerVectorizationsModeEnum::Full); std::unique_ptr createMakeTablesPass(); std::unique_ptr createMuxToControlFlowPass(); +std::unique_ptr createPrintCostModelPass(); std::unique_ptr createSimplifyVariadicOpsPass(); std::unique_ptr createSplitLoopsPass(); std::unique_ptr createStripSVPass(); diff --git a/include/circt/Dialect/Arc/ArcPasses.td b/include/circt/Dialect/Arc/ArcPasses.td index a84519888e00..6a89f69c7b02 100644 --- a/include/circt/Dialect/Arc/ArcPasses.td +++ b/include/circt/Dialect/Arc/ArcPasses.td @@ -58,9 +58,9 @@ def Dedup : Pass<"arc-dedup", "mlir::ModuleOp"> { ]; } -def DummyAnalysisTester : Pass<"arc-dummy-analysis-tester", "mlir::ModuleOp"> { +def PrintCostModel : Pass<"arc-print-cost-model", "mlir::ModuleOp"> { let summary = "A dymmy pass to test analysis passes"; - let constructor = "circt::arc::createDummyAnalysisTesterPass()"; + let constructor = "circt::arc::createPrintCostModelPass()"; let dependentDialects = ["arc::ArcDialect"]; let statistics = [ Statistic<"moduleCost", "Operation(s)", diff --git a/lib/Dialect/Arc/ArcCostModel.cpp b/lib/Dialect/Arc/ArcCostModel.cpp index 27185044433b..32393506df17 100644 --- a/lib/Dialect/Arc/ArcCostModel.cpp +++ b/lib/Dialect/Arc/ArcCostModel.cpp @@ -16,52 +16,65 @@ using namespace circt; using namespace arc; using namespace std; -size_t ArcCostModel::getCost(Operation *op) { return computeOperationCost(op); } +// FIXME: May be refined and we have more accurate operation costs +enum class OperationCost : size_t { + NOCOST, + NORMALCOST, + PACKCOST = 2, + EXTRACTCOST = 3, + CONCATCOST = 3, + SAMEVECTORNOSHUFFLE = 0, + SAMEVECTORSHUFFLECOST = 2, + DIFFERENTVECTORNOSHUFFLE = 2, + DIFFERENTVECTORSHUFFLECOST = 3 +}; + +OperationCosts ArcCostModel::getCost(Operation *op) { + return computeOperationCost(op); +} + +OperationCosts ArcCostModel::computeOperationCost(Operation *op) { + if (auto it = opCostCache.find(op); it != opCostCache.end()) + return it->second; + + OperationCosts costs; -size_t ArcCostModel::computeOperationCost(Operation *op) { - if (opCostCash.count(op)) - return opCostCash[op]; if (isa(op)) - return opCostCash[op] = size_t(OperationCost::CONCATCOST); - if (isa(op)) - return opCostCash[op] = size_t(OperationCost::EXTRACTCOST); - // We have some other functions that need to be handled in a different way - // arc::StateOp, arc::CallOp, mlir::func::CallOp and arc::VectorizeOp, each of - // these functions have bodies so the cost of the op equals the cost of its - // body. - if (isa(op) || isa(op) || - isa(op)) { - size_t totalCost = 0; - const auto regions = - dyn_cast(op).resolveCallable()->getRegions(); - for (auto ®ion : regions) - for (auto &block : region) - for (auto &innerOp : block) - totalCost += computeOperationCost(&innerOp); - return opCostCash[op] = totalCost; - } + costs.normalCost = size_t(OperationCost::CONCATCOST); + else if (isa(op)) + costs.normalCost = size_t(OperationCost::EXTRACTCOST); + else if (auto vecOp = dyn_cast(op)) { + // VectorizeOpCost = packingCost + shufflingCost + bodyCost + OperationCosts inputVecCosts = getInputVectorsCost(vecOp); + costs.packingCost += inputVecCosts.packingCost; + costs.shufflingCost += inputVecCosts.shufflingCost; - if (isa(op)) { - size_t inputVecCost = getInputVectorsCost(dyn_cast(op)); - size_t vecOpBodyCost = 0; - auto regions = op->getRegions(); - for (auto ®ion : regions) + for (auto ®ion : op->getRegions()) { + for (auto &block : region) { + for (auto &innerOp : block) { + OperationCosts innerCosts = computeOperationCost(&innerOp); + costs.vectorizeOpsBodyCost += innerCosts.totalCost(); + } + } + } + } else if (auto callableOp = dyn_cast(op)) { + // Callable Op? then resolve! + if (auto *calledOp = callableOp.resolveCallable()) + return opCostCache[callableOp] = computeOperationCost(calledOp); + } else if (isa(op)) { + // Get the body cost + for (auto ®ion : op->getRegions()) for (auto &block : region) for (auto &innerOp : block) - vecOpBodyCost += computeOperationCost(&innerOp); + costs += computeOperationCost(&innerOp); + } else + costs.normalCost = size_t(OperationCost::NORMALCOST); - vectoroizeOpsBodyCost += vecOpBodyCost; - allVectorizeOpsCost += inputVecCost + vecOpBodyCost; - return opCostCash[op] = inputVecCost + vecOpBodyCost; - } - - return opCostCash[op] = size_t(OperationCost::NORMALCOST); + return opCostCache[op] = costs; } -size_t ArcCostModel::getInputVectorsCost(VectorizeOp vecOp) { - // per VectorizeOp packing and shuffling costs - size_t localPackCost = 0; - size_t localShufflingCost = 0; +OperationCosts ArcCostModel::getInputVectorsCost(VectorizeOp vecOp) { + OperationCosts costs; for (auto inputVec : vecOp.getInputs()) { if (auto otherVecOp = inputVec[0].getDefiningOp(); all_of(inputVec.begin(), inputVec.end(), [&](auto element) { @@ -72,19 +85,18 @@ size_t ArcCostModel::getInputVectorsCost(VectorizeOp vecOp) { // Check if they all scalars we multiply by the PACKCOST (SHL/R + OR) if (!otherVecOp) - localPackCost += inputVec.size() * size_t(OperationCost::PACKCOST); + costs.packingCost += inputVec.size() * size_t(OperationCost::PACKCOST); else - localShufflingCost += inputVec == otherVecOp.getResults() - ? size_t(OperationCost::SAMEVECTORNOSHUFFLE) - : getShufflingCost(inputVec, true); + costs.shufflingCost += inputVec == otherVecOp.getResults() + ? size_t(OperationCost::SAMEVECTORNOSHUFFLE) + : getShufflingCost(inputVec, true); } else // inputVector consists of elements from different vectotrize ops and // may have scalars as well. - localShufflingCost += getShufflingCost(inputVec); + costs.shufflingCost += getShufflingCost(inputVec); } - packingCost += localPackCost; - shufflingCost += localShufflingCost; - return localShufflingCost + localPackCost; + + return costs; } size_t ArcCostModel::getShufflingCost(const ValueRange &inputVec, bool isSame) { diff --git a/lib/Dialect/Arc/Transforms/CMakeLists.txt b/lib/Dialect/Arc/Transforms/CMakeLists.txt index ec63f08be71e..fa01509d8502 100644 --- a/lib/Dialect/Arc/Transforms/CMakeLists.txt +++ b/lib/Dialect/Arc/Transforms/CMakeLists.txt @@ -3,7 +3,6 @@ add_circt_dialect_library(CIRCTArcTransforms AllocateState.cpp ArcCanonicalizer.cpp Dedup.cpp - DummyAnalysisTester.cpp FindInitialVectors.cpp GroupResetsAndEnables.cpp InferMemories.cpp @@ -19,6 +18,7 @@ add_circt_dialect_library(CIRCTArcTransforms LowerVectorizations.cpp MakeTables.cpp MuxToControlFlow.cpp + PrintCostModel.cpp SimplifyVariadicOps.cpp SplitFuncs.cpp SplitLoops.cpp diff --git a/lib/Dialect/Arc/Transforms/PrintCostModel.cpp b/lib/Dialect/Arc/Transforms/PrintCostModel.cpp new file mode 100644 index 000000000000..2f8a03be392e --- /dev/null +++ b/lib/Dialect/Arc/Transforms/PrintCostModel.cpp @@ -0,0 +1,56 @@ +//===- DummyAnalysisTester.cpp --------------------------------------------===// +// +// 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 is a dummy pass to test the cost model results it doesn't do any thing. +// just walks over the ops to compute some statistics. +// +//===----------------------------------------------------------------------===// + +#include "circt/Dialect/Arc/ArcCostModel.h" +#include "circt/Dialect/Arc/ArcPasses.h" +#include "circt/Dialect/HW/HWOps.h" +#include "mlir/IR/MLIRContext.h" +#include "mlir/Pass/Pass.h" + +#define DEBUG_TYPE "arc-print-cost-model" + +namespace circt { +namespace arc { +#define GEN_PASS_DEF_PRINTCOSTMODEL +#include "circt/Dialect/Arc/ArcPasses.h.inc" +} // namespace arc +} // namespace circt + +using namespace circt; +using namespace arc; + +namespace { +struct PrintCostModelPass + : public arc::impl::PrintCostModelBase { + void runOnOperation() override; +}; +} // namespace + +void PrintCostModelPass::runOnOperation() { + OperationCosts statVars; + ArcCostModel arcCostModel; + for (auto moduleOp : getOperation().getOps()) { + moduleOp.walk([&](Operation *op) { statVars += arcCostModel.getCost(op); }); + } + + moduleCost = statVars.totalCost(); + packingCost = statVars.packingCost; + shufflingCost = statVars.shufflingCost; + vectoroizeOpsBodyCost = statVars.vectorizeOpsBodyCost; + allVectorizeOpsCost = statVars.packingCost + statVars.shufflingCost + + statVars.vectorizeOpsBodyCost; +} + +std::unique_ptr arc::createPrintCostModelPass() { + return std::make_unique(); +} From c14941c9144a346cea8aec693e22fb033a64d29b Mon Sep 17 00:00:00 2001 From: Mohamed Atef Date: Tue, 13 Aug 2024 00:40:17 +0300 Subject: [PATCH 5/5] [Arc] Remove DummyAnalysisTester.cpp --- .../Arc/Transforms/DummyAnalysisTester.cpp | 72 ------------------- 1 file changed, 72 deletions(-) delete mode 100644 lib/Dialect/Arc/Transforms/DummyAnalysisTester.cpp diff --git a/lib/Dialect/Arc/Transforms/DummyAnalysisTester.cpp b/lib/Dialect/Arc/Transforms/DummyAnalysisTester.cpp deleted file mode 100644 index 92078ef9ff3c..000000000000 --- a/lib/Dialect/Arc/Transforms/DummyAnalysisTester.cpp +++ /dev/null @@ -1,72 +0,0 @@ -//===- DummyAnalysisTester.cpp --------------------------------------------===// -// -// 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 is a dummy pass to test the analysis passes it doesn't do any thing. It -// just walks over the ops to compute some statistics, you can add any -// statistics you need to compute. -// -//===----------------------------------------------------------------------===// - -#include "circt/Dialect/Arc/ArcCostModel.h" -#include "circt/Dialect/Arc/ArcPasses.h" -#include "circt/Dialect/HW/HWOps.h" -#include "mlir/IR/MLIRContext.h" -#include "mlir/Pass/Pass.h" - -#define DEBUG_TYPE "arc-dummy-analysis-tester" - -namespace circt { -namespace arc { -#define GEN_PASS_DEF_DUMMYANALYSISTESTER -#include "circt/Dialect/Arc/ArcPasses.h.inc" -} // namespace arc -} // namespace circt - -using namespace circt; -using namespace arc; - -namespace { -struct DummyAnalysisTesterPass - : public arc::impl::DummyAnalysisTesterBase { - void runOnOperation() override; - - // You can add any statistics you need to compute here. - struct StatisticVars { - size_t moduleCost{0}; - size_t packingCost{0}; - size_t shufflingCost{0}; - size_t vectoroizeOpsBodyCost{0}; - size_t allVectorizeOpsCost{0}; - }; - - StatisticVars statVars; -}; -} // namespace - -void DummyAnalysisTesterPass::runOnOperation() { - for (auto moduleOp : getOperation().getOps()) { - ArcCostModel arcCostModel; - moduleOp.walk([&](Operation *op) { - statVars.moduleCost += arcCostModel.getCost(op); - }); - statVars.packingCost += arcCostModel.getPackingCost(); - statVars.shufflingCost += arcCostModel.getShufflingCost(); - statVars.vectoroizeOpsBodyCost += arcCostModel.getVectorizeOpsBodyCost(); - statVars.allVectorizeOpsCost += arcCostModel.getAllVectorizeOpsCost(); - } - - moduleCost = statVars.moduleCost; - packingCost = statVars.packingCost; - shufflingCost = statVars.shufflingCost; - vectoroizeOpsBodyCost = statVars.vectoroizeOpsBodyCost; - allVectorizeOpsCost = statVars.allVectorizeOpsCost; -} - -std::unique_ptr arc::createDummyAnalysisTesterPass() { - return std::make_unique(); -}