//===- AffineAnalysis.h - analyses for affine structures --------*- 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 // //===----------------------------------------------------------------------===// // // This header file defines prototypes for methods that perform analysis // involving affine structures (AffineExprStorage, AffineMap, IntegerSet, etc.) // and other IR structures that in turn use these. // //===----------------------------------------------------------------------===// #ifndef MLIR_DIALECT_AFFINE_ANALYSIS_AFFINEANALYSIS_H #define MLIR_DIALECT_AFFINE_ANALYSIS_AFFINEANALYSIS_H #include "mlir/Analysis/Presburger/IntegerRelation.h" #include "mlir/Dialect/Arith/IR/Arith.h" #include "mlir/IR/Value.h" #include "llvm/ADT/SmallVector.h" #include <optional> namespace mlir { class Operation; namespace affine { class AffineApplyOp; class AffineForOp; class AffineValueMap; class FlatAffineRelation; class FlatAffineValueConstraints; /// A description of a (parallelizable) reduction in an affine loop. struct LoopReduction { … }; /// Populate `supportedReductions` with descriptors of the supported reductions. void getSupportedReductions( AffineForOp forOp, SmallVectorImpl<LoopReduction> &supportedReductions); /// Returns true if `forOp' is a parallel loop. If `parallelReductions` is /// provided, populates it with descriptors of the parallelizable reductions and /// treats them as not preventing parallelization. bool isLoopParallel( AffineForOp forOp, SmallVectorImpl<LoopReduction> *parallelReductions = nullptr); /// Returns true if `forOp' doesn't have memory dependences preventing /// parallelization. Memrefs that are allocated inside `forOp` do not impact its /// dependences and parallelism. This function does not check iter_args (for /// values other than memref types) and should be used only as a building block /// for complete parallelism-checking functions. bool isLoopMemoryParallel(AffineForOp forOp); /// Returns in `affineApplyOps`, the sequence of those AffineApplyOp /// Operations that are reachable via a search starting from `operands` and /// ending at those operands that are not the result of an AffineApplyOp. void getReachableAffineApplyOps(ArrayRef<Value> operands, SmallVectorImpl<Operation *> &affineApplyOps); /// Builds a system of constraints with dimensional variables corresponding to /// the loop IVs of the forOps and AffineIfOp's operands appearing in /// that order. Bounds of the loop are used to add appropriate inequalities. /// Constraints from the index sets of AffineIfOp are also added. Any symbols /// founds in the bound operands are added as symbols in the system. Returns /// failure for the yet unimplemented cases. `ops` accepts both AffineForOp and /// AffineIfOp. // TODO: handle non-unit strides. LogicalResult getIndexSet(MutableArrayRef<Operation *> ops, FlatAffineValueConstraints *domain); /// Encapsulates a memref load or store access information. struct MemRefAccess { … }; // DependenceComponent contains state about the direction of a dependence as an // interval [lb, ub] for an AffineForOp. // Distance vectors components are represented by the interval [lb, ub] with // lb == ub. // Direction vectors components are represented by the interval [lb, ub] with // lb < ub. Note that ub/lb == None means unbounded. struct DependenceComponent { … }; /// Checks whether two accesses to the same memref access the same element. /// Each access is specified using the MemRefAccess structure, which contains /// the operation, indices and memref associated with the access. Returns /// 'NoDependence' if it can be determined conclusively that the accesses do not /// access the same memref element. If 'allowRAR' is true, will consider /// read-after-read dependences (typically used by applications trying to /// optimize input reuse). // TODO: Wrap 'dependenceConstraints' and 'dependenceComponents' into a single // struct. // TODO: Make 'dependenceConstraints' optional arg. struct DependenceResult { … }; DependenceResult checkMemrefAccessDependence( const MemRefAccess &srcAccess, const MemRefAccess &dstAccess, unsigned loopDepth, FlatAffineValueConstraints *dependenceConstraints = nullptr, SmallVector<DependenceComponent, 2> *dependenceComponents = nullptr, bool allowRAR = false); /// Utility function that returns true if the provided DependenceResult /// corresponds to a dependence result. inline bool hasDependence(DependenceResult result) { … } /// Returns true if the provided DependenceResult corresponds to the absence of /// a dependence. inline bool noDependence(DependenceResult result) { … } /// Returns in 'depCompsVec', dependence components for dependences between all /// load and store ops in loop nest rooted at 'forOp', at loop depths in range /// [1, maxLoopDepth]. void getDependenceComponents( AffineForOp forOp, unsigned maxLoopDepth, std::vector<SmallVector<DependenceComponent, 2>> *depCompsVec); } // namespace affine } // namespace mlir #endif // MLIR_DIALECT_AFFINE_ANALYSIS_AFFINEANALYSIS_H