xref: /freebsd-src/contrib/llvm-project/clang/lib/CodeGen/CGLoopInfo.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===---- CGLoopInfo.h - LLVM CodeGen for loop metadata -*- C++ -*---------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This is the internal state used for llvm translation for loop statement
100b57cec5SDimitry Andric // metadata.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #ifndef LLVM_CLANG_LIB_CODEGEN_CGLOOPINFO_H
150b57cec5SDimitry Andric #define LLVM_CLANG_LIB_CODEGEN_CGLOOPINFO_H
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
180b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
190b57cec5SDimitry Andric #include "llvm/IR/DebugLoc.h"
200b57cec5SDimitry Andric #include "llvm/IR/Value.h"
210b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric namespace llvm {
240b57cec5SDimitry Andric class BasicBlock;
250b57cec5SDimitry Andric class Instruction;
260b57cec5SDimitry Andric class MDNode;
270b57cec5SDimitry Andric } // end namespace llvm
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric namespace clang {
300b57cec5SDimitry Andric class Attr;
310b57cec5SDimitry Andric class ASTContext;
325ffd83dbSDimitry Andric class CodeGenOptions;
330b57cec5SDimitry Andric namespace CodeGen {
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric /// Attributes that may be specified on loops.
360b57cec5SDimitry Andric struct LoopAttributes {
370b57cec5SDimitry Andric   explicit LoopAttributes(bool IsParallel = false);
380b57cec5SDimitry Andric   void clear();
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric   /// Generate llvm.loop.parallel metadata for loads and stores.
410b57cec5SDimitry Andric   bool IsParallel;
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric   /// State of loop vectorization or unrolling.
440b57cec5SDimitry Andric   enum LVEnableState { Unspecified, Enable, Disable, Full };
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric   /// Value for llvm.loop.vectorize.enable metadata.
470b57cec5SDimitry Andric   LVEnableState VectorizeEnable;
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric   /// Value for llvm.loop.unroll.* metadata (enable, disable, or full).
500b57cec5SDimitry Andric   LVEnableState UnrollEnable;
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   /// Value for llvm.loop.unroll_and_jam.* metadata (enable, disable, or full).
530b57cec5SDimitry Andric   LVEnableState UnrollAndJamEnable;
540b57cec5SDimitry Andric 
55a7dea167SDimitry Andric   /// Value for llvm.loop.vectorize.predicate metadata
56a7dea167SDimitry Andric   LVEnableState VectorizePredicateEnable;
57a7dea167SDimitry Andric 
580b57cec5SDimitry Andric   /// Value for llvm.loop.vectorize.width metadata.
590b57cec5SDimitry Andric   unsigned VectorizeWidth;
600b57cec5SDimitry Andric 
61e8d8bef9SDimitry Andric   // Value for llvm.loop.vectorize.scalable.enable
62e8d8bef9SDimitry Andric   LVEnableState VectorizeScalable;
63e8d8bef9SDimitry Andric 
640b57cec5SDimitry Andric   /// Value for llvm.loop.interleave.count metadata.
650b57cec5SDimitry Andric   unsigned InterleaveCount;
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   /// llvm.unroll.
680b57cec5SDimitry Andric   unsigned UnrollCount;
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric   /// llvm.unroll.
710b57cec5SDimitry Andric   unsigned UnrollAndJamCount;
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   /// Value for llvm.loop.distribute.enable metadata.
740b57cec5SDimitry Andric   LVEnableState DistributeEnable;
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   /// Value for llvm.loop.pipeline.disable metadata.
770b57cec5SDimitry Andric   bool PipelineDisabled;
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric   /// Value for llvm.loop.pipeline.iicount metadata.
800b57cec5SDimitry Andric   unsigned PipelineInitiationInterval;
81e8d8bef9SDimitry Andric 
825f757f3fSDimitry Andric   /// Value for 'llvm.loop.align' metadata.
835f757f3fSDimitry Andric   unsigned CodeAlign;
845f757f3fSDimitry Andric 
85e8d8bef9SDimitry Andric   /// Value for whether the loop is required to make progress.
86e8d8bef9SDimitry Andric   bool MustProgress;
870b57cec5SDimitry Andric };
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric /// Information used when generating a structured loop.
900b57cec5SDimitry Andric class LoopInfo {
910b57cec5SDimitry Andric public:
920b57cec5SDimitry Andric   /// Construct a new LoopInfo for the loop with entry Header.
930b57cec5SDimitry Andric   LoopInfo(llvm::BasicBlock *Header, const LoopAttributes &Attrs,
940b57cec5SDimitry Andric            const llvm::DebugLoc &StartLoc, const llvm::DebugLoc &EndLoc,
950b57cec5SDimitry Andric            LoopInfo *Parent);
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric   /// Get the loop id metadata for this loop.
980b57cec5SDimitry Andric   llvm::MDNode *getLoopID() const { return TempLoopID.get(); }
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric   /// Get the header block of this loop.
1010b57cec5SDimitry Andric   llvm::BasicBlock *getHeader() const { return Header; }
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric   /// Get the set of attributes active for this loop.
1040b57cec5SDimitry Andric   const LoopAttributes &getAttributes() const { return Attrs; }
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric   /// Return this loop's access group or nullptr if it does not have one.
1070b57cec5SDimitry Andric   llvm::MDNode *getAccessGroup() const { return AccGroup; }
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric   /// Create the loop's metadata. Must be called after its nested loops have
1100b57cec5SDimitry Andric   /// been processed.
1110b57cec5SDimitry Andric   void finish();
1120b57cec5SDimitry Andric 
113*0fca6ea1SDimitry Andric   /// Returns the first outer loop containing this loop if any, nullptr
114*0fca6ea1SDimitry Andric   /// otherwise.
115*0fca6ea1SDimitry Andric   const LoopInfo *getParent() const { return Parent; }
116*0fca6ea1SDimitry Andric 
1170b57cec5SDimitry Andric private:
1180b57cec5SDimitry Andric   /// Loop ID metadata.
1190b57cec5SDimitry Andric   llvm::TempMDTuple TempLoopID;
1200b57cec5SDimitry Andric   /// Header block of this loop.
1210b57cec5SDimitry Andric   llvm::BasicBlock *Header;
1220b57cec5SDimitry Andric   /// The attributes for this loop.
1230b57cec5SDimitry Andric   LoopAttributes Attrs;
1240b57cec5SDimitry Andric   /// The access group for memory accesses parallel to this loop.
1250b57cec5SDimitry Andric   llvm::MDNode *AccGroup = nullptr;
1260b57cec5SDimitry Andric   /// Start location of this loop.
1270b57cec5SDimitry Andric   llvm::DebugLoc StartLoc;
1280b57cec5SDimitry Andric   /// End location of this loop.
1290b57cec5SDimitry Andric   llvm::DebugLoc EndLoc;
1300b57cec5SDimitry Andric   /// The next outer loop, or nullptr if this is the outermost loop.
1310b57cec5SDimitry Andric   LoopInfo *Parent;
1320b57cec5SDimitry Andric   /// If this loop has unroll-and-jam metadata, this can be set by the inner
1330b57cec5SDimitry Andric   /// loop's LoopInfo to set the llvm.loop.unroll_and_jam.followup_inner
1340b57cec5SDimitry Andric   /// metadata.
1350b57cec5SDimitry Andric   llvm::MDNode *UnrollAndJamInnerFollowup = nullptr;
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric   /// Create a LoopID without any transformations.
1380b57cec5SDimitry Andric   llvm::MDNode *
1390b57cec5SDimitry Andric   createLoopPropertiesMetadata(llvm::ArrayRef<llvm::Metadata *> LoopProperties);
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   /// Create a LoopID for transformations.
1420b57cec5SDimitry Andric   ///
1430b57cec5SDimitry Andric   /// The methods call each other in case multiple transformations are applied
1440b57cec5SDimitry Andric   /// to a loop. The transformation first to be applied will use LoopID of the
1450b57cec5SDimitry Andric   /// next transformation in its followup attribute.
1460b57cec5SDimitry Andric   ///
1470b57cec5SDimitry Andric   /// @param Attrs             The loop's transformations.
1480b57cec5SDimitry Andric   /// @param LoopProperties    Non-transformation properties such as debug
1490b57cec5SDimitry Andric   ///                          location, parallel accesses and disabled
1500b57cec5SDimitry Andric   ///                          transformations. These are added to the returned
1510b57cec5SDimitry Andric   ///                          LoopID.
1520b57cec5SDimitry Andric   /// @param HasUserTransforms [out] Set to true if the returned MDNode encodes
1530b57cec5SDimitry Andric   ///                          at least one transformation.
1540b57cec5SDimitry Andric   ///
1550b57cec5SDimitry Andric   /// @return A LoopID (metadata node) that can be used for the llvm.loop
1560b57cec5SDimitry Andric   ///         annotation or followup-attribute.
1570b57cec5SDimitry Andric   /// @{
1580b57cec5SDimitry Andric   llvm::MDNode *
1590b57cec5SDimitry Andric   createPipeliningMetadata(const LoopAttributes &Attrs,
1600b57cec5SDimitry Andric                            llvm::ArrayRef<llvm::Metadata *> LoopProperties,
1610b57cec5SDimitry Andric                            bool &HasUserTransforms);
1620b57cec5SDimitry Andric   llvm::MDNode *
1630b57cec5SDimitry Andric   createPartialUnrollMetadata(const LoopAttributes &Attrs,
1640b57cec5SDimitry Andric                               llvm::ArrayRef<llvm::Metadata *> LoopProperties,
1650b57cec5SDimitry Andric                               bool &HasUserTransforms);
1660b57cec5SDimitry Andric   llvm::MDNode *
1670b57cec5SDimitry Andric   createUnrollAndJamMetadata(const LoopAttributes &Attrs,
1680b57cec5SDimitry Andric                              llvm::ArrayRef<llvm::Metadata *> LoopProperties,
1690b57cec5SDimitry Andric                              bool &HasUserTransforms);
1700b57cec5SDimitry Andric   llvm::MDNode *
1710b57cec5SDimitry Andric   createLoopVectorizeMetadata(const LoopAttributes &Attrs,
1720b57cec5SDimitry Andric                               llvm::ArrayRef<llvm::Metadata *> LoopProperties,
1730b57cec5SDimitry Andric                               bool &HasUserTransforms);
1740b57cec5SDimitry Andric   llvm::MDNode *
1750b57cec5SDimitry Andric   createLoopDistributeMetadata(const LoopAttributes &Attrs,
1760b57cec5SDimitry Andric                                llvm::ArrayRef<llvm::Metadata *> LoopProperties,
1770b57cec5SDimitry Andric                                bool &HasUserTransforms);
1780b57cec5SDimitry Andric   llvm::MDNode *
1790b57cec5SDimitry Andric   createFullUnrollMetadata(const LoopAttributes &Attrs,
1800b57cec5SDimitry Andric                            llvm::ArrayRef<llvm::Metadata *> LoopProperties,
1810b57cec5SDimitry Andric                            bool &HasUserTransforms);
1820b57cec5SDimitry Andric   /// @}
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric   /// Create a LoopID for this loop, including transformation-unspecific
1850b57cec5SDimitry Andric   /// metadata such as debug location.
1860b57cec5SDimitry Andric   ///
1870b57cec5SDimitry Andric   /// @param Attrs             This loop's attributes and transformations.
1880b57cec5SDimitry Andric   /// @param LoopProperties    Additional non-transformation properties to add
1890b57cec5SDimitry Andric   ///                          to the LoopID, such as transformation-specific
1900b57cec5SDimitry Andric   ///                          metadata that are not covered by @p Attrs.
1910b57cec5SDimitry Andric   /// @param HasUserTransforms [out] Set to true if the returned MDNode encodes
1920b57cec5SDimitry Andric   ///                          at least one transformation.
1930b57cec5SDimitry Andric   ///
1940b57cec5SDimitry Andric   /// @return A LoopID (metadata node) that can be used for the llvm.loop
1950b57cec5SDimitry Andric   ///         annotation.
1960b57cec5SDimitry Andric   llvm::MDNode *createMetadata(const LoopAttributes &Attrs,
1970b57cec5SDimitry Andric                                llvm::ArrayRef<llvm::Metadata *> LoopProperties,
1980b57cec5SDimitry Andric                                bool &HasUserTransforms);
1990b57cec5SDimitry Andric };
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric /// A stack of loop information corresponding to loop nesting levels.
2020b57cec5SDimitry Andric /// This stack can be used to prepare attributes which are applied when a loop
2030b57cec5SDimitry Andric /// is emitted.
2040b57cec5SDimitry Andric class LoopInfoStack {
2050b57cec5SDimitry Andric   LoopInfoStack(const LoopInfoStack &) = delete;
2060b57cec5SDimitry Andric   void operator=(const LoopInfoStack &) = delete;
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric public:
2090b57cec5SDimitry Andric   LoopInfoStack() {}
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric   /// Begin a new structured loop. The set of staged attributes will be
2120b57cec5SDimitry Andric   /// applied to the loop and then cleared.
2130b57cec5SDimitry Andric   void push(llvm::BasicBlock *Header, const llvm::DebugLoc &StartLoc,
2140b57cec5SDimitry Andric             const llvm::DebugLoc &EndLoc);
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric   /// Begin a new structured loop. Stage attributes from the Attrs list.
2170b57cec5SDimitry Andric   /// The staged attributes are applied to the loop and then cleared.
2180b57cec5SDimitry Andric   void push(llvm::BasicBlock *Header, clang::ASTContext &Ctx,
2195ffd83dbSDimitry Andric             const clang::CodeGenOptions &CGOpts,
2200b57cec5SDimitry Andric             llvm::ArrayRef<const Attr *> Attrs, const llvm::DebugLoc &StartLoc,
221e8d8bef9SDimitry Andric             const llvm::DebugLoc &EndLoc, bool MustProgress = false);
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric   /// End the current loop.
2240b57cec5SDimitry Andric   void pop();
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric   /// Return the top loop id metadata.
2270b57cec5SDimitry Andric   llvm::MDNode *getCurLoopID() const { return getInfo().getLoopID(); }
2280b57cec5SDimitry Andric 
2290b57cec5SDimitry Andric   /// Return true if the top loop is parallel.
2300b57cec5SDimitry Andric   bool getCurLoopParallel() const {
2310b57cec5SDimitry Andric     return hasInfo() ? getInfo().getAttributes().IsParallel : false;
2320b57cec5SDimitry Andric   }
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric   /// Function called by the CodeGenFunction when an instruction is
2350b57cec5SDimitry Andric   /// created.
2360b57cec5SDimitry Andric   void InsertHelper(llvm::Instruction *I) const;
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   /// Set the next pushed loop as parallel.
2390b57cec5SDimitry Andric   void setParallel(bool Enable = true) { StagedAttrs.IsParallel = Enable; }
2400b57cec5SDimitry Andric 
2410b57cec5SDimitry Andric   /// Set the next pushed loop 'vectorize.enable'
2420b57cec5SDimitry Andric   void setVectorizeEnable(bool Enable = true) {
2430b57cec5SDimitry Andric     StagedAttrs.VectorizeEnable =
2440b57cec5SDimitry Andric         Enable ? LoopAttributes::Enable : LoopAttributes::Disable;
2450b57cec5SDimitry Andric   }
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric   /// Set the next pushed loop as a distribution candidate.
2480b57cec5SDimitry Andric   void setDistributeState(bool Enable = true) {
2490b57cec5SDimitry Andric     StagedAttrs.DistributeEnable =
2500b57cec5SDimitry Andric         Enable ? LoopAttributes::Enable : LoopAttributes::Disable;
2510b57cec5SDimitry Andric   }
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric   /// Set the next pushed loop unroll state.
2540b57cec5SDimitry Andric   void setUnrollState(const LoopAttributes::LVEnableState &State) {
2550b57cec5SDimitry Andric     StagedAttrs.UnrollEnable = State;
2560b57cec5SDimitry Andric   }
2570b57cec5SDimitry Andric 
258a7dea167SDimitry Andric   /// Set the next pushed vectorize predicate state.
259a7dea167SDimitry Andric   void setVectorizePredicateState(const LoopAttributes::LVEnableState &State) {
260a7dea167SDimitry Andric     StagedAttrs.VectorizePredicateEnable = State;
261a7dea167SDimitry Andric   }
262a7dea167SDimitry Andric 
2630b57cec5SDimitry Andric   /// Set the next pushed loop unroll_and_jam state.
2640b57cec5SDimitry Andric   void setUnrollAndJamState(const LoopAttributes::LVEnableState &State) {
2650b57cec5SDimitry Andric     StagedAttrs.UnrollAndJamEnable = State;
2660b57cec5SDimitry Andric   }
2670b57cec5SDimitry Andric 
2680b57cec5SDimitry Andric   /// Set the vectorize width for the next loop pushed.
2690b57cec5SDimitry Andric   void setVectorizeWidth(unsigned W) { StagedAttrs.VectorizeWidth = W; }
2700b57cec5SDimitry Andric 
271e8d8bef9SDimitry Andric   void setVectorizeScalable(const LoopAttributes::LVEnableState &State) {
272e8d8bef9SDimitry Andric     StagedAttrs.VectorizeScalable = State;
273e8d8bef9SDimitry Andric   }
274e8d8bef9SDimitry Andric 
2750b57cec5SDimitry Andric   /// Set the interleave count for the next loop pushed.
2760b57cec5SDimitry Andric   void setInterleaveCount(unsigned C) { StagedAttrs.InterleaveCount = C; }
2770b57cec5SDimitry Andric 
2780b57cec5SDimitry Andric   /// Set the unroll count for the next loop pushed.
2790b57cec5SDimitry Andric   void setUnrollCount(unsigned C) { StagedAttrs.UnrollCount = C; }
2800b57cec5SDimitry Andric 
2810b57cec5SDimitry Andric   /// \brief Set the unroll count for the next loop pushed.
2820b57cec5SDimitry Andric   void setUnrollAndJamCount(unsigned C) { StagedAttrs.UnrollAndJamCount = C; }
2830b57cec5SDimitry Andric 
2840b57cec5SDimitry Andric   /// Set the pipeline disabled state.
2850b57cec5SDimitry Andric   void setPipelineDisabled(bool S) { StagedAttrs.PipelineDisabled = S; }
2860b57cec5SDimitry Andric 
2870b57cec5SDimitry Andric   /// Set the pipeline initiation interval.
2880b57cec5SDimitry Andric   void setPipelineInitiationInterval(unsigned C) {
2890b57cec5SDimitry Andric     StagedAttrs.PipelineInitiationInterval = C;
2900b57cec5SDimitry Andric   }
2910b57cec5SDimitry Andric 
2925f757f3fSDimitry Andric   /// Set value of code align for the next loop pushed.
2935f757f3fSDimitry Andric   void setCodeAlign(unsigned C) { StagedAttrs.CodeAlign = C; }
2945f757f3fSDimitry Andric 
295e8d8bef9SDimitry Andric   /// Set no progress for the next loop pushed.
296e8d8bef9SDimitry Andric   void setMustProgress(bool P) { StagedAttrs.MustProgress = P; }
297e8d8bef9SDimitry Andric 
2980b57cec5SDimitry Andric   /// Returns true if there is LoopInfo on the stack.
2990b57cec5SDimitry Andric   bool hasInfo() const { return !Active.empty(); }
3000b57cec5SDimitry Andric   /// Return the LoopInfo for the current loop. HasInfo should be called
3010b57cec5SDimitry Andric   /// first to ensure LoopInfo is present.
302a7dea167SDimitry Andric   const LoopInfo &getInfo() const { return *Active.back(); }
303*0fca6ea1SDimitry Andric 
304*0fca6ea1SDimitry Andric private:
3050b57cec5SDimitry Andric   /// The set of attributes that will be applied to the next pushed loop.
3060b57cec5SDimitry Andric   LoopAttributes StagedAttrs;
3070b57cec5SDimitry Andric   /// Stack of active loops.
308a7dea167SDimitry Andric   llvm::SmallVector<std::unique_ptr<LoopInfo>, 4> Active;
3090b57cec5SDimitry Andric };
3100b57cec5SDimitry Andric 
3110b57cec5SDimitry Andric } // end namespace CodeGen
3120b57cec5SDimitry Andric } // end namespace clang
3130b57cec5SDimitry Andric 
3140b57cec5SDimitry Andric #endif
315