diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Legality.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Legality.h index 50fa56c5b2194..233abf3efd64e 100644 --- a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Legality.h +++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Legality.h @@ -13,6 +13,8 @@ #define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_LEGALITY_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/raw_ostream.h" namespace llvm::sandboxir { @@ -20,9 +22,38 @@ class LegalityAnalysis; class Value; enum class LegalityResultID { + Pack, ///> Collect scalar values. Widen, ///> Vectorize by combining scalars to a vector. }; +/// The reason for vectorizing or not vectorizing. +enum class ResultReason { + DiffOpcodes, + DiffTypes, +}; + +#ifndef NDEBUG +struct ToStr { + static const char *getLegalityResultID(LegalityResultID ID) { + switch (ID) { + case LegalityResultID::Pack: + return "Pack"; + case LegalityResultID::Widen: + return "Widen"; + } + } + + static const char *getVecReason(ResultReason Reason) { + switch (Reason) { + case ResultReason::DiffOpcodes: + return "DiffOpcodes"; + case ResultReason::DiffTypes: + return "DiffTypes"; + } + } +}; +#endif // NDEBUG + /// The legality outcome is represented by a class rather than an enum class /// because in some cases the legality checks are expensive and look for a /// particular instruction that can be passed along to the vectorizer to avoid @@ -35,7 +66,34 @@ class LegalityResult { friend class LegalityAnalysis; public: + virtual ~LegalityResult() {} LegalityResultID getSubclassID() const { return ID; } +#ifndef NDEBUG + virtual void print(raw_ostream &OS) const { + OS << ToStr::getLegalityResultID(ID); + } + LLVM_DUMP_METHOD void dump() const; + friend raw_ostream &operator<<(raw_ostream &OS, const LegalityResult &LR) { + LR.print(OS); + return OS; + } +#endif // NDEBUG +}; + +/// Base class for results with reason. +class LegalityResultWithReason : public LegalityResult { + ResultReason Reason; + LegalityResultWithReason(LegalityResultID ID, ResultReason Reason) + : LegalityResult(ID), Reason(Reason) {} + friend class Pack; // For constructor. + +public: +#ifndef NDEBUG + void print(raw_ostream &OS) const override { + LegalityResult::print(OS); + OS << " Reason: " << ToStr::getVecReason(Reason); + } +#endif }; class Widen final : public LegalityResult { @@ -48,14 +106,37 @@ class Widen final : public LegalityResult { } }; +class Pack final : public LegalityResultWithReason { + Pack(ResultReason Reason) + : LegalityResultWithReason(LegalityResultID::Pack, Reason) {} + friend class LegalityAnalysis; // For constructor. + +public: + static bool classof(const LegalityResult *From) { + return From->getSubclassID() == LegalityResultID::Pack; + } +}; + /// Performs the legality analysis and returns a LegalityResult object. class LegalityAnalysis { + /// Owns the legality result objects created by createLegalityResult(). + SmallVector> ResultPool; + /// Checks opcodes, types and other IR-specifics and returns a ResultReason + /// object if not vectorizable, or nullptr otherwise. + std::optional + notVectorizableBasedOnOpcodesAndTypes(ArrayRef Bndl); + public: LegalityAnalysis() = default; - LegalityResult canVectorize(ArrayRef Bndl) { - // TODO: For now everything is legal. - return Widen(); + /// A LegalityResult factory. + template + ResultT &createLegalityResult(ArgsT... Args) { + ResultPool.push_back(std::unique_ptr(new ResultT(Args...))); + return cast(*ResultPool.back()); } + /// Checks if it's legal to vectorize the instructions in \p Bndl. + /// \Returns a LegalityResult object owned by LegalityAnalysis. + LegalityResult &canVectorize(ArrayRef Bndl); }; } // namespace llvm::sandboxir diff --git a/llvm/lib/Transforms/Vectorize/CMakeLists.txt b/llvm/lib/Transforms/Vectorize/CMakeLists.txt index fc4355af5af6b..d769d5100afd2 100644 --- a/llvm/lib/Transforms/Vectorize/CMakeLists.txt +++ b/llvm/lib/Transforms/Vectorize/CMakeLists.txt @@ -5,6 +5,7 @@ add_llvm_component_library(LLVMVectorize LoopVectorize.cpp SandboxVectorizer/DependencyGraph.cpp SandboxVectorizer/Interval.cpp + SandboxVectorizer/Legality.cpp SandboxVectorizer/Passes/BottomUpVec.cpp SandboxVectorizer/Passes/RegionsFromMetadata.cpp SandboxVectorizer/SandboxVectorizer.cpp diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Legality.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Legality.cpp new file mode 100644 index 0000000000000..0e2cd83c37b0c --- /dev/null +++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Legality.cpp @@ -0,0 +1,39 @@ +//===- Legality.cpp -------------------------------------------------------===// +// +// 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/Legality.h" +#include "llvm/SandboxIR/Value.h" +#include "llvm/Support/Debug.h" + +namespace llvm::sandboxir { + +#ifndef NDEBUG +void LegalityResult::dump() const { + print(dbgs()); + dbgs() << "\n"; +} +#endif // NDEBUG + +std::optional +LegalityAnalysis::notVectorizableBasedOnOpcodesAndTypes( + ArrayRef Bndl) { + // TODO: Unimplemented. + return std::nullopt; +} + +LegalityResult &LegalityAnalysis::canVectorize(ArrayRef Bndl) { + if (auto ReasonOpt = notVectorizableBasedOnOpcodesAndTypes(Bndl)) + return createLegalityResult(*ReasonOpt); + + // TODO: Check for existing vectors containing values in Bndl. + + // TODO: Check with scheduler. + + return createLegalityResult(); +} +} // namespace llvm::sandboxir diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.cpp index 6171d5e52b586..f11420e47f3e1 100644 --- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.cpp +++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.cpp @@ -50,6 +50,10 @@ void BottomUpVec::vectorizeRec(ArrayRef Bndl) { } break; } + case LegalityResultID::Pack: { + // TODO: Unimplemented + llvm_unreachable("Unimplemented"); + } } } diff --git a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/LegalityTest.cpp b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/LegalityTest.cpp index e16222ddb2d61..76e5a5ce5aed9 100644 --- a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/LegalityTest.cpp +++ b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/LegalityTest.cpp @@ -55,3 +55,24 @@ define void @foo(ptr %ptr) { auto Result = Legality.canVectorize({St0, St1}); EXPECT_TRUE(isa(Result)); } + +#ifndef NDEBUG +TEST_F(LegalityTest, LegalityResultDump) { + auto Matches = [](const sandboxir::LegalityResult &Result, + const std::string &ExpectedStr) -> bool { + std::string Buff; + raw_string_ostream OS(Buff); + Result.print(OS); + return Buff == ExpectedStr; + }; + sandboxir::LegalityAnalysis Legality; + EXPECT_TRUE( + Matches(Legality.createLegalityResult(), "Widen")); + EXPECT_TRUE(Matches(Legality.createLegalityResult( + sandboxir::ResultReason::DiffOpcodes), + "Pack Reason: DiffOpcodes")); + EXPECT_TRUE(Matches(Legality.createLegalityResult( + sandboxir::ResultReason::DiffTypes), + "Pack Reason: DiffTypes")); +} +#endif // NDEBUG