blob: dc56d62b107f4bac1d95deb3ab89e5699f2f78d2 [file] [log] [blame]
Uday Bondhugulacf4f4c42018-09-12 10:21:23 -07001//===- LoopAnalysis.cpp - Misc loop analysis routines //-------------------===//
2//
3// Copyright 2019 The MLIR Authors.
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16// =============================================================================
17//
18// This file implements miscellaneous loop analysis routines.
19//
20//===----------------------------------------------------------------------===//
21
22#include "mlir/Analysis/LoopAnalysis.h"
23
24#include "mlir/Analysis/AffineAnalysis.h"
25#include "mlir/IR/AffineExpr.h"
26#include "mlir/IR/AffineMap.h"
27#include "mlir/IR/Statements.h"
28
29using mlir::AffineExpr;
30
31/// Returns the trip count of the loop as an affine expression if the latter is
32/// expressible as an affine expression, and nullptr otherwise. The trip count
33/// expression is simplified before returning.
34AffineExpr *mlir::getTripCount(const ForStmt &forStmt) {
35 // upper_bound - lower_bound + 1
36 int64_t loopSpan;
37
38 int64_t step = forStmt.getStep();
39 auto *context = forStmt.getContext();
40
41 if (forStmt.hasConstantBounds()) {
42 int64_t lb = forStmt.getConstantLowerBound();
43 int64_t ub = forStmt.getConstantUpperBound();
44 loopSpan = ub - lb + 1;
45 } else {
46 const AffineBound lb = forStmt.getLowerBound();
47 const AffineBound ub = forStmt.getUpperBound();
48 auto lbMap = lb.getMap();
49 auto ubMap = ub.getMap();
50 // TODO(bondhugula): handle max/min of multiple expressions.
51 if (lbMap->getNumResults() != 1 || ubMap->getNumResults() != 1 ||
52 lbMap->getNumDims() != ubMap->getNumDims() ||
53 lbMap->getNumSymbols() != ubMap->getNumSymbols()) {
54 return nullptr;
55 }
56
57 // TODO(bondhugula): handle bounds with different operands.
58 unsigned i, e = lb.getNumOperands();
59 for (i = 0; i < e; i++) {
60 if (lb.getStmtOperand(i).get() != ub.getStmtOperand(i).get())
61 break;
62 }
63 // Bounds have different operands, unhandled for now.
64 if (i != e)
65 return nullptr;
66
67 // ub_expr - lb_expr + 1
68 auto *loopSpanExpr = AffineBinaryOpExpr::getAdd(
69 AffineBinaryOpExpr::getSub(ubMap->getResult(0), lbMap->getResult(0),
70 context),
71 1, context);
72
73 if (auto *expr = simplifyAffineExpr(loopSpanExpr, lbMap->getNumDims(),
74 lbMap->getNumSymbols(), context))
75 loopSpanExpr = expr;
76
77 auto *cExpr = dyn_cast<AffineConstantExpr>(loopSpanExpr);
78 if (!cExpr)
79 return AffineBinaryOpExpr::getCeilDiv(loopSpanExpr, std::abs(step),
80 context);
81 loopSpan = cExpr->getValue();
82 }
83
84 // 0 iteration loops.
85 if ((loopSpan < 0 && step >= 1) || (loopSpan > 0 && step <= -1))
86 return 0;
87
88 return AffineConstantExpr::get(
89 static_cast<uint64_t>(loopSpan % step == 0 ? loopSpan / step
90 : loopSpan / step + 1),
91 context);
92}
93
94/// Returns the trip count of the loop if it's a constant, None otherwise. This
95/// method uses affine expression analysis (in turn using getTripCount) and is
96/// able to determine constant trip count in non-trivial cases.
97llvm::Optional<uint64_t> mlir::getConstantTripCount(const ForStmt &forStmt) {
98 AffineExpr *tripCountExpr = getTripCount(forStmt);
99
100 if (auto *constExpr = dyn_cast_or_null<AffineConstantExpr>(tripCountExpr))
101 return constExpr->getValue();
102
103 return None;
104}
105
106/// Returns the greatest known integral divisor of the trip count. Affine
107/// expression analysis is used (indirectly through getTripCount), and
108/// this method is thus able to determine non-trivial divisors.
109uint64_t mlir::getLargestDivisorOfTripCount(const ForStmt &forStmt) {
110 AffineExpr *tripCountExpr = getTripCount(forStmt);
111
112 if (!tripCountExpr)
113 return 1;
114
115 if (auto *constExpr = dyn_cast<AffineConstantExpr>(tripCountExpr)) {
116 uint64_t tripCount = constExpr->getValue();
117
118 // 0 iteration loops (greatest divisor is 2^64 - 1).
119 if (tripCount == 0)
120 return ULONG_MAX;
121
122 // The greatest divisor is the trip count.
123 return tripCount;
124 }
125
126 // Trip count is not a known constant; return its largest known divisor.
127 return tripCountExpr->getLargestKnownDivisor();
128}