| //===- SeedCollection.cpp - Seed collection pass --------------------------===// | |
| // | |
| // 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 "llvm/Transforms/Vectorize/SandboxVectorizer/Passes/SeedCollection.h" | |
| #include "llvm/Analysis/TargetTransformInfo.h" | |
| #include "llvm/SandboxIR/Module.h" | |
| #include "llvm/Transforms/Vectorize/SandboxVectorizer/RegionWithScore.h" | |
| #include "llvm/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizerPassBuilder.h" | |
| #include "llvm/Transforms/Vectorize/SandboxVectorizer/SeedCollector.h" | |
| #include "llvm/Transforms/Vectorize/SandboxVectorizer/VecUtils.h" | |
| namespace llvm { | |
| static cl::opt<unsigned> | |
| OverrideVecRegBits("sbvec-vec-reg-bits", cl::init(0), cl::Hidden, | |
| cl::desc("Override the vector register size in bits, " | |
| "which is otherwise found by querying TTI.")); | |
| static cl::opt<bool> | |
| AllowNonPow2("sbvec-allow-non-pow2", cl::init(false), cl::Hidden, | |
| cl::desc("Allow non-power-of-2 vectorization.")); | |
| #define LoadSeedsDef "loads" | |
| #define StoreSeedsDef "stores" | |
| cl::opt<std::string> CollectSeeds( | |
| "sbvec-collect-seeds", cl::init(StoreSeedsDef), cl::Hidden, | |
| cl::desc("Collect these seeds. Use empty for none or a comma-separated " | |
| "list of '" StoreSeedsDef "' and '" LoadSeedsDef "'.")); | |
| namespace sandboxir { | |
| SeedCollection::SeedCollection(StringRef Pipeline, StringRef AuxArg) | |
| : FunctionPass("seed-collection"), | |
| RPM("rpm", Pipeline, SandboxVectorizerPassBuilder::createRegionPass) { | |
| if (!AuxArg.empty()) { | |
| if (AuxArg != DiffTypesArgStr) { | |
| std::string ErrStr; | |
| raw_string_ostream ErrSS(ErrStr); | |
| ErrSS << "SeedCollection only supports '" << DiffTypesArgStr | |
| << "' aux argument!\n"; | |
| reportFatalUsageError(ErrStr.c_str()); | |
| } | |
| AllowDiffTypes = true; | |
| } | |
| } | |
| bool SeedCollection::runOnFunction(Function &F, const Analyses &A) { | |
| bool Change = false; | |
| const auto &DL = F.getParent()->getDataLayout(); | |
| bool CollectStores = CollectSeeds.find(StoreSeedsDef) != std::string::npos; | |
| bool CollectLoads = CollectSeeds.find(LoadSeedsDef) != std::string::npos; | |
| // TODO: Start from innermost BBs first | |
| for (auto &BB : F) { | |
| SeedCollector SC(&BB, A.getScalarEvolution(), CollectStores, CollectLoads, | |
| AllowDiffTypes); | |
| for (auto &SeedRange : {SC.getStoreSeeds(), SC.getLoadSeeds()}) { | |
| for (SeedBundle &Seeds : SeedRange) { | |
| unsigned ElmBits = | |
| Utils::getNumBits(VecUtils::getElementType(Utils::getExpectedType( | |
| Seeds[Seeds.getFirstUnusedElementIdx()])), | |
| DL); | |
| unsigned AS = getLoadStoreAddressSpace(Seeds[0]); | |
| unsigned VecRegBits = OverrideVecRegBits != 0 | |
| ? OverrideVecRegBits | |
| : A.getTTI().getLoadStoreVecRegBitWidth(AS); | |
| auto DivideBy2 = [](unsigned Num) { | |
| auto Floor = VecUtils::getFloorPowerOf2(Num); | |
| if (Floor == Num) | |
| return Floor / 2; | |
| return Floor; | |
| }; | |
| // Try to create the largest vector supported by the target. If it fails | |
| // reduce the vector size by half. | |
| for (unsigned SliceElms = std::min(VecRegBits / ElmBits, | |
| Seeds.getNumUnusedBits() / ElmBits); | |
| SliceElms >= 2u; SliceElms = DivideBy2(SliceElms)) { | |
| if (Seeds.allUsed()) | |
| break; | |
| // Keep trying offsets after FirstUnusedElementIdx, until we vectorize | |
| // the slice. This could be quite expensive, so we enforce a limit. | |
| for (unsigned Offset = Seeds.getFirstUnusedElementIdx(), | |
| OE = Seeds.size(); | |
| Offset + 1 < OE; Offset += 1) { | |
| // Seeds are getting used as we vectorize, so skip them. | |
| if (Seeds.isUsed(Offset)) | |
| continue; | |
| if (Seeds.allUsed()) | |
| break; | |
| auto SeedSlice = | |
| Seeds.getSlice(Offset, SliceElms * ElmBits, !AllowNonPow2); | |
| if (SeedSlice.empty()) | |
| continue; | |
| assert(SeedSlice.size() >= 2 && "Should have been rejected!"); | |
| // Create a region containing the seed slice. | |
| auto &Ctx = F.getContext(); | |
| RegionWithScore Rgn(Ctx, A.getTTI()); | |
| Rgn.setAux(SeedSlice); | |
| // Run the region pass pipeline. | |
| Change |= RPM.runOnRegion(Rgn, A); | |
| Rgn.clearAux(); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| return Change; | |
| } | |
| } // namespace sandboxir | |
| } // namespace llvm |