//===- VPlan.h - VPlan-based SLP ------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// // /// \file /// This file contains the declarations for VPlan-based SLP. /// //===----------------------------------------------------------------------===// #ifndef LLVM_TRANSFORMS_VECTORIZE_VPLANSLP_H #define LLVM_TRANSFORMS_VECTORIZE_VPLANSLP_H #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Analysis/VectorUtils.h" namespace llvm { class VPBasicBlock; class VPBlockBase; class VPRegionBlock; class VPlan; class VPValue; class VPInstruction; class VPInterleavedAccessInfo { DenseMap *> InterleaveGroupMap; /// Type for mapping of instruction based interleave groups to VPInstruction /// interleave groups using Old2NewTy = DenseMap *, InterleaveGroup *>; /// Recursively \p Region and populate VPlan based interleave groups based on /// \p IAI. void visitRegion(VPRegionBlock *Region, Old2NewTy &Old2New, InterleavedAccessInfo &IAI); /// Recursively traverse \p Block and populate VPlan based interleave groups /// based on \p IAI. void visitBlock(VPBlockBase *Block, Old2NewTy &Old2New, InterleavedAccessInfo &IAI); public: LLVM_ABI_FOR_TEST VPInterleavedAccessInfo(VPlan &Plan, InterleavedAccessInfo &IAI); VPInterleavedAccessInfo(const VPInterleavedAccessInfo &) = delete; VPInterleavedAccessInfo &operator=(const VPInterleavedAccessInfo &) = delete; ~VPInterleavedAccessInfo() { // Avoid releasing a pointer twice. SmallPtrSet *, 4> DelSet( llvm::from_range, llvm::make_second_range(InterleaveGroupMap)); for (auto *Ptr : DelSet) delete Ptr; } /// Get the interleave group that \p Instr belongs to. /// /// \returns nullptr if doesn't have such group. InterleaveGroup * getInterleaveGroup(VPInstruction *Instr) const { return InterleaveGroupMap.lookup(Instr); } }; /// Class that maps (parts of) an existing VPlan to trees of combined /// VPInstructions. class VPlanSlp { enum class OpMode { Failed, Load, Opcode }; /// Mapping of values in the original VPlan to a combined VPInstruction. DenseMap, VPInstruction *> BundleToCombined; VPInterleavedAccessInfo &IAI; /// Basic block to operate on. For now, only instructions in a single BB are /// considered. const VPBasicBlock &BB; /// Indicates whether we managed to combine all visited instructions or not. bool CompletelySLP = true; /// Width of the widest combined bundle in bits. unsigned WidestBundleBits = 0; using MultiNodeOpTy = typename std::pair>; // Input operand bundles for the current multi node. Each multi node operand // bundle contains values not matching the multi node's opcode. They will // be reordered in reorderMultiNodeOps, once we completed building a // multi node. SmallVector MultiNodeOps; /// Indicates whether we are building a multi node currently. bool MultiNodeActive = false; /// Check if we can vectorize Operands together. bool areVectorizable(ArrayRef Operands) const; /// Add combined instruction \p New for the bundle \p Operands. void addCombined(ArrayRef Operands, VPInstruction *New); /// Indicate we hit a bundle we failed to combine. Returns nullptr for now. VPInstruction *markFailed(); /// Reorder operands in the multi node to maximize sequential memory access /// and commutative operations. SmallVector reorderMultiNodeOps(); /// Choose the best candidate to use for the lane after \p Last. The set of /// candidates to choose from are values with an opcode matching \p Last's /// or loads consecutive to \p Last. std::pair getBest(OpMode Mode, VPValue *Last, SmallPtrSetImpl &Candidates, VPInterleavedAccessInfo &IAI); #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) /// Print bundle \p Values to dbgs(). void dumpBundle(ArrayRef Values); #endif public: VPlanSlp(VPInterleavedAccessInfo &IAI, VPBasicBlock &BB) : IAI(IAI), BB(BB) {} ~VPlanSlp() = default; /// Tries to build an SLP tree rooted at \p Operands and returns a /// VPInstruction combining \p Operands, if they can be combined. LLVM_ABI_FOR_TEST VPInstruction *buildGraph(ArrayRef Operands); /// Return the width of the widest combined bundle in bits. unsigned getWidestBundleBits() const { return WidestBundleBits; } /// Return true if all visited instruction can be combined. bool isCompletelySLP() const { return CompletelySLP; } }; } // end namespace llvm #endif // LLVM_TRANSFORMS_VECTORIZE_VPLAN_H