1b8737614SUday Bondhugula //===- VectorizerTestPass.cpp - VectorizerTestPass Pass Impl --------------===// 2b8737614SUday Bondhugula // 3b8737614SUday Bondhugula // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4b8737614SUday Bondhugula // See https://llvm.org/LICENSE.txt for license information. 5b8737614SUday Bondhugula // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6b8737614SUday Bondhugula // 7b8737614SUday Bondhugula //===----------------------------------------------------------------------===// 8b8737614SUday Bondhugula // 9b8737614SUday Bondhugula // This file implements a simple testing pass for vectorization functionality. 10b8737614SUday Bondhugula // 11b8737614SUday Bondhugula //===----------------------------------------------------------------------===// 12b8737614SUday Bondhugula 13b8737614SUday Bondhugula #include "mlir/Analysis/SliceAnalysis.h" 14755dc07dSRiver Riddle #include "mlir/Dialect/Affine/Analysis/AffineAnalysis.h" 15755dc07dSRiver Riddle #include "mlir/Dialect/Affine/Analysis/NestedMatcher.h" 16b8737614SUday Bondhugula #include "mlir/Dialect/Affine/IR/AffineOps.h" 17a70aa7bbSRiver Riddle #include "mlir/Dialect/Affine/LoopUtils.h" 1893936da9SDiego Caballero #include "mlir/Dialect/Affine/Utils.h" 1936550692SRiver Riddle #include "mlir/Dialect/Func/IR/FuncOps.h" 207a69a9d7SNicolas Vasilache #include "mlir/Dialect/Utils/IndexingUtils.h" 2199ef9eebSMatthias Springer #include "mlir/Dialect/Vector/IR/VectorOps.h" 2299ef9eebSMatthias Springer #include "mlir/Dialect/Vector/Utils/VectorUtils.h" 23b8737614SUday Bondhugula #include "mlir/IR/Builders.h" 2409f7a55fSRiver Riddle #include "mlir/IR/BuiltinTypes.h" 25b8737614SUday Bondhugula #include "mlir/IR/Diagnostics.h" 26b8737614SUday Bondhugula #include "mlir/Pass/Pass.h" 27b8737614SUday Bondhugula #include "mlir/Transforms/Passes.h" 28b8737614SUday Bondhugula 29b8737614SUday Bondhugula #include "llvm/ADT/STLExtras.h" 30b8737614SUday Bondhugula #include "llvm/Support/CommandLine.h" 31b8737614SUday Bondhugula #include "llvm/Support/Debug.h" 32b8737614SUday Bondhugula 33b8737614SUday Bondhugula #define DEBUG_TYPE "affine-super-vectorizer-test" 34b8737614SUday Bondhugula 35b8737614SUday Bondhugula using namespace mlir; 364c48f016SMatthias Springer using namespace mlir::affine; 37b8737614SUday Bondhugula 38b8737614SUday Bondhugula static llvm::cl::OptionCategory clOptionsCategory(DEBUG_TYPE " options"); 39b8737614SUday Bondhugula 40b8737614SUday Bondhugula namespace { 4180aca1eaSRiver Riddle struct VectorizerTestPass 4258ceae95SRiver Riddle : public PassWrapper<VectorizerTestPass, OperationPass<func::FuncOp>> { 435e50dd04SRiver Riddle MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(VectorizerTestPass) 445e50dd04SRiver Riddle 45b8737614SUday Bondhugula static constexpr auto kTestAffineMapOpName = "test_affine_map"; 46b8737614SUday Bondhugula static constexpr auto kTestAffineMapAttrName = "affine_map"; 47f9dc2b70SMehdi Amini void getDependentDialects(DialectRegistry ®istry) const override { 48f9dc2b70SMehdi Amini registry.insert<vector::VectorDialect>(); 49f9dc2b70SMehdi Amini } 50b5e22e6dSMehdi Amini StringRef getArgument() const final { return "affine-super-vectorizer-test"; } 51b5e22e6dSMehdi Amini StringRef getDescription() const final { 52b5e22e6dSMehdi Amini return "Tests vectorizer standalone functionality."; 53b5e22e6dSMehdi Amini } 54b8737614SUday Bondhugula 55608a663cSPhilip Lassen VectorizerTestPass() = default; 56608a663cSPhilip Lassen VectorizerTestPass(const VectorizerTestPass &pass) : PassWrapper(pass){}; 57608a663cSPhilip Lassen 58608a663cSPhilip Lassen ListOption<int> clTestVectorShapeRatio{ 59608a663cSPhilip Lassen *this, "vector-shape-ratio", 60608a663cSPhilip Lassen llvm::cl::desc("Specify the HW vector size for vectorization")}; 61608a663cSPhilip Lassen Option<bool> clTestForwardSlicingAnalysis{ 62608a663cSPhilip Lassen *this, "forward-slicing", 63608a663cSPhilip Lassen llvm::cl::desc( 64608a663cSPhilip Lassen "Enable testing forward static slicing and topological sort " 65608a663cSPhilip Lassen "functionalities")}; 66608a663cSPhilip Lassen Option<bool> clTestBackwardSlicingAnalysis{ 67608a663cSPhilip Lassen *this, "backward-slicing", 68608a663cSPhilip Lassen llvm::cl::desc("Enable testing backward static slicing and " 69608a663cSPhilip Lassen "topological sort functionalities")}; 70608a663cSPhilip Lassen Option<bool> clTestSlicingAnalysis{ 71608a663cSPhilip Lassen *this, "slicing", 72608a663cSPhilip Lassen llvm::cl::desc("Enable testing static slicing and topological sort " 73608a663cSPhilip Lassen "functionalities")}; 74608a663cSPhilip Lassen Option<bool> clTestComposeMaps{ 75608a663cSPhilip Lassen *this, "compose-maps", 76608a663cSPhilip Lassen llvm::cl::desc("Enable testing the composition of AffineMap where each " 77608a663cSPhilip Lassen "AffineMap in the composition is specified as the " 78608a663cSPhilip Lassen "affine_map attribute " 79608a663cSPhilip Lassen "in a constant op.")}; 80608a663cSPhilip Lassen Option<bool> clTestVecAffineLoopNest{ 81608a663cSPhilip Lassen *this, "vectorize-affine-loop-nest", 82608a663cSPhilip Lassen llvm::cl::desc( 83608a663cSPhilip Lassen "Enable testing for the 'vectorizeAffineLoopNest' utility by " 84608a663cSPhilip Lassen "vectorizing the outermost loops found")}; 85608a663cSPhilip Lassen 8641574554SRiver Riddle void runOnOperation() override; 87b8737614SUday Bondhugula void testVectorShapeRatio(llvm::raw_ostream &outs); 88b8737614SUday Bondhugula void testForwardSlicing(llvm::raw_ostream &outs); 89b8737614SUday Bondhugula void testBackwardSlicing(llvm::raw_ostream &outs); 90b8737614SUday Bondhugula void testSlicing(llvm::raw_ostream &outs); 91b8737614SUday Bondhugula void testComposeMaps(llvm::raw_ostream &outs); 9293936da9SDiego Caballero 9393936da9SDiego Caballero /// Test for 'vectorizeAffineLoopNest' utility. 9410cff75fSKai Sasaki void testVecAffineLoopNest(llvm::raw_ostream &outs); 95b8737614SUday Bondhugula }; 96b8737614SUday Bondhugula 97be0a7e9fSMehdi Amini } // namespace 98b8737614SUday Bondhugula 99b8737614SUday Bondhugula void VectorizerTestPass::testVectorShapeRatio(llvm::raw_ostream &outs) { 10041574554SRiver Riddle auto f = getOperation(); 1014c48f016SMatthias Springer using affine::matcher::Op; 102b8737614SUday Bondhugula SmallVector<int64_t, 8> shape(clTestVectorShapeRatio.begin(), 103b8737614SUday Bondhugula clTestVectorShapeRatio.end()); 104*f023da12SMatthias Springer auto subVectorType = VectorType::get(shape, Float32Type::get(f.getContext())); 105b8737614SUday Bondhugula // Only filter operations that operate on a strict super-vector and have one 106b8737614SUday Bondhugula // return. This makes testing easier. 107b8737614SUday Bondhugula auto filter = [&](Operation &op) { 108b8737614SUday Bondhugula assert(subVectorType.getElementType().isF32() && 109b8737614SUday Bondhugula "Only f32 supported for now"); 1104c48f016SMatthias Springer if (!mlir::matcher::operatesOnSuperVectorsOf(op, subVectorType)) { 111b8737614SUday Bondhugula return false; 112b8737614SUday Bondhugula } 113b8737614SUday Bondhugula if (op.getNumResults() != 1) { 114b8737614SUday Bondhugula return false; 115b8737614SUday Bondhugula } 116b8737614SUday Bondhugula return true; 117b8737614SUday Bondhugula }; 118b8737614SUday Bondhugula auto pat = Op(filter); 119b8737614SUday Bondhugula SmallVector<NestedMatch, 8> matches; 120b8737614SUday Bondhugula pat.match(f, &matches); 121b8737614SUday Bondhugula for (auto m : matches) { 122b8737614SUday Bondhugula auto *opInst = m.getMatchedOperation(); 123b8737614SUday Bondhugula // This is a unit test that only checks and prints shape ratio. 124b8737614SUday Bondhugula // As a consequence we write only Ops with a single return type for the 125b8737614SUday Bondhugula // purpose of this test. If we need to test more intricate behavior in the 126b8737614SUday Bondhugula // future we can always extend. 1275550c821STres Popp auto superVectorType = cast<VectorType>(opInst->getResult(0).getType()); 1287a69a9d7SNicolas Vasilache auto ratio = 1297a69a9d7SNicolas Vasilache computeShapeRatio(superVectorType.getShape(), subVectorType.getShape()); 130037f0995SKazu Hirata if (!ratio) { 131b8737614SUday Bondhugula opInst->emitRemark("NOT MATCHED"); 132b8737614SUday Bondhugula } else { 133b8737614SUday Bondhugula outs << "\nmatched: " << *opInst << " with shape ratio: "; 1342f21a579SRiver Riddle llvm::interleaveComma(MutableArrayRef<int64_t>(*ratio), outs); 135b8737614SUday Bondhugula } 136b8737614SUday Bondhugula } 137b8737614SUday Bondhugula } 138b8737614SUday Bondhugula 139b8737614SUday Bondhugula static NestedPattern patternTestSlicingOps() { 1404c48f016SMatthias Springer using affine::matcher::Op; 141b8737614SUday Bondhugula // Match all operations with the kTestSlicingOpName name. 142b8737614SUday Bondhugula auto filter = [](Operation &op) { 143b8737614SUday Bondhugula // Just use a custom op name for this test, it makes life easier. 144b8737614SUday Bondhugula return op.getName().getStringRef() == "slicing-test-op"; 145b8737614SUday Bondhugula }; 146b8737614SUday Bondhugula return Op(filter); 147b8737614SUday Bondhugula } 148b8737614SUday Bondhugula 149b8737614SUday Bondhugula void VectorizerTestPass::testBackwardSlicing(llvm::raw_ostream &outs) { 15041574554SRiver Riddle auto f = getOperation(); 151b8737614SUday Bondhugula outs << "\n" << f.getName(); 152b8737614SUday Bondhugula 153b8737614SUday Bondhugula SmallVector<NestedMatch, 8> matches; 154b8737614SUday Bondhugula patternTestSlicingOps().match(f, &matches); 155b8737614SUday Bondhugula for (auto m : matches) { 156b8737614SUday Bondhugula SetVector<Operation *> backwardSlice; 157b8737614SUday Bondhugula getBackwardSlice(m.getMatchedOperation(), &backwardSlice); 158b8737614SUday Bondhugula outs << "\nmatched: " << *m.getMatchedOperation() 159b8737614SUday Bondhugula << " backward static slice: "; 160b8737614SUday Bondhugula for (auto *op : backwardSlice) 161b8737614SUday Bondhugula outs << "\n" << *op; 162b8737614SUday Bondhugula } 163b8737614SUday Bondhugula } 164b8737614SUday Bondhugula 165b8737614SUday Bondhugula void VectorizerTestPass::testForwardSlicing(llvm::raw_ostream &outs) { 16641574554SRiver Riddle auto f = getOperation(); 167b8737614SUday Bondhugula outs << "\n" << f.getName(); 168b8737614SUday Bondhugula 169b8737614SUday Bondhugula SmallVector<NestedMatch, 8> matches; 170b8737614SUday Bondhugula patternTestSlicingOps().match(f, &matches); 171b8737614SUday Bondhugula for (auto m : matches) { 172b8737614SUday Bondhugula SetVector<Operation *> forwardSlice; 173b8737614SUday Bondhugula getForwardSlice(m.getMatchedOperation(), &forwardSlice); 174b8737614SUday Bondhugula outs << "\nmatched: " << *m.getMatchedOperation() 175b8737614SUday Bondhugula << " forward static slice: "; 176b8737614SUday Bondhugula for (auto *op : forwardSlice) 177b8737614SUday Bondhugula outs << "\n" << *op; 178b8737614SUday Bondhugula } 179b8737614SUday Bondhugula } 180b8737614SUday Bondhugula 181b8737614SUday Bondhugula void VectorizerTestPass::testSlicing(llvm::raw_ostream &outs) { 18241574554SRiver Riddle auto f = getOperation(); 183b8737614SUday Bondhugula outs << "\n" << f.getName(); 184b8737614SUday Bondhugula 185b8737614SUday Bondhugula SmallVector<NestedMatch, 8> matches; 186b8737614SUday Bondhugula patternTestSlicingOps().match(f, &matches); 187b8737614SUday Bondhugula for (auto m : matches) { 188b8737614SUday Bondhugula SetVector<Operation *> staticSlice = getSlice(m.getMatchedOperation()); 189b8737614SUday Bondhugula outs << "\nmatched: " << *m.getMatchedOperation() << " static slice: "; 190b8737614SUday Bondhugula for (auto *op : staticSlice) 191b8737614SUday Bondhugula outs << "\n" << *op; 192b8737614SUday Bondhugula } 193b8737614SUday Bondhugula } 194b8737614SUday Bondhugula 195b8737614SUday Bondhugula static bool customOpWithAffineMapAttribute(Operation &op) { 196b8737614SUday Bondhugula return op.getName().getStringRef() == 197b8737614SUday Bondhugula VectorizerTestPass::kTestAffineMapOpName; 198b8737614SUday Bondhugula } 199b8737614SUday Bondhugula 200b8737614SUday Bondhugula void VectorizerTestPass::testComposeMaps(llvm::raw_ostream &outs) { 20141574554SRiver Riddle auto f = getOperation(); 202b8737614SUday Bondhugula 2034c48f016SMatthias Springer using affine::matcher::Op; 204b8737614SUday Bondhugula auto pattern = Op(customOpWithAffineMapAttribute); 205b8737614SUday Bondhugula SmallVector<NestedMatch, 8> matches; 206b8737614SUday Bondhugula pattern.match(f, &matches); 207b8737614SUday Bondhugula SmallVector<AffineMap, 4> maps; 208b8737614SUday Bondhugula maps.reserve(matches.size()); 209b8737614SUday Bondhugula for (auto m : llvm::reverse(matches)) { 210b8737614SUday Bondhugula auto *opInst = m.getMatchedOperation(); 211830b9b07SMehdi Amini auto map = 212830b9b07SMehdi Amini cast<AffineMapAttr>(opInst->getDiscardableAttr( 213830b9b07SMehdi Amini VectorizerTestPass::kTestAffineMapAttrName)) 214b8737614SUday Bondhugula .getValue(); 215b8737614SUday Bondhugula maps.push_back(map); 216b8737614SUday Bondhugula } 2173d7383d7SKai Sasaki if (maps.empty()) 2183d7383d7SKai Sasaki // Nothing to compose 2193d7383d7SKai Sasaki return; 220b8737614SUday Bondhugula AffineMap res; 221b8737614SUday Bondhugula for (auto m : maps) { 222b8737614SUday Bondhugula res = res ? res.compose(m) : m; 223b8737614SUday Bondhugula } 224b8737614SUday Bondhugula simplifyAffineMap(res).print(outs << "\nComposed map: "); 225b8737614SUday Bondhugula } 226b8737614SUday Bondhugula 22793936da9SDiego Caballero /// Test for 'vectorizeAffineLoopNest' utility. 22810cff75fSKai Sasaki void VectorizerTestPass::testVecAffineLoopNest(llvm::raw_ostream &outs) { 22993936da9SDiego Caballero std::vector<SmallVector<AffineForOp, 2>> loops; 23041574554SRiver Riddle gatherLoops(getOperation(), loops); 231b8737614SUday Bondhugula 23293936da9SDiego Caballero // Expected only one loop nest. 23393936da9SDiego Caballero if (loops.empty() || loops[0].size() != 1) 23493936da9SDiego Caballero return; 23593936da9SDiego Caballero 23693936da9SDiego Caballero // We vectorize the outermost loop found with VF=4. 23793936da9SDiego Caballero AffineForOp outermostLoop = loops[0][0]; 23893936da9SDiego Caballero VectorizationStrategy strategy; 23993936da9SDiego Caballero strategy.vectorSizes.push_back(4 /*vectorization factor*/); 24093936da9SDiego Caballero strategy.loopToVectorDim[outermostLoop] = 0; 24110cff75fSKai Sasaki 24210cff75fSKai Sasaki ReductionLoopMap reductionLoops; 24310cff75fSKai Sasaki SmallVector<LoopReduction, 2> reductions; 24410cff75fSKai Sasaki if (!isLoopParallel(outermostLoop, &reductions)) { 24510cff75fSKai Sasaki outs << "Outermost loop cannot be parallel\n"; 24610cff75fSKai Sasaki return; 24710cff75fSKai Sasaki } 24893936da9SDiego Caballero std::vector<SmallVector<AffineForOp, 2>> loopsToVectorize; 24993936da9SDiego Caballero loopsToVectorize.push_back({outermostLoop}); 250e21adfa3SRiver Riddle (void)vectorizeAffineLoopNest(loopsToVectorize, strategy); 25193936da9SDiego Caballero } 25293936da9SDiego Caballero 25341574554SRiver Riddle void VectorizerTestPass::runOnOperation() { 254b8737614SUday Bondhugula // Only support single block functions at this point. 25558ceae95SRiver Riddle func::FuncOp f = getOperation(); 2562eaadfc4SRahul Joshi if (!llvm::hasSingleElement(f)) 257b8737614SUday Bondhugula return; 258b8737614SUday Bondhugula 259b8737614SUday Bondhugula std::string str; 260b8737614SUday Bondhugula llvm::raw_string_ostream outs(str); 261b8737614SUday Bondhugula 26293936da9SDiego Caballero { // Tests that expect a NestedPatternContext to be allocated externally. 26393936da9SDiego Caballero NestedPatternContext mlContext; 26493936da9SDiego Caballero 265b8737614SUday Bondhugula if (!clTestVectorShapeRatio.empty()) 266b8737614SUday Bondhugula testVectorShapeRatio(outs); 267b8737614SUday Bondhugula 268b8737614SUday Bondhugula if (clTestForwardSlicingAnalysis) 269b8737614SUday Bondhugula testForwardSlicing(outs); 270b8737614SUday Bondhugula 271b8737614SUday Bondhugula if (clTestBackwardSlicingAnalysis) 272b8737614SUday Bondhugula testBackwardSlicing(outs); 273b8737614SUday Bondhugula 274b8737614SUday Bondhugula if (clTestSlicingAnalysis) 275b8737614SUday Bondhugula testSlicing(outs); 276b8737614SUday Bondhugula 277b8737614SUday Bondhugula if (clTestComposeMaps) 278b8737614SUday Bondhugula testComposeMaps(outs); 27993936da9SDiego Caballero } 28093936da9SDiego Caballero 28193936da9SDiego Caballero if (clTestVecAffineLoopNest) 28210cff75fSKai Sasaki testVecAffineLoopNest(outs); 283b8737614SUday Bondhugula 284b8737614SUday Bondhugula if (!outs.str().empty()) { 285b8737614SUday Bondhugula emitRemark(UnknownLoc::get(&getContext()), outs.str()); 286b8737614SUday Bondhugula } 287b8737614SUday Bondhugula } 288b8737614SUday Bondhugula 289b8737614SUday Bondhugula namespace mlir { 290b5e22e6dSMehdi Amini void registerVectorizerTestPass() { PassRegistration<VectorizerTestPass>(); } 291b8737614SUday Bondhugula } // namespace mlir 292