//===- Region.h -------------------------------------------------*- C++ -*-===// // // 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 // //===----------------------------------------------------------------------===// #ifndef LLVM_SANDBOXIR_REGION_H #define LLVM_SANDBOXIR_REGION_H #include "llvm/Support/Compiler.h" #include #include "llvm/ADT/SetVector.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/SandboxIR/Instruction.h" #include "llvm/Support/raw_ostream.h" namespace llvm::sandboxir { class Region; class ScoreBoard { const Region &Rgn; TargetTransformInfo &TTI; constexpr static TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput; /// The cost of all instructions added to the region. InstructionCost AfterCost = 0; /// The cost of all instructions that got removed and replaced by new ones. InstructionCost BeforeCost = 0; /// Helper for both add() and remove(). \Returns the TTI cost of \p I. LLVM_ABI InstructionCost getCost(Instruction *I) const; /// No need to allow copies. ScoreBoard(const ScoreBoard &) = delete; const ScoreBoard &operator=(const ScoreBoard &) = delete; public: ScoreBoard(Region &Rgn, TargetTransformInfo &TTI) : Rgn(Rgn), TTI(TTI) {} /// Mark \p I as a newly added instruction to the region. void add(Instruction *I) { AfterCost += getCost(I); } /// Mark \p I as a deleted instruction from the region. LLVM_ABI void remove(Instruction *I); /// \Returns the cost of the newly added instructions. InstructionCost getAfterCost() const { return AfterCost; } /// \Returns the cost of the Removed instructions. InstructionCost getBeforeCost() const { return BeforeCost; } #ifndef NDEBUG void dump(raw_ostream &OS) const { OS << "BeforeCost: " << BeforeCost << "\n"; OS << "AfterCost: " << AfterCost << "\n"; } LLVM_DUMP_METHOD void dump() const; #endif // NDEBUG }; /// The main job of the Region is to point to new instructions generated by /// vectorization passes. It is the unit that RegionPasses operate on with their /// runOnRegion() function. /// /// The region allows us to stack transformations horizontally, meaning that /// each transformation operates on a single region and the resulting region is /// the input to the next transformation, as opposed to vertically, which is the /// common way of applying a transformation across the whole function. This /// enables us to check for profitability and decide whether we accept or /// rollback at a region granularity, which is much better than doing this at /// the function level. /// // Traditional approach: transformations applied vertically for the whole // function // F // +----+ // | | // | | // | | -> Transform1 -> ... -> TransformN -> Check Cost // | | // | | // +----+ // // Region-based approach: transformations applied horizontally, for each Region // F // +----+ // |Rgn1| -> Transform1 -> ... -> TransformN -> Check Cost // | | // |Rgn2| -> Transform1 -> ... -> TransformN -> Check Cost // | | // |Rgn3| -> Transform1 -> ... -> TransformN -> Check Cost // +----+ // // The region can also hold an ordered sequence of "auxiliary" instructions. // This can be used to pass auxiliary information across region passes, like for // example the initial seed slice used by the bottom-up vectorizer. class Region { /// All the instructions in the Region. Only new instructions generated during /// vectorization are part of the Region. SetVector Insts; /// An auxiliary sequence of Instruction-Index pairs. SmallVector Aux; /// MDNode that we'll use to mark instructions as being part of the region. MDNode *RegionMDN; static constexpr const char *MDKind = "sandboxvec"; static constexpr const char *RegionStr = "sandboxregion"; static constexpr const char *AuxMDKind = "sandboxaux"; Context &Ctx; /// Keeps track of cost of instructions added and removed. ScoreBoard Scoreboard; /// ID (for later deregistration) of the "create instruction" callback. Context::CallbackID CreateInstCB; /// ID (for later deregistration) of the "erase instruction" callback. Context::CallbackID EraseInstCB; /// Adds \p I to the set but also don't track the instruction's score if \p /// IgnoreCost is true. Only to be used when adding an instruction to the /// auxiliary vector. /// NOTE: When an instruction is added to the region we track it cost in the /// scoreboard, which currently resides in the region class. However, when we /// add an instruction to the auxiliary vector it does get tagged as being a /// member of the region (for ownership reasons), but its cost does not get /// counted because the instruction hasn't been added in the "normal" way. LLVM_ABI void addImpl(Instruction *I, bool IgnoreCost); /// Adds I to the set. This is the main API for adding an instruction to the /// region. void add(Instruction *I) { addImpl(I, /*IgnoreCost=*/false); } /// Removes I from the set. LLVM_ABI void remove(Instruction *I); friend class Context; // The callbacks need to call add() and remove(). friend class RegionInternalsAttorney; // For unit tests. friend class RegionsFromBBs; // For add(). /// Set \p I as the \p Idx'th element in the auxiliary vector. /// NOTE: This is for internal use, it does not set the metadata. void setAux(unsigned Idx, Instruction *I); /// Helper for dropping Aux metadata for \p I. void dropAuxMetadata(Instruction *I); /// Remove instruction \p I from Aux and drop metadata. void removeFromAux(Instruction *I); public: LLVM_ABI Region(Context &Ctx, TargetTransformInfo &TTI); LLVM_ABI ~Region(); Context &getContext() const { return Ctx; } /// Returns true if I is in the Region. bool contains(Instruction *I) const { return Insts.contains(I); } /// Returns true if the Region has no instructions. bool empty() const { return Insts.empty(); } /// Set the auxiliary vector. LLVM_ABI void setAux(ArrayRef Aux); /// \Returns the auxiliary vector. const SmallVector &getAux() const { return Aux; } /// Clears all auxiliary data. LLVM_ABI void clearAux(); using iterator = decltype(Insts.begin()); iterator begin() { return Insts.begin(); } iterator end() { return Insts.end(); } iterator_range insts() { return make_range(begin(), end()); } LLVM_ABI static SmallVector> createRegionsFromMD(Function &F, TargetTransformInfo &TTI); /// \Returns the ScoreBoard data structure that keeps track of instr costs. const ScoreBoard &getScoreboard() const { return Scoreboard; } #ifndef NDEBUG /// This is an expensive check, meant for testing. LLVM_ABI_FOR_TEST bool operator==(const Region &Other) const; bool operator!=(const Region &other) const { return !(*this == other); } LLVM_ABI_FOR_TEST void dump(raw_ostream &OS) const; void dump() const; friend raw_ostream &operator<<(raw_ostream &OS, const Region &Rgn) { Rgn.dump(OS); return OS; } #endif }; /// A helper client-attorney class for unit tests. class RegionInternalsAttorney { public: static void add(Region &Rgn, Instruction *I) { Rgn.add(I); } static void remove(Region &Rgn, Instruction *I) { Rgn.remove(I); } }; } // namespace llvm::sandboxir #endif // LLVM_SANDBOXIR_REGION_H