CIRCT  20.0.0git
ArcCostModel.cpp
Go to the documentation of this file.
1 //===- ArcCostModel.cpp ---------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
11 #include "mlir/Dialect/Func/IR/FuncOps.h"
12 #include <algorithm>
13 
14 using namespace llvm;
15 using namespace circt;
16 using namespace arc;
17 using namespace std;
18 
19 // FIXME: May be refined and we have more accurate operation costs
20 enum class OperationCost : size_t {
21  NOCOST,
22  NORMALCOST,
23  PACKCOST = 2,
24  EXTRACTCOST = 3,
25  CONCATCOST = 3,
30 };
31 
32 OperationCosts ArcCostModel::getCost(Operation *op) {
33  return computeOperationCost(op);
34 }
35 
36 OperationCosts ArcCostModel::computeOperationCost(Operation *op) {
37  if (auto it = opCostCache.find(op); it != opCostCache.end())
38  return it->second;
39 
40  OperationCosts costs;
41 
42  if (isa<circt::comb::ConcatOp>(op))
43  costs.normalCost = size_t(OperationCost::CONCATCOST);
44  else if (isa<circt::comb::ExtractOp>(op))
45  costs.normalCost = size_t(OperationCost::EXTRACTCOST);
46  else if (auto vecOp = dyn_cast<arc::VectorizeOp>(op)) {
47  // VectorizeOpCost = packingCost + shufflingCost + bodyCost
48  OperationCosts inputVecCosts = getInputVectorsCost(vecOp);
49  costs.packingCost += inputVecCosts.packingCost;
50  costs.shufflingCost += inputVecCosts.shufflingCost;
51 
52  for (auto &region : op->getRegions()) {
53  for (auto &block : region) {
54  for (auto &innerOp : block) {
55  OperationCosts innerCosts = computeOperationCost(&innerOp);
56  costs.vectorizeOpsBodyCost += innerCosts.totalCost();
57  }
58  }
59  }
60  } else if (auto callableOp = dyn_cast<CallOpInterface>(op)) {
61  // Callable Op? then resolve!
62  if (auto *calledOp = callableOp.resolveCallable())
63  return opCostCache[callableOp] = computeOperationCost(calledOp);
64  } else if (isa<func::FuncOp, arc::DefineOp, mlir::ModuleOp>(op)) {
65  // Get the body cost
66  for (auto &region : op->getRegions())
67  for (auto &block : region)
68  for (auto &innerOp : block)
69  costs += computeOperationCost(&innerOp);
70  } else
71  costs.normalCost = size_t(OperationCost::NORMALCOST);
72 
73  return opCostCache[op] = costs;
74 }
75 
76 OperationCosts ArcCostModel::getInputVectorsCost(VectorizeOp vecOp) {
77  OperationCosts costs;
78  for (auto inputVec : vecOp.getInputs()) {
79  if (auto otherVecOp = inputVec[0].getDefiningOp<VectorizeOp>();
80  all_of(inputVec.begin(), inputVec.end(), [&](auto element) {
81  return element.template getDefiningOp<VectorizeOp>() == otherVecOp;
82  })) {
83  // This means that they came from the same vector or
84  // VectorizeOp == null so they are all scalars
85 
86  // Check if they all scalars we multiply by the PACKCOST (SHL/R + OR)
87  if (!otherVecOp)
88  costs.packingCost += inputVec.size() * size_t(OperationCost::PACKCOST);
89  else
90  costs.shufflingCost += inputVec == otherVecOp.getResults()
92  : getShufflingCost(inputVec, true);
93  } else
94  // inputVector consists of elements from different vectotrize ops and
95  // may have scalars as well.
96  costs.shufflingCost += getShufflingCost(inputVec);
97  }
98 
99  return costs;
100 }
101 
102 size_t ArcCostModel::getShufflingCost(const ValueRange &inputVec, bool isSame) {
103  size_t totalCost = 0;
104  if (isSame) {
105  auto vecOp = inputVec[0].getDefiningOp<VectorizeOp>();
106  for (auto [elem, orig] : llvm::zip(inputVec, vecOp.getResults()))
107  if (elem != orig)
108  ++totalCost;
109 
110  return totalCost * size_t(OperationCost::SAMEVECTORSHUFFLECOST);
111  }
112 
113  for (size_t i = 0; i < inputVec.size(); ++i) {
114  auto otherVecOp = inputVec[i].getDefiningOp<VectorizeOp>();
115  // If the element is not a result of a vector operation then it's a result
116  // of a scalar operation, then it just needs to be packed into the vector.
117  if (!otherVecOp)
118  totalCost += size_t(OperationCost::PACKCOST);
119  else {
120  // If it's a result of a vector operation, then we have two cases:
121  // (1) Its order in `inputVec` is the same as its order in the result of
122  // the defining op.
123  // (2) the order is different.
124  size_t idx = find(otherVecOp.getResults().begin(),
125  otherVecOp.getResults().end(), inputVec[i]) -
126  otherVecOp.getResults().begin();
127  totalCost += i == idx ? size_t(OperationCost::DIFFERENTVECTORNOSHUFFLE)
129  }
130  }
131  return totalCost;
132 }
OperationCost
@ DIFFERENTVECTORSHUFFLECOST
@ DIFFERENTVECTORNOSHUFFLE
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
size_t totalCost() const
Definition: ArcCostModel.h:26