blob: 9c2160c1450a189d06f5afcc1e3f9a8e2b86311a [file] [log] [blame]
Nicolas Vasilache13b3bce2018-11-20 08:36:07 -08001//===- VectorAnalysis.cpp - Analysis for Vectorization --------------------===//
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#include "mlir/Analysis/VectorAnalysis.h"
19#include "mlir/IR/BuiltinOps.h"
20#include "mlir/IR/Statements.h"
Nicolas Vasilache9a19ada2018-12-03 15:21:27 -080021#include "mlir/StandardOps/StandardOps.h"
Nicolas Vasilache13b3bce2018-11-20 08:36:07 -080022#include "mlir/Support/Functional.h"
23#include "mlir/Support/STLExtras.h"
24
25///
26/// Implements Analysis functions specific to vectors which support
27/// the vectorization and vectorization materialization passes.
28///
29
30using namespace mlir;
31
Nicolas Vasilache13b3bce2018-11-20 08:36:07 -080032Optional<SmallVector<unsigned, 4>> mlir::shapeRatio(ArrayRef<int> superShape,
33 ArrayRef<int> subShape) {
34 if (superShape.size() < subShape.size()) {
35 return Optional<SmallVector<unsigned, 4>>();
36 }
37
38 // Starting from the end, compute the integer divisors.
39 // Set the boolean `divides` if integral division is not possible.
40 std::vector<unsigned> result;
41 result.reserve(superShape.size());
42 bool divides = true;
43 auto divide = [&divides, &result](int superSize, int subSize) {
44 assert(superSize > 0 && "superSize must be > 0");
45 assert(subSize > 0 && "subSize must be > 0");
46 divides &= (superSize % subSize == 0);
47 result.push_back(superSize / subSize);
48 };
Nicolas Vasilacheb8863072018-11-21 12:34:10 -080049 functional::zipApply(
50 divide, SmallVector<int, 8>{superShape.rbegin(), superShape.rend()},
51 SmallVector<int, 8>{subShape.rbegin(), subShape.rend()});
Nicolas Vasilache13b3bce2018-11-20 08:36:07 -080052
53 // If integral division does not occur, return and let the caller decide.
54 if (!divides) {
Nicolas Vasilacheb8863072018-11-21 12:34:10 -080055 return None;
Nicolas Vasilache13b3bce2018-11-20 08:36:07 -080056 }
57
Nicolas Vasilacheb8863072018-11-21 12:34:10 -080058 // At this point we computed the ratio (in reverse) for the common
Nicolas Vasilache13b3bce2018-11-20 08:36:07 -080059 // size. Fill with the remaining entries from the super-vector shape (still in
60 // reverse).
61 int commonSize = subShape.size();
62 std::copy(superShape.rbegin() + commonSize, superShape.rend(),
63 std::back_inserter(result));
64
65 assert(result.size() == superShape.size() &&
Nicolas Vasilacheb8863072018-11-21 12:34:10 -080066 "super to sub shape ratio is not of the same size as the super rank");
Nicolas Vasilache13b3bce2018-11-20 08:36:07 -080067
68 // Reverse again to get it back in the proper order and return.
69 return SmallVector<unsigned, 4>{result.rbegin(), result.rend()};
70}
71
72Optional<SmallVector<unsigned, 4>> mlir::shapeRatio(VectorType superVectorType,
73 VectorType subVectorType) {
74 assert(superVectorType.getElementType() == subVectorType.getElementType() &&
75 "NYI: vector types must be of the same elemental type");
Nicolas Vasilache13b3bce2018-11-20 08:36:07 -080076 return shapeRatio(superVectorType.getShape(), subVectorType.getShape());
77}
78
Nicolas Vasilache9a19ada2018-12-03 15:21:27 -080079AffineMap mlir::makePermutationMap(MemRefType memrefType,
80 VectorType vectorType) {
81 unsigned memRefRank = memrefType.getRank();
82 unsigned vectorRank = vectorType.getRank();
83 assert(memRefRank >= vectorRank && "Broadcast not supported");
84 unsigned offset = memRefRank - vectorRank;
85 SmallVector<AffineExpr, 4> perm;
86 perm.reserve(memRefRank);
87 for (unsigned i = 0; i < vectorRank; ++i) {
88 perm.push_back(getAffineDimExpr(offset + i, memrefType.getContext()));
89 }
90 return AffineMap::get(memRefRank, 0, perm, {});
91}
92
Nicolas Vasilache13b3bce2018-11-20 08:36:07 -080093bool mlir::matcher::operatesOnStrictSuperVectors(const OperationStmt &opStmt,
94 VectorType subVectorType) {
95 // First, extract the vector type and ditinguish between:
96 // a. ops that *must* lower a super-vector (i.e. vector_transfer_read,
97 // vector_transfer_write); and
98 // b. ops that *may* lower a super-vector (all other ops).
Nicolas Vasilacheb8863072018-11-21 12:34:10 -080099 // The ops that *may* lower a super-vector only do so if the super-vector to
100 // sub-vector ratio is striclty greater than 1. The ops that *must* lower a
101 // super-vector are explicitly checked for this property.
Nicolas Vasilache13b3bce2018-11-20 08:36:07 -0800102 /// TODO(ntv): there should be a single function for all ops to do this so we
103 /// do not have to special case. Maybe a trait, or just a method, unclear atm.
104 bool mustDivide = false;
105 VectorType superVectorType;
Nicolas Vasilache9a19ada2018-12-03 15:21:27 -0800106 if (auto read = opStmt.dyn_cast<VectorTransferReadOp>()) {
107 superVectorType = read->getResultType();
Nicolas Vasilache13b3bce2018-11-20 08:36:07 -0800108 mustDivide = true;
Nicolas Vasilache9a19ada2018-12-03 15:21:27 -0800109 } else if (auto write = opStmt.dyn_cast<VectorTransferWriteOp>()) {
110 superVectorType = write->getVectorType();
Nicolas Vasilache13b3bce2018-11-20 08:36:07 -0800111 mustDivide = true;
112 } else if (opStmt.getNumResults() == 0) {
Nicolas Vasilacheb8863072018-11-21 12:34:10 -0800113 assert(opStmt.isa<ReturnOp>() &&
Nicolas Vasilache13b3bce2018-11-20 08:36:07 -0800114 "NYI: assuming only return statements can have 0 results at this "
115 "point");
116 return false;
117 } else if (opStmt.getNumResults() == 1) {
118 if (auto v = opStmt.getResult(0)->getType().dyn_cast<VectorType>()) {
119 superVectorType = v;
120 } else {
121 // Not a vector type.
122 return false;
123 }
124 } else {
125 // Not a vector_transfer and has more than 1 result, fail hard for now to
126 // wake us up when something changes.
127 assert(false && "NYI: statement has more than 1 result");
128 return false;
129 }
130
Nicolas Vasilacheb8863072018-11-21 12:34:10 -0800131 // Get the ratio.
132 auto ratio = shapeRatio(superVectorType, subVectorType);
Nicolas Vasilache13b3bce2018-11-20 08:36:07 -0800133
134 // Sanity check.
Nicolas Vasilacheb8863072018-11-21 12:34:10 -0800135 assert((ratio.hasValue() || !mustDivide) &&
Nicolas Vasilache13b3bce2018-11-20 08:36:07 -0800136 "NYI: vector_transfer instruction in which super-vector size is not an"
137 " integer multiple of sub-vector size");
138
139 // This catches cases that are not strictly necessary to have multiplicity but
140 // still aren't divisible by the sub-vector shape.
141 // This could be useful information if we wanted to reshape at the level of
142 // the vector type (but we would have to look at the compute and distinguish
143 // between parallel, reduction and possibly other cases.
Nicolas Vasilacheb8863072018-11-21 12:34:10 -0800144 if (!ratio.hasValue()) {
Nicolas Vasilache13b3bce2018-11-20 08:36:07 -0800145 return false;
146 }
147
148 // A strict super-vector is at least 2 sub-vectors.
Nicolas Vasilacheb8863072018-11-21 12:34:10 -0800149 for (auto m : *ratio) {
Nicolas Vasilache13b3bce2018-11-20 08:36:07 -0800150 if (m > 1) {
151 return true;
152 }
153 }
154
155 // Not a strict super-vector.
156 return false;
157}