Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:48:21

0001 //===------ ZoneAlgo.h ------------------------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // Derive information about array elements between statements ("Zones").
0010 //
0011 //===----------------------------------------------------------------------===//
0012 
0013 #ifndef POLLY_ZONEALGO_H
0014 #define POLLY_ZONEALGO_H
0015 
0016 #include "llvm/ADT/DenseMap.h"
0017 #include "llvm/ADT/DenseSet.h"
0018 #include "llvm/ADT/SmallPtrSet.h"
0019 #include "isl/isl-noexceptions.h"
0020 #include <memory>
0021 
0022 namespace llvm {
0023 class Value;
0024 class LoopInfo;
0025 class Loop;
0026 class PHINode;
0027 class raw_ostream;
0028 } // namespace llvm
0029 
0030 namespace polly {
0031 class Scop;
0032 class ScopStmt;
0033 class MemoryAccess;
0034 class ScopArrayInfo;
0035 
0036 /// Return only the mappings that map to known values.
0037 ///
0038 /// @param UMap { [] -> ValInst[] }
0039 ///
0040 /// @return { [] -> ValInst[] }
0041 isl::union_map filterKnownValInst(const isl::union_map &UMap);
0042 
0043 /// Base class for algorithms based on zones, like DeLICM.
0044 class ZoneAlgorithm {
0045 protected:
0046   /// The name of the pass this is used from. Used for optimization remarks.
0047   const char *PassName;
0048 
0049   /// Hold a reference to the isl_ctx to avoid it being freed before we released
0050   /// all of the isl objects.
0051   ///
0052   /// This must be declared before any other member that holds an isl object.
0053   /// This guarantees that the shared_ptr and its isl_ctx is destructed last,
0054   /// after all other members free'd the isl objects they were holding.
0055   std::shared_ptr<isl_ctx> IslCtx;
0056 
0057   /// Cached reaching definitions for each ScopStmt.
0058   ///
0059   /// Use getScalarReachingDefinition() to get its contents.
0060   llvm::DenseMap<ScopStmt *, isl::map> ScalarReachDefZone;
0061 
0062   /// The analyzed Scop.
0063   Scop *S;
0064 
0065   /// LoopInfo analysis used to determine whether values are synthesizable.
0066   llvm::LoopInfo *LI;
0067 
0068   /// Parameter space that does not need realignment.
0069   isl::space ParamSpace;
0070 
0071   /// Space the schedule maps to.
0072   isl::space ScatterSpace;
0073 
0074   /// Cached version of the schedule and domains.
0075   isl::union_map Schedule;
0076 
0077   /// Combined access relations of all MemoryKind::Array READ accesses.
0078   /// { DomainRead[] -> Element[] }
0079   isl::union_map AllReads;
0080 
0081   /// The loaded values (llvm::LoadInst) of all reads.
0082   /// { [Element[] -> DomainRead[]] -> ValInst[] }
0083   isl::union_map AllReadValInst;
0084 
0085   /// Combined access relations of all MemoryKind::Array, MAY_WRITE accesses.
0086   /// { DomainMayWrite[] -> Element[] }
0087   isl::union_map AllMayWrites;
0088 
0089   /// Combined access relations of all MemoryKind::Array, MUST_WRITE accesses.
0090   /// { DomainMustWrite[] -> Element[] }
0091   isl::union_map AllMustWrites;
0092 
0093   /// Combined access relations of all MK_Array write accesses (union of
0094   /// AllMayWrites and AllMustWrites).
0095   /// { DomainWrite[] -> Element[] }
0096   isl::union_map AllWrites;
0097 
0098   /// The value instances written to array elements of all write accesses.
0099   /// { [Element[] -> DomainWrite[]] -> ValInst[] }
0100   isl::union_map AllWriteValInst;
0101 
0102   /// All reaching definitions for  MemoryKind::Array writes.
0103   /// { [Element[] -> Zone[]] -> DomainWrite[] }
0104   isl::union_map WriteReachDefZone;
0105 
0106   /// Map llvm::Values to an isl identifier.
0107   /// Used with -polly-use-llvm-names=false as an alternative method to get
0108   /// unique ids that do not depend on pointer values.
0109   llvm::DenseMap<llvm::Value *, isl::id> ValueIds;
0110 
0111   /// Set of array elements that can be reliably used for zone analysis.
0112   /// { Element[] }
0113   isl::union_set CompatibleElts;
0114 
0115   /// List of PHIs that may transitively refer to themselves.
0116   ///
0117   /// Computing them would require a polyhedral transitive closure operation,
0118   /// for which isl may only return an approximation. For correctness, we always
0119   /// require an exact result. Hence, we exclude such PHIs.
0120   llvm::SmallPtrSet<llvm::PHINode *, 4> RecursivePHIs;
0121 
0122   /// PHIs that have been computed.
0123   ///
0124   /// Computed PHIs are replaced by their incoming values using #NormalizeMap.
0125   llvm::DenseSet<llvm::PHINode *> ComputedPHIs;
0126 
0127   /// For computed PHIs, contains the ValInst they stand for.
0128   ///
0129   /// To show an example, assume the following PHINode:
0130   ///
0131   ///   Stmt:
0132   ///     %phi = phi double [%val1, %bb1], [%val2, %bb2]
0133   ///
0134   /// It's ValInst is:
0135   ///
0136   ///   { [Stmt[i] -> phi[]] }
0137   ///
0138   /// The value %phi will be either %val1 or %val2, depending on whether in
0139   /// iteration i %bb1 or %bb2 has been executed before. In SCoPs, this can be
0140   /// determined at compile-time, and the result stored in #NormalizeMap. For
0141   /// the previous example, it could be:
0142   ///
0143   ///   { [Stmt[i] -> phi[]] -> [Stmt[0] -> val1[]];
0144   ///     [Stmt[i] -> phi[]] -> [Stmt[i] -> val2[]] : i > 0 }
0145   ///
0146   /// Only ValInsts in #ComputedPHIs are present in this map. Other values are
0147   /// assumed to represent themselves. This is to avoid adding lots of identity
0148   /// entries to this map.
0149   ///
0150   /// { PHIValInst[] -> IncomingValInst[] }
0151   isl::union_map NormalizeMap;
0152 
0153   /// Cache for computePerPHI(const ScopArrayInfo *)
0154   llvm::SmallDenseMap<llvm::PHINode *, isl::union_map> PerPHIMaps;
0155 
0156   /// A cache for getDefToTarget().
0157   llvm::DenseMap<std::pair<ScopStmt *, ScopStmt *>, isl::map> DefToTargetCache;
0158 
0159   /// Prepare the object before computing the zones of @p S.
0160   ///
0161   /// @param PassName Name of the pass using this analysis.
0162   /// @param S        The SCoP to process.
0163   /// @param LI       LoopInfo analysis used to determine synthesizable values.
0164   ZoneAlgorithm(const char *PassName, Scop *S, llvm::LoopInfo *LI);
0165 
0166 private:
0167   /// Find the array elements that violate the zone analysis assumptions.
0168   ///
0169   /// What violates our assumptions:
0170   /// - A load after a write of the same location; we assume that all reads
0171   ///   occur before the writes.
0172   /// - Two writes to the same location; we cannot model the order in which
0173   ///   these occur.
0174   ///
0175   /// Scalar reads implicitly always occur before other accesses therefore never
0176   /// violate the first condition. There is also at most one write to a scalar,
0177   /// satisfying the second condition.
0178   ///
0179   /// @param Stmt                  The statement to be analyzed.
0180   /// @param[out] IncompatibleElts Receives the elements that are not
0181   ///                              zone-analysis compatible.
0182   /// @param[out]                  AllElts receives all encountered elements.
0183   void collectIncompatibleElts(ScopStmt *Stmt, isl::union_set &IncompatibleElts,
0184                                isl::union_set &AllElts);
0185 
0186   void addArrayReadAccess(MemoryAccess *MA);
0187 
0188   /// Return the ValInst write by a (must-)write access. Returns the 'unknown'
0189   /// ValInst if there is no single ValInst[] the array element written to will
0190   /// have.
0191   ///
0192   /// @return { ValInst[] }
0193   isl::union_map getWrittenValue(MemoryAccess *MA, isl::map AccRel);
0194 
0195   void addArrayWriteAccess(MemoryAccess *MA);
0196 
0197   /// For an llvm::Value defined in @p DefStmt, compute the RAW dependency for a
0198   /// use in every instance of @p UseStmt.
0199   ///
0200   /// @param UseStmt Statement a scalar is used in.
0201   /// @param DefStmt Statement a scalar is defined in.
0202   ///
0203   /// @return { DomainUse[] -> DomainDef[] }
0204   isl::map computeUseToDefFlowDependency(ScopStmt *UseStmt, ScopStmt *DefStmt);
0205 
0206 protected:
0207   isl::union_set makeEmptyUnionSet() const;
0208 
0209   isl::union_map makeEmptyUnionMap() const;
0210 
0211   /// For each 'execution' of a PHINode, get the incoming block that was
0212   /// executed before.
0213   ///
0214   /// For each PHI instance we can directly determine which was the incoming
0215   /// block, and hence derive which value the PHI has.
0216   ///
0217   /// @param SAI The ScopArrayInfo representing the PHI's storage.
0218   ///
0219   /// @return { DomainPHIRead[] -> DomainPHIWrite[] }
0220   isl::union_map computePerPHI(const polly::ScopArrayInfo *SAI);
0221 
0222   /// Find the array elements that can be used for zone analysis.
0223   void collectCompatibleElts();
0224 
0225   /// Get the schedule for @p Stmt.
0226   ///
0227   /// The domain of the result is as narrow as possible.
0228   isl::map getScatterFor(ScopStmt *Stmt) const;
0229 
0230   /// Get the schedule of @p MA's parent statement.
0231   isl::map getScatterFor(MemoryAccess *MA) const;
0232 
0233   /// Get the schedule for the statement instances of @p Domain.
0234   isl::union_map getScatterFor(isl::union_set Domain) const;
0235 
0236   /// Get the schedule for the statement instances of @p Domain.
0237   isl::map getScatterFor(isl::set Domain) const;
0238 
0239   /// Get the domain of @p Stmt.
0240   isl::set getDomainFor(ScopStmt *Stmt) const;
0241 
0242   /// Get the domain @p MA's parent statement.
0243   isl::set getDomainFor(MemoryAccess *MA) const;
0244 
0245   /// Get the access relation of @p MA.
0246   ///
0247   /// The domain of the result is as narrow as possible.
0248   isl::map getAccessRelationFor(MemoryAccess *MA) const;
0249 
0250   /// Get a domain translation map from a (scalar) definition to the statement
0251   /// where the definition is being moved to.
0252   ///
0253   /// @p TargetStmt can also be seen at an llvm::Use of an llvm::Value in
0254   /// @p DefStmt. In addition, we allow transitive uses:
0255   ///
0256   /// DefStmt -> MiddleStmt -> TargetStmt
0257   ///
0258   /// where an operand tree of instructions in DefStmt and MiddleStmt are to be
0259   /// moved to TargetStmt. To be generally correct, we also need to know all the
0260   /// intermediate statements. However, we make use of the fact that
0261   /// ForwardOpTree currently does not support a move from a loop body across
0262   /// its header such that only the first definition and the target statement
0263   /// are relevant.
0264   ///
0265   /// @param DefStmt    Statement from where a definition might be moved from.
0266   /// @param TargetStmt Statement where the definition is potentially being
0267   ///                   moved to (should contain a use of that definition).
0268   ///
0269   /// @return { DomainDef[] -> DomainTarget[] }
0270   isl::map getDefToTarget(ScopStmt *DefStmt, ScopStmt *TargetStmt);
0271 
0272   /// Get the reaching definition of a scalar defined in @p Stmt.
0273   ///
0274   /// Note that this does not depend on the llvm::Instruction, only on the
0275   /// statement it is defined in. Therefore the same computation can be reused.
0276   ///
0277   /// @param Stmt The statement in which a scalar is defined.
0278   ///
0279   /// @return { Scatter[] -> DomainDef[] }
0280   isl::map getScalarReachingDefinition(ScopStmt *Stmt);
0281 
0282   /// Get the reaching definition of a scalar defined in @p DefDomain.
0283   ///
0284   /// @param DomainDef { DomainDef[] }
0285   ///              The write statements to get the reaching definition for.
0286   ///
0287   /// @return { Scatter[] -> DomainDef[] }
0288   isl::map getScalarReachingDefinition(isl::set DomainDef);
0289 
0290   /// Create a statement-to-unknown value mapping.
0291   ///
0292   /// @param Stmt The statement whose instances are mapped to unknown.
0293   ///
0294   /// @return { Domain[] -> ValInst[] }
0295   isl::map makeUnknownForDomain(ScopStmt *Stmt) const;
0296 
0297   /// Create an isl_id that represents @p V.
0298   isl::id makeValueId(llvm::Value *V);
0299 
0300   /// Create the space for an llvm::Value that is available everywhere.
0301   isl::space makeValueSpace(llvm::Value *V);
0302 
0303   /// Create a set with the llvm::Value @p V which is available everywhere.
0304   isl::set makeValueSet(llvm::Value *V);
0305 
0306   /// Create a mapping from a statement instance to the instance of an
0307   /// llvm::Value that can be used in there.
0308   ///
0309   /// Although LLVM IR uses single static assignment, llvm::Values can have
0310   /// different contents in loops, when they get redefined in the last
0311   /// iteration. This function tries to get the statement instance of the
0312   /// previous definition, relative to a user.
0313   ///
0314   /// Example:
0315   /// for (int i = 0; i < N; i += 1) {
0316   /// DEF:
0317   ///    int v = A[i];
0318   /// USE:
0319   ///    use(v);
0320   ///  }
0321   ///
0322   /// The value instance used by statement instance USE[i] is DEF[i]. Hence,
0323   /// makeValInst returns:
0324   ///
0325   /// { USE[i] -> [DEF[i] -> v[]] : 0 <= i < N }
0326   ///
0327   /// @param Val       The value to get the instance of.
0328   /// @param UserStmt  The statement that uses @p Val. Can be nullptr.
0329   /// @param Scope     Loop the using instruction resides in.
0330   /// @param IsCertain Pass true if the definition of @p Val is a
0331   ///                  MUST_WRITE or false if the write is conditional.
0332   ///
0333   /// @return { DomainUse[] -> ValInst[] }
0334   isl::map makeValInst(llvm::Value *Val, ScopStmt *UserStmt, llvm::Loop *Scope,
0335                        bool IsCertain = true);
0336 
0337   /// Create and normalize a ValInst.
0338   ///
0339   /// @see makeValInst
0340   /// @see normalizeValInst
0341   /// @see #NormalizedPHI
0342   isl::union_map makeNormalizedValInst(llvm::Value *Val, ScopStmt *UserStmt,
0343                                        llvm::Loop *Scope,
0344                                        bool IsCertain = true);
0345 
0346   /// Return whether @p MA can be used for transformations (e.g. OpTree load
0347   /// forwarding, DeLICM mapping).
0348   bool isCompatibleAccess(MemoryAccess *MA);
0349 
0350   /// Compute the different zones.
0351   void computeCommon();
0352 
0353   ///  Compute the normalization map that replaces PHIs by their incoming
0354   ///  values.
0355   ///
0356   /// @see #NormalizeMap
0357   void computeNormalizedPHIs();
0358 
0359   /// Print the current state of all MemoryAccesses to @p.
0360   void printAccesses(llvm::raw_ostream &OS, int Indent = 0) const;
0361 
0362   /// Is @p MA a PHI READ access that can be normalized?
0363   ///
0364   /// @see #NormalizeMap
0365   bool isNormalizable(MemoryAccess *MA);
0366 
0367   /// @{
0368   /// Determine whether the argument does not map to any computed PHI. Those
0369   /// should have been replaced by their incoming values.
0370   ///
0371   /// @see #NormalizedPHI
0372   isl::boolean isNormalized(isl::map Map);
0373   isl::boolean isNormalized(isl::union_map Map);
0374   /// @}
0375 
0376 public:
0377   /// Return the SCoP this object is analyzing.
0378   Scop *getScop() const { return S; }
0379 
0380   /// A reaching definition zone is known to have the definition's written value
0381   /// if the definition is a MUST_WRITE.
0382   ///
0383   /// @return { [Element[] -> Zone[]] -> ValInst[] }
0384   isl::union_map computeKnownFromMustWrites() const;
0385 
0386   /// A reaching definition zone is known to be the same value as any load that
0387   /// reads from that array element in that period.
0388   ///
0389   /// @return { [Element[] -> Zone[]] -> ValInst[] }
0390   isl::union_map computeKnownFromLoad() const;
0391 
0392   /// Compute which value an array element stores at every instant.
0393   ///
0394   /// @param FromWrite Use stores as source of information.
0395   /// @param FromRead  Use loads as source of information.
0396   ///
0397   /// @return { [Element[] -> Zone[]] -> ValInst[] }
0398   isl::union_map computeKnown(bool FromWrite, bool FromRead) const;
0399 };
0400 
0401 /// Create a domain-to-unknown value mapping.
0402 ///
0403 /// Value instances that do not represent a specific value are represented by an
0404 /// unnamed tuple of 0 dimensions. Its meaning depends on the context. It can
0405 /// either mean a specific but unknown value which cannot be represented by
0406 /// other means. It conflicts with itself because those two unknown ValInsts may
0407 /// have different concrete values at runtime.
0408 ///
0409 /// The other meaning is an arbitrary or wildcard value that can be chosen
0410 /// freely, like LLVM's undef. If matched with an unknown ValInst, there is no
0411 /// conflict.
0412 ///
0413 /// @param Domain { Domain[] }
0414 ///
0415 /// @return { Domain[] -> ValInst[] }
0416 isl::union_map makeUnknownForDomain(isl::union_set Domain);
0417 } // namespace polly
0418 
0419 #endif /* POLLY_ZONEALGO_H */