[polly] r302636 - [Polly] Canonicalize arrays according to base-ptr equivalence class

Tobias Grosser via llvm-commits llvm-commits at lists.llvm.org
Tue May 30 09:38:06 PDT 2017


We do not use setNewAccess relation any more, right? I dropped this on
your request. 

Best,
Tobias

On Tue, May 30, 2017, at 02:26 PM, Michael Kruse via llvm-commits wrote:
> Just a though why I had concerns using setNewAccessRelation for this
> purpose.
> 
> setNewAccessRelation will trigger code-generation of the index
> expression. This is not possible if the index expression is affine.
> That is, this patch effectively breaks load-hoisting of base pointers
> that have one or more non-affine access.
> 
> Michael
> 
> 
> 2017-05-10 12:59 GMT+02:00 Tobias Grosser via llvm-commits
> <llvm-commits at lists.llvm.org>:
> > Author: grosser
> > Date: Wed May 10 05:59:58 2017
> > New Revision: 302636
> >
> > URL: http://llvm.org/viewvc/llvm-project?rev=302636&view=rev
> > Log:
> > [Polly] Canonicalize arrays according to base-ptr equivalence class
> >
> > Summary:
> >     In case two arrays share base pointers in the same invariant load equivalence
> >     class, we canonicalize all memory accesses to the first of these arrays
> >     (according to their order in the equivalence class).
> >
> >     This enables us to optimize kernels such as boost::ublas by ensuring that
> >     different references to the C array are interpreted as accesses to the same
> >     array. Before this change the runtime alias check for ublas would fail, as it
> >     would assume models of the C array with differing (but identically valued) base
> >     pointers would reference distinct regions of memory whereas the referenced
> >     memory regions were indeed identical.
> >
> >     As part of this change we remove most of the MemoryAccess::get*BaseAddr
> >     interface. We removed already all references to get*BaseAddr in previous
> >     commits to ensure that no code relies on matching base pointers between
> >     memory accesses and scop arrays -- except for three remaining uses where we
> >     need the original base pointer. We document for these situations that
> >     MemoryAccess::getOriginalBaseAddr may return a base pointer that is distinct
> >     to the base pointer of the scop array referenced by this memory access.
> >
> > Reviewers: sebpop, Meinersbur, zinob, gareevroman, pollydev, huihuiz, efriedma, jdoerfert
> >
> > Reviewed By: Meinersbur
> >
> > Subscribers: etherzhhb
> >
> > Tags: #polly
> >
> > Differential Revision: https://reviews.llvm.org/D28518
> >
> > Added:
> >     polly/trunk/test/Isl/CodeGen/invariant_load_canonicalize_array_baseptrs.ll
> >     polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs.ll
> >     polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_2.ll
> >     polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_3.ll
> >     polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4.ll
> >     polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4b.ll
> >     polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4c.ll
> >     polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_5.ll
> > Modified:
> >     polly/trunk/include/polly/ScopInfo.h
> >     polly/trunk/lib/Analysis/ScopBuilder.cpp
> >     polly/trunk/lib/Analysis/ScopInfo.cpp
> >     polly/trunk/lib/CodeGen/IslNodeBuilder.cpp
> >     polly/trunk/lib/Transform/ScheduleOptimizer.cpp
> >
> > Modified: polly/trunk/include/polly/ScopInfo.h
> > URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/ScopInfo.h?rev=302636&r1=302635&r2=302636&view=diff
> > ==============================================================================
> > --- polly/trunk/include/polly/ScopInfo.h (original)
> > +++ polly/trunk/include/polly/ScopInfo.h Wed May 10 05:59:58 2017
> > @@ -367,6 +367,16 @@ public:
> >    /// If the array is read only
> >    bool isReadOnly();
> >
> > +  /// Verify that @p Array is compatible to this ScopArrayInfo.
> > +  ///
> > +  /// Two arrays are compatible if their dimensionality, the sizes of their
> > +  /// dimensions, and their element sizes match.
> > +  ///
> > +  /// @param Array The array to compare against.
> > +  ///
> > +  /// @returns True, if the arrays are compatible, False otherwise.
> > +  bool isCompatibleWith(const ScopArrayInfo *Array) const;
> > +
> >  private:
> >    void addDerivedSAI(ScopArrayInfo *DerivedSAI) {
> >      DerivedSAIs.insert(DerivedSAI);
> > @@ -804,22 +814,14 @@ public:
> >    /// Get an isl string representing a new access function, if available.
> >    std::string getNewAccessRelationStr() const;
> >
> > -  /// Get the base address of this access (e.g. A for A[i+j]) when
> > +  /// Get the original base address of this access (e.g. A for A[i+j]) when
> >    /// detected.
> > -  Value *getOriginalBaseAddr() const {
> > -    assert(!getOriginalScopArrayInfo() /* may noy yet be initialized */ ||
> > -           getOriginalScopArrayInfo()->getBasePtr() == BaseAddr);
> > -    return BaseAddr;
> > -  }
> > -
> > -  /// Get the base address of this access (e.g. A for A[i+j]) after a
> > -  /// potential change by setNewAccessRelation().
> > -  Value *getLatestBaseAddr() const {
> > -    return getLatestScopArrayInfo()->getBasePtr();
> > -  }
> > -
> > -  /// Old name for getOriginalBaseAddr().
> > -  Value *getBaseAddr() const { return getOriginalBaseAddr(); }
> > +  ///
> > +  /// This adress may differ from the base address referenced by the Original
> > +  /// ScopArrayInfo to which this array belongs, as this memory access may
> > +  /// have been unified to a ScopArray which has a different but identically
> > +  /// valued base pointer in case invariant load hoisting is enabled.
> > +  Value *getOriginalBaseAddr() const { return BaseAddr; }
> >
> >    /// Get the detection-time base array isl_id for this access.
> >    __isl_give isl_id *getOriginalArrayId() const;
> > @@ -1890,6 +1892,34 @@ private:
> >    ///
> >    void hoistInvariantLoads();
> >
> > +  /// Canonicalize arrays with base pointers from the same equivalence class.
> > +  ///
> > +  /// Some context: in our normal model we assume that each base pointer is
> > +  /// related to a single specific memory region, where memory regions
> > +  /// associated with different base pointers are disjoint. Consequently we do
> > +  /// not need to compute additional data dependences that model possible
> > +  /// overlaps of these memory regions. To verify our assumption we compute
> > +  /// alias checks that verify that modeled arrays indeed do not overlap. In
> > +  /// case an overlap is detected the runtime check fails and we fall back to
> > +  /// the original code.
> > +  ///
> > +  /// In case of arrays where the base pointers are know to be identical,
> > +  /// because they are dynamically loaded by accesses that are in the same
> > +  /// invariant load equivalence class, such run-time alias check would always
> > +  /// be false.
> > +  ///
> > +  /// This function makes sure that we do not generate consistently failing
> > +  /// run-time checks for code that contains distinct arrays with known
> > +  /// equivalent base pointers. It identifies for each invariant load
> > +  /// equivalence class a single canonical array and canonicalizes all memory
> > +  /// accesses that reference arrays that have base pointers that are known to
> > +  /// be equal to the base pointer of such a canonical array to this canonical
> > +  /// array.
> > +  ///
> > +  /// We currently do not canonicalize arrays for which certain memory accesses
> > +  /// have been hoisted as loop invariant.
> > +  void canonicalizeDynamicBasePtrs();
> > +
> >    /// Add invariant loads listed in @p InvMAs with the domain of @p Stmt.
> >    void addInvariantLoads(ScopStmt &Stmt, InvariantAccessesTy &InvMAs);
> >
> > @@ -2483,6 +2513,18 @@ public:
> >    ///
> >    /// @param BasePtr   The base pointer the object has been stored for.
> >    /// @param Kind      The kind of array info object.
> > +  ///
> > +  /// @returns The ScopArrayInfo pointer or NULL if no such pointer is
> > +  ///          available.
> > +  const ScopArrayInfo *getScopArrayInfoOrNull(Value *BasePtr, MemoryKind Kind);
> > +
> > +  /// Return the cached ScopArrayInfo object for @p BasePtr.
> > +  ///
> > +  /// @param BasePtr   The base pointer the object has been stored for.
> > +  /// @param Kind      The kind of array info object.
> > +  ///
> > +  /// @returns The ScopArrayInfo pointer (may assert if no such pointer is
> > +  ///          available).
> >    const ScopArrayInfo *getScopArrayInfo(Value *BasePtr, MemoryKind Kind);
> >
> >    /// Invalidate ScopArrayInfo object for base address.
> >
> > Modified: polly/trunk/lib/Analysis/ScopBuilder.cpp
> > URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Analysis/ScopBuilder.cpp?rev=302636&r1=302635&r2=302636&view=diff
> > ==============================================================================
> > --- polly/trunk/lib/Analysis/ScopBuilder.cpp (original)
> > +++ polly/trunk/lib/Analysis/ScopBuilder.cpp Wed May 10 05:59:58 2017
> > @@ -776,6 +776,7 @@ void ScopBuilder::buildScop(Region &R, A
> >      return;
> >
> >    scop->hoistInvariantLoads();
> > +  scop->canonicalizeDynamicBasePtrs();
> >    scop->verifyInvariantLoads();
> >    scop->simplifySCoP(true);
> >
> >
> > Modified: polly/trunk/lib/Analysis/ScopInfo.cpp
> > URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Analysis/ScopInfo.cpp?rev=302636&r1=302635&r2=302636&view=diff
> > ==============================================================================
> > --- polly/trunk/lib/Analysis/ScopInfo.cpp (original)
> > +++ polly/trunk/lib/Analysis/ScopInfo.cpp Wed May 10 05:59:58 2017
> > @@ -279,6 +279,20 @@ bool ScopArrayInfo::isReadOnly() {
> >    return IsReadOnly;
> >  }
> >
> > +bool ScopArrayInfo::isCompatibleWith(const ScopArrayInfo *Array) const {
> > +  if (Array->getElementType() != getElementType())
> > +    return false;
> > +
> > +  if (Array->getNumberOfDimensions() != getNumberOfDimensions())
> > +    return false;
> > +
> > +  for (unsigned i = 0; i < getNumberOfDimensions(); i++)
> > +    if (Array->getDimensionSize(i) != getDimensionSize(i))
> > +      return false;
> > +
> > +  return true;
> > +}
> > +
> >  void ScopArrayInfo::updateElementType(Type *NewElementType) {
> >    if (NewElementType == ElementType)
> >      return;
> > @@ -3765,6 +3779,76 @@ void Scop::hoistInvariantLoads() {
> >    isl_union_map_free(Writes);
> >  }
> >
> > +/// Find the canonical scop array info object for a set of invariant load
> > +/// hoisted loads. The canonical array is the one that corresponds to the
> > +/// first load in the list of accesses which is used as base pointer of a
> > +/// scop array.
> > +static const ScopArrayInfo *findCanonicalArray(Scop *S,
> > +                                               MemoryAccessList &Accesses) {
> > +  for (MemoryAccess *Access : Accesses) {
> > +    const ScopArrayInfo *CanonicalArray = S->getScopArrayInfoOrNull(
> > +        Access->getAccessInstruction(), MemoryKind::Array);
> > +    if (CanonicalArray)
> > +      return CanonicalArray;
> > +  }
> > +  return nullptr;
> > +}
> > +
> > +/// Check if @p Array severs as base array in an invariant load.
> > +static bool isUsedForIndirectHoistedLoad(Scop *S, const ScopArrayInfo *Array) {
> > +  for (InvariantEquivClassTy &EqClass2 : S->getInvariantAccesses())
> > +    for (MemoryAccess *Access2 : EqClass2.InvariantAccesses)
> > +      if (Access2->getScopArrayInfo() == Array)
> > +        return true;
> > +  return false;
> > +}
> > +
> > +/// Replace the base pointer arrays in all memory accesses referencing @p Old,
> > +/// with a reference to @p New.
> > +static void replaceBasePtrArrays(Scop *S, const ScopArrayInfo *Old,
> > +                                 const ScopArrayInfo *New) {
> > +  for (ScopStmt &Stmt : *S)
> > +    for (MemoryAccess *Access : Stmt) {
> > +      if (Access->getLatestScopArrayInfo() != Old)
> > +        continue;
> > +
> > +      isl_id *Id = New->getBasePtrId();
> > +      isl_map *Map = Access->getAccessRelation();
> > +      Map = isl_map_set_tuple_id(Map, isl_dim_out, Id);
> > +      Access->setAccessRelation(Map);
> > +    }
> > +}
> > +
> > +void Scop::canonicalizeDynamicBasePtrs() {
> > +  for (InvariantEquivClassTy &EqClass : InvariantEquivClasses) {
> > +    MemoryAccessList &BasePtrAccesses = EqClass.InvariantAccesses;
> > +
> > +    const ScopArrayInfo *CanonicalBasePtrSAI =
> > +        findCanonicalArray(this, BasePtrAccesses);
> > +
> > +    if (!CanonicalBasePtrSAI)
> > +      continue;
> > +
> > +    for (MemoryAccess *BasePtrAccess : BasePtrAccesses) {
> > +      const ScopArrayInfo *BasePtrSAI = getScopArrayInfoOrNull(
> > +          BasePtrAccess->getAccessInstruction(), MemoryKind::Array);
> > +      if (!BasePtrSAI || BasePtrSAI == CanonicalBasePtrSAI ||
> > +          !BasePtrSAI->isCompatibleWith(CanonicalBasePtrSAI))
> > +        continue;
> > +
> > +      // we currently do not canonicalize arrays where some accesses are
> > +      // hoisted as invariant loads. If we would, we need to update the access
> > +      // function of the invariant loads as well. However, as this is not a
> > +      // very common situation, we leave this for now to avoid further
> > +      // complexity increases.
> > +      if (isUsedForIndirectHoistedLoad(this, BasePtrSAI))
> > +        continue;
> > +
> > +      replaceBasePtrArrays(this, BasePtrSAI, CanonicalBasePtrSAI);
> > +    }
> > +  }
> > +}
> > +
> >  const ScopArrayInfo *
> >  Scop::getOrCreateScopArrayInfo(Value *BasePtr, Type *ElementType,
> >                                 ArrayRef<const SCEV *> Sizes, MemoryKind Kind,
> > @@ -3806,8 +3890,14 @@ Scop::createScopArrayInfo(Type *ElementT
> >    return SAI;
> >  }
> >
> > -const ScopArrayInfo *Scop::getScopArrayInfo(Value *BasePtr, MemoryKind Kind) {
> > +const ScopArrayInfo *Scop::getScopArrayInfoOrNull(Value *BasePtr,
> > +                                                  MemoryKind Kind) {
> >    auto *SAI = ScopArrayInfoMap[std::make_pair(BasePtr, Kind)].get();
> > +  return SAI;
> > +}
> > +
> > +const ScopArrayInfo *Scop::getScopArrayInfo(Value *BasePtr, MemoryKind Kind) {
> > +  auto *SAI = getScopArrayInfoOrNull(BasePtr, Kind);
> >    assert(SAI && "No ScopArrayInfo available for this base pointer");
> >    return SAI;
> >  }
> >
> > Modified: polly/trunk/lib/CodeGen/IslNodeBuilder.cpp
> > URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/CodeGen/IslNodeBuilder.cpp?rev=302636&r1=302635&r2=302636&view=diff
> > ==============================================================================
> > --- polly/trunk/lib/CodeGen/IslNodeBuilder.cpp (original)
> > +++ polly/trunk/lib/CodeGen/IslNodeBuilder.cpp Wed May 10 05:59:58 2017
> > @@ -1229,7 +1229,7 @@ bool IslNodeBuilder::preloadInvariantEqu
> >        // current SAI could be the base pointer of the derived SAI, however we
> >        // should only change the base pointer of the derived SAI if we actually
> >        // preloaded it.
> > -      if (BasePtr == MA->getBaseAddr()) {
> > +      if (BasePtr == MA->getOriginalBaseAddr()) {
> >          assert(BasePtr->getType() == PreloadVal->getType());
> >          DerivedSAI->setBasePtr(PreloadVal);
> >        }
> >
> > Modified: polly/trunk/lib/Transform/ScheduleOptimizer.cpp
> > URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Transform/ScheduleOptimizer.cpp?rev=302636&r1=302635&r2=302636&view=diff
> > ==============================================================================
> > --- polly/trunk/lib/Transform/ScheduleOptimizer.cpp (original)
> > +++ polly/trunk/lib/Transform/ScheduleOptimizer.cpp Wed May 10 05:59:58 2017
> > @@ -1304,7 +1304,8 @@ __isl_give isl_schedule_node *ScheduleTr
> >      __isl_take isl_schedule_node *Node, const llvm::TargetTransformInfo *TTI,
> >      MatMulInfoTy &MMI) {
> >    assert(TTI && "The target transform info should be provided.");
> > -  Node = markInterIterationAliasFree(Node, MMI.WriteToC->getLatestBaseAddr());
> > +  Node = markInterIterationAliasFree(
> > +      Node, MMI.WriteToC->getLatestScopArrayInfo()->getBasePtr());
> >    int DimOutNum = isl_schedule_node_band_n_member(Node);
> >    assert(DimOutNum > 2 && "In case of the matrix multiplication the loop nest "
> >                            "and, consequently, the corresponding scheduling "
> >
> > Added: polly/trunk/test/Isl/CodeGen/invariant_load_canonicalize_array_baseptrs.ll
> > URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/Isl/CodeGen/invariant_load_canonicalize_array_baseptrs.ll?rev=302636&view=auto
> > ==============================================================================
> > --- polly/trunk/test/Isl/CodeGen/invariant_load_canonicalize_array_baseptrs.ll (added)
> > +++ polly/trunk/test/Isl/CodeGen/invariant_load_canonicalize_array_baseptrs.ll Wed May 10 05:59:58 2017
> > @@ -0,0 +1,36 @@
> > +; RUN: opt %loadPolly -polly-codegen -S < %s \
> > +; RUN:  -polly-invariant-load-hoisting \
> > +; RUN:  | FileCheck %s
> > +
> > +; CHECK: %polly.access.A = getelementptr float*, float** %A, i64 0
> > +; CHECK: %polly.access.A.load = load float*, float** %polly.access.A
> > +; CHECK: store float 4.200000e+01, float* %polly.access.A.load
> > +; CHECK: store float 4.800000e+01, float* %polly.access.A.load
> > +
> > +define void @foo(float** %A) {
> > +start:
> > +  br label %loop
> > +
> > +loop:
> > +  %indvar = phi i64 [0, %start], [%indvar.next, %latch]
> > +  %indvar.next = add nsw i64 %indvar, 1
> > +  %icmp = icmp slt i64 %indvar.next, 1024
> > +  br i1 %icmp, label %body1, label %exit
> > +
> > +body1:
> > +  %baseA = load float*, float** %A
> > +  store float 42.0, float* %baseA
> > +  br label %body2
> > +
> > +body2:
> > +  %baseB = load float*, float** %A
> > +  store float 48.0, float* %baseB
> > +  br label %latch
> > +
> > +latch:
> > +  br label %loop
> > +
> > +exit:
> > +  ret void
> > +
> > +}
> >
> > Added: polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs.ll
> > URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs.ll?rev=302636&view=auto
> > ==============================================================================
> > --- polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs.ll (added)
> > +++ polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs.ll Wed May 10 05:59:58 2017
> > @@ -0,0 +1,46 @@
> > +; RUN: opt %loadPolly -polly-scops -analyze < %s \
> > +; RUN:  -polly-invariant-load-hoisting \
> > +; RUN:  | FileCheck %s
> > +
> > +; CHECK:      Stmt_body1
> > +; CHECK-NEXT:       Domain :=
> > +; CHECK-NEXT:           { Stmt_body1[i0] : 0 <= i0 <= 1022 };
> > +; CHECK-NEXT:       Schedule :=
> > +; CHECK-NEXT:           { Stmt_body1[i0] -> [i0, 0] };
> > +; CHECK-NEXT:       MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
> > +; CHECK-NEXT:          { Stmt_body1[i0] -> MemRef_baseB[0] };
> > +; CHECK-NEXT: Stmt_body2
> > +; CHECK-NEXT:       Domain :=
> > +; CHECK-NEXT:           { Stmt_body2[i0] : 0 <= i0 <= 1022 };
> > +; CHECK-NEXT:       Schedule :=
> > +; CHECK-NEXT:           { Stmt_body2[i0] -> [i0, 1] };
> > +; CHECK-NEXT:       MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
> > +; CHECK-NEXT:                { Stmt_body2[i0] -> MemRef_baseB[0] };
> > +
> > +define void @foo(float** %A) {
> > +start:
> > +  br label %loop
> > +
> > +loop:
> > +  %indvar = phi i64 [0, %start], [%indvar.next, %latch]
> > +  %indvar.next = add nsw i64 %indvar, 1
> > +  %icmp = icmp slt i64 %indvar.next, 1024
> > +  br i1 %icmp, label %body1, label %exit
> > +
> > +body1:
> > +  %baseA = load float*, float** %A
> > +  store float 42.0, float* %baseA
> > +  br label %body2
> > +
> > +body2:
> > +  %baseB = load float*, float** %A
> > +  store float 42.0, float* %baseB
> > +  br label %latch
> > +
> > +latch:
> > +  br label %loop
> > +
> > +exit:
> > +  ret void
> > +
> > +}
> >
> > Added: polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_2.ll
> > URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_2.ll?rev=302636&view=auto
> > ==============================================================================
> > --- polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_2.ll (added)
> > +++ polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_2.ll Wed May 10 05:59:58 2017
> > @@ -0,0 +1,91 @@
> > +; RUN: opt %loadPolly -polly-scops -analyze < %s \
> > +; RUN:  -polly-invariant-load-hoisting \
> > +; RUN:  | FileCheck %s
> > +
> > +; Make sure we choose a canonical element that is not the first invariant load,
> > +; but the first that is an array base pointer.
> > +
> > +; CHECK:     Statements {
> > +; CHECK-NEXT:          Stmt_body0
> > +; CHECK-NEXT:             Domain :=
> > +; CHECK-NEXT:                 { Stmt_body0[i0] : 0 <= i0 <= 1022 };
> > +; CHECK-NEXT:             Schedule :=
> > +; CHECK-NEXT:                 { Stmt_body0[i0] -> [i0, 0] };
> > +; CHECK-NEXT:             MustWriteAccess :=   [Reduction Type: NONE] [Scalar: 0]
> > +; CHECK-NEXT:                 { Stmt_body0[i0] -> MemRef_X[0] };
> > +; CHECK-NEXT:          Stmt_body1
> > +; CHECK-NEXT:             Domain :=
> > +; CHECK-NEXT:                 { Stmt_body1[i0] : 0 <= i0 <= 1022 };
> > +; CHECK-NEXT:             Schedule :=
> > +; CHECK-NEXT:                 { Stmt_body1[i0] -> [i0, 1] };
> > +; CHECK-NEXT:             MustWriteAccess :=   [Reduction Type: NONE] [Scalar: 0]
> > +; CHECK-NEXT:                 { Stmt_body1[i0] -> MemRef_baseB[0] };
> > +; CHECK-NEXT:          Stmt_body2
> > +; CHECK-NEXT:             Domain :=
> > +; CHECK-NEXT:                 { Stmt_body2[i0] : 0 <= i0 <= 1022 };
> > +; CHECK-NEXT:             Schedule :=
> > +; CHECK-NEXT:                 { Stmt_body2[i0] -> [i0, 2] };
> > +; CHECK-NEXT:             MustWriteAccess :=   [Reduction Type: NONE] [Scalar: 0]
> > +; CHECK-NEXT:                 { Stmt_body2[i0] -> MemRef_X[0] };
> > +; CHECK-NEXT:             ReadAccess :=        [Reduction Type: NONE] [Scalar: 1]
> > +; CHECK-NEXT:                 { Stmt_body2[i0] -> MemRef_ptr[] };
> > +; CHECK-NEXT:          Stmt_body3
> > +; CHECK-NEXT:             Domain :=
> > +; CHECK-NEXT:                 { Stmt_body3[i0] : 0 <= i0 <= 1022 };
> > +; CHECK-NEXT:             Schedule :=
> > +; CHECK-NEXT:                 { Stmt_body3[i0] -> [i0, 3] };
> > +; CHECK-NEXT:             MustWriteAccess :=   [Reduction Type: NONE] [Scalar: 0]
> > +; CHECK-NEXT:                 { Stmt_body3[i0] -> MemRef_baseB[0] };
> > +; CHECK-NEXT:          Stmt_body4
> > +; CHECK-NEXT:             Domain :=
> > +; CHECK-NEXT:                 { Stmt_body4[i0] : 0 <= i0 <= 1022 };
> > +; CHECK-NEXT:             Schedule :=
> > +; CHECK-NEXT:                 { Stmt_body4[i0] -> [i0, 4] };
> > +; CHECK-NEXT:             MustWriteAccess :=   [Reduction Type: NONE] [Scalar: 0]
> > +; CHECK-NEXT:                 { Stmt_body4[i0] -> MemRef_X[0] };
> > +; CHECK-NEXT:             ReadAccess :=        [Reduction Type: NONE] [Scalar: 1]
> > +; CHECK-NEXT:                 { Stmt_body4[i0] -> MemRef_ptr[] };
> > +; CHECK-NEXT:     }
> > +
> > +define void @foo(float** %A, float** %X) {
> > +start:
> > +  br label %loop
> > +
> > +loop:
> > +  %indvar = phi i64 [0, %start], [%indvar.next, %latch]
> > +  %indvar.next = add nsw i64 %indvar, 1
> > +  %icmp = icmp slt i64 %indvar.next, 1024
> > +  br i1 %icmp, label %body0, label %exit
> > +
> > +body0:
> > +  %ptr = load float*, float** %A
> > +  store float* %ptr, float** %X
> > +  br label %body1
> > +
> > +body1:
> > +  %baseA = load float*, float** %A
> > +  store float 42.0, float* %baseA
> > +  br label %body2
> > +
> > +body2:
> > +  %ptr2 = load float*, float** %A
> > +  store float* %ptr, float** %X
> > +  br label %body3
> > +
> > +body3:
> > +  %baseB = load float*, float** %A
> > +  store float 42.0, float* %baseB
> > +  br label %body4
> > +
> > +body4:
> > +  %ptr3 = load float*, float** %A
> > +  store float* %ptr, float** %X
> > +  br label %latch
> > +
> > +latch:
> > +  br label %loop
> > +
> > +exit:
> > +  ret void
> > +
> > +}
> >
> > Added: polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_3.ll
> > URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_3.ll?rev=302636&view=auto
> > ==============================================================================
> > --- polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_3.ll (added)
> > +++ polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_3.ll Wed May 10 05:59:58 2017
> > @@ -0,0 +1,58 @@
> > +; RUN: opt %loadPolly -polly-scops -analyze < %s \
> > +; RUN:  -polly-invariant-load-hoisting \
> > +; RUN:  | FileCheck %s
> > +
> > +; Verify that we canonicalize accesses even tough one of the accesses (even
> > +; the canonical base) has a partial execution context. This is correct as
> > +; the combined execution context still coveres both accesses.
> > +
> > +; CHECK:      Invariant Accesses: {
> > +; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
> > +; CHECK-NEXT:             { Stmt_body2[i0] -> MemRef_A[0] };
> > +; CHECK-NEXT:         Execution Context: {  :  }
> > +; CHECK-NEXT: }
> > +
> > +; CHECK:      Stmt_body1
> > +; CHECK-NEXT:   Domain :=
> > +; CHECK-NEXT:       { Stmt_body1[i0] : 0 <= i0 <= 1022 };
> > +; CHECK-NEXT:   Schedule :=
> > +; CHECK-NEXT:       { Stmt_body1[i0] -> [i0, 0] };
> > +; CHECK-NEXT:   MustWriteAccess :=     [Reduction Type: NONE] [Scalar: 0]
> > +; CHECK-NEXT:       { Stmt_body1[i0] -> MemRef_baseB[0] };
> > +; CHECK-NEXT: Stmt_body2
> > +; CHECK-NEXT:   Domain :=
> > +; CHECK-NEXT:       { Stmt_body2[i0] : 0 <= i0 <= 510 };
> > +; CHECK-NEXT:   Schedule :=
> > +; CHECK-NEXT:       { Stmt_body2[i0] -> [i0, 1] };
> > +; CHECK-NEXT:   MustWriteAccess :=     [Reduction Type: NONE] [Scalar: 0]
> > +; CHECK-NEXT:       { Stmt_body2[i0] -> MemRef_baseB[0] };
> > +
> > +
> > +define void @foo(float** %A) {
> > +start:
> > +  br label %loop
> > +
> > +loop:
> > +  %indvar = phi i64 [0, %start], [%indvar.next, %latch]
> > +  %indvar.next = add nsw i64 %indvar, 1
> > +  %icmp = icmp slt i64 %indvar.next, 1024
> > +  br i1 %icmp, label %body1, label %exit
> > +
> > +body1:
> > +  %baseA = load float*, float** %A
> > +  store float 42.0, float* %baseA
> > +  %cmp = icmp slt i64 %indvar.next, 512
> > +  br i1 %cmp, label %body2, label %latch
> > +
> > +body2:
> > +  %baseB = load float*, float** %A
> > +  store float 42.0, float* %baseB
> > +  br label %latch
> > +
> > +latch:
> > +  br label %loop
> > +
> > +exit:
> > +  ret void
> > +
> > +}
> >
> > Added: polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4.ll
> > URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4.ll?rev=302636&view=auto
> > ==============================================================================
> > --- polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4.ll (added)
> > +++ polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4.ll Wed May 10 05:59:58 2017
> > @@ -0,0 +1,54 @@
> > +; RUN: opt %loadPolly -polly-scops -analyze < %s \
> > +; RUN:  -polly-invariant-load-hoisting \
> > +; RUN:  | FileCheck %s
> > +
> > +; Verify that a delinearized and a not delinearized access are not
> > +; canonizalized.
> > +
> > +; CHECK:      Stmt_body1
> > +; CHECK-NEXT:   Domain :=
> > +; CHECK-NEXT:       [n] -> { Stmt_body1[i0] : 0 <= i0 <= 1022 };
> > +; CHECK-NEXT:   Schedule :=
> > +; CHECK-NEXT:       [n] -> { Stmt_body1[i0] -> [i0, 0] };
> > +; CHECK-NEXT:   MustWriteAccess :=     [Reduction Type: NONE] [Scalar: 0]
> > +; CHECK-NEXT:       [n] -> { Stmt_body1[i0] -> MemRef_baseB[0] };
> > +; CHECK-NEXT: Stmt_body2
> > +; CHECK-NEXT:   Domain :=
> > +; CHECK-NEXT:       [n] -> { Stmt_body2[i0] : 0 <= i0 <= 1022 };
> > +; CHECK-NEXT:   Schedule :=
> > +; CHECK-NEXT:       [n] -> { Stmt_body2[i0] -> [i0, 1] };
> > +; CHECK-NEXT:   MustWriteAccess :=     [Reduction Type: NONE] [Scalar: 0]
> > +; CHECK-NEXT:       [n] -> { Stmt_body2[i0] -> MemRef_baseA[i0, i0] };
> > +; CHECK-NEXT: }
> > +
> > +
> > +define void @foo(float** %A, i64 %n, i64 %m) {
> > +start:
> > +  br label %loop
> > +
> > +loop:
> > +  %indvar = phi i64 [0, %start], [%indvar.next, %latch]
> > +  %indvar.next = add nsw i64 %indvar, 1
> > +  %icmp = icmp slt i64 %indvar.next, 1024
> > +  br i1 %icmp, label %body1, label %exit
> > +
> > +body1:
> > +  %baseB = load float*, float** %A
> > +  store float 42.0, float* %baseB
> > +  br label %body2
> > +
> > +body2:
> > +  %baseA = load float*, float** %A
> > +  %offsetA = mul i64 %indvar, %n
> > +  %offsetA2 = add i64 %offsetA, %indvar
> > +  %ptrA = getelementptr float, float* %baseA, i64 %offsetA2
> > +  store float 42.0, float* %ptrA
> > +  br label %latch
> > +
> > +latch:
> > +  br label %loop
> > +
> > +exit:
> > +  ret void
> > +
> > +}
> >
> > Added: polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4b.ll
> > URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4b.ll?rev=302636&view=auto
> > ==============================================================================
> > --- polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4b.ll (added)
> > +++ polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4b.ll Wed May 10 05:59:58 2017
> > @@ -0,0 +1,55 @@
> > +; RUN: opt %loadPolly -polly-scops -analyze < %s \
> > +; RUN:  -polly-invariant-load-hoisting \
> > +; RUN:  | FileCheck %s
> > +
> > +; Verify that two arrays delinearized with different sizes are not coalesced.
> > +
> > +; CHECK:      Stmt_body1
> > +; CHECK-NEXT:     Domain :=
> > +; CHECK-NEXT:         [m, n] -> { Stmt_body1[i0] : 0 <= i0 <= 1022 };
> > +; CHECK-NEXT:     Schedule :=
> > +; CHECK-NEXT:         [m, n] -> { Stmt_body1[i0] -> [i0, 0] };
> > +; CHECK-NEXT:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
> > +; CHECK-NEXT:         [m, n] -> { Stmt_body1[i0] -> MemRef_baseB[i0, i0] };
> > +; CHECK-NEXT: Stmt_body2
> > +; CHECK-NEXT:     Domain :=
> > +; CHECK-NEXT:         [m, n] -> { Stmt_body2[i0] : 0 <= i0 <= 1022 };
> > +; CHECK-NEXT:     Schedule :=
> > +; CHECK-NEXT:         [m, n] -> { Stmt_body2[i0] -> [i0, 1] };
> > +; CHECK-NEXT:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
> > +; CHECK-NEXT:         [m, n] -> { Stmt_body2[i0] -> MemRef_baseA[i0, i0] };
> > +; CHECK-NEXT: }
> > +
> > +define void @foo(float** %A, i64 %n, i64 %m) {
> > +start:
> > +  br label %loop
> > +
> > +loop:
> > +  %indvar = phi i64 [0, %start], [%indvar.next, %latch]
> > +  %indvar.next = add nsw i64 %indvar, 1
> > +  %icmp = icmp slt i64 %indvar.next, 1024
> > +  br i1 %icmp, label %body1, label %exit
> > +
> > +body1:
> > +  %baseB = load float*, float** %A
> > +  %offsetB = mul i64 %indvar, %m
> > +  %offsetB2 = add i64 %offsetB, %indvar
> > +  %ptrB = getelementptr float, float* %baseB, i64 %offsetB2
> > +  store float 42.0, float* %ptrB
> > +  br label %body2
> > +
> > +body2:
> > +  %baseA = load float*, float** %A
> > +  %offsetA = mul i64 %indvar, %n
> > +  %offsetA2 = add i64 %offsetA, %indvar
> > +  %ptrA = getelementptr float, float* %baseA, i64 %offsetA2
> > +  store float 42.0, float* %ptrA
> > +  br label %latch
> > +
> > +latch:
> > +  br label %loop
> > +
> > +exit:
> > +  ret void
> > +
> > +}
> >
> > Added: polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4c.ll
> > URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4c.ll?rev=302636&view=auto
> > ==============================================================================
> > --- polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4c.ll (added)
> > +++ polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4c.ll Wed May 10 05:59:58 2017
> > @@ -0,0 +1,51 @@
> > +; RUN: opt %loadPolly -polly-scops -analyze < %s \
> > +; RUN:  -polly-invariant-load-hoisting \
> > +; RUN:  | FileCheck %s
> > +
> > +; Verify that arrays with different element types are not coalesced.
> > +
> > +; CHECK:      Statements {
> > +; CHECK-NEXT:  Stmt_body1
> > +; CHECK-NEXT:         Domain :=
> > +; CHECK-NEXT:             { Stmt_body1[i0] : 0 <= i0 <= 1022 };
> > +; CHECK-NEXT:         Schedule :=
> > +; CHECK-NEXT:             { Stmt_body1[i0] -> [i0, 0] };
> > +; CHECK-NEXT:         MustWriteAccess :=       [Reduction Type: NONE] [Scalar: 0]
> > +; CHECK-NEXT:             { Stmt_body1[i0] -> MemRef_baseB[0] };
> > +; CHECK-NEXT:  Stmt_body2
> > +; CHECK-NEXT:         Domain :=
> > +; CHECK-NEXT:             { Stmt_body2[i0] : 0 <= i0 <= 1022 };
> > +; CHECK-NEXT:         Schedule :=
> > +; CHECK-NEXT:             { Stmt_body2[i0] -> [i0, 1] };
> > +; CHECK-NEXT:         MustWriteAccess :=       [Reduction Type: NONE] [Scalar: 0]
> > +; CHECK-NEXT:             { Stmt_body2[i0] -> MemRef_baseA[0] };
> > +; CHECK-NEXT: }
> > +
> > +define void @foo(float** %A, i64 %n, i64 %m) {
> > +start:
> > +  br label %loop
> > +
> > +loop:
> > +  %indvar = phi i64 [0, %start], [%indvar.next, %latch]
> > +  %indvar.next = add nsw i64 %indvar, 1
> > +  %icmp = icmp slt i64 %indvar.next, 1024
> > +  br i1 %icmp, label %body1, label %exit
> > +
> > +body1:
> > +  %baseB = load float*, float** %A
> > +  store float 42.0, float* %baseB
> > +  br label %body2
> > +
> > +body2:
> > +  %baseA = load float*, float** %A
> > +  %ptrcast = bitcast float* %baseA to i64*
> > +  store i64 42, i64* %ptrcast
> > +  br label %latch
> > +
> > +latch:
> > +  br label %loop
> > +
> > +exit:
> > +  ret void
> > +
> > +}
> >
> > Added: polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_5.ll
> > URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_5.ll?rev=302636&view=auto
> > ==============================================================================
> > --- polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_5.ll (added)
> > +++ polly/trunk/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_5.ll Wed May 10 05:59:58 2017
> > @@ -0,0 +1,78 @@
> > +; RUN: opt %loadPolly -polly-scops -analyze < %s \
> > +; RUN:  -polly-invariant-load-hoisting \
> > +; RUN:  | FileCheck %s
> > +
> > +; Verify that nested arrays with invariant base pointers are handled correctly.
> > +; Specifically, we currently do not canonicalize arrays where some accesses are
> > +; hoisted as invariant loads. If we would, we need to update the access function
> > +; of the invariant loads as well. However, as this is not a very common
> > +; situation, we leave this for now to avoid further complexity increases.
> > +;
> > +; In this test case the arrays baseA1 and baseA2 could be canonicalized to a
> > +; single array, but there is also an invariant access to baseA1[0] through
> > +; "%v0 = load float, float* %ptr" which prevents the canonicalization.
> > +
> > +; CHECK:      Invariant Accesses: {
> > +; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
> > +; CHECK-NEXT:             { Stmt_body2[i0] -> MemRef_A[0] };
> > +; CHECK-NEXT:         Execution Context: {  :  }
> > +; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
> > +; CHECK-NEXT:             { Stmt_body1[i0] -> MemRef_baseA1[0] };
> > +; CHECK-NEXT:         Execution Context: {  :  }
> > +; CHECK-NEXT: }
> > +
> > +; CHECK:      Statements {
> > +; CHECK-NEXT:  Stmt_body1
> > +; CHECK-NEXT:         Domain :=
> > +; CHECK-NEXT:             { Stmt_body1[i0] : 0 <= i0 <= 1021 };
> > +; CHECK-NEXT:         Schedule :=
> > +; CHECK-NEXT:             { Stmt_body1[i0] -> [i0, 0] };
> > +; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
> > +; CHECK-NEXT:             { Stmt_body1[i0] -> MemRef_baseA1[1 + i0] };
> > +; CHECK-NEXT:         MustWriteAccess :=       [Reduction Type: NONE] [Scalar: 0]
> > +; CHECK-NEXT:             { Stmt_body1[i0] -> MemRef_B[0] };
> > +; CHECK-NEXT:         MustWriteAccess :=       [Reduction Type: NONE] [Scalar: 0]
> > +; CHECK-NEXT:             { Stmt_body1[i0] -> MemRef_B[0] };
> > +; CHECK-NEXT:  Stmt_body2
> > +; CHECK-NEXT:         Domain :=
> > +; CHECK-NEXT:             { Stmt_body2[i0] : 0 <= i0 <= 1021 };
> > +; CHECK-NEXT:         Schedule :=
> > +; CHECK-NEXT:             { Stmt_body2[i0] -> [i0, 1] };
> > +; CHECK-NEXT:         MustWriteAccess :=       [Reduction Type: NONE] [Scalar: 0]
> > +; CHECK-NEXT:             { Stmt_body2[i0] -> MemRef_baseA2[0] };
> > +; CHECK-NEXT: }
> > +
> > +define void @foo(float** %A, float* %B) {
> > +start:
> > +  br label %loop
> > +
> > +loop:
> > +  %indvar = phi i64 [1, %start], [%indvar.next, %latch]
> > +  %indvar.next = add nsw i64 %indvar, 1
> > +  %icmp = icmp slt i64 %indvar.next, 1024
> > +  br i1 %icmp, label %body1, label %exit
> > +
> > +body1:
> > +  %baseA1 = load float*, float** %A
> > +  %ptr = getelementptr inbounds float, float* %baseA1, i64 %indvar
> > +  %v0 = load float, float* %ptr
> > +  %v1 = load float, float* %baseA1
> > +  store float %v0, float* %B
> > +  store float %v1, float* %B
> > +  br label %body2
> > +
> > +body2:
> > +  %baseA2 = load float*, float** %A
> > +  store float undef, float* %baseA2
> > +  br label %body3
> > +
> > +body3:
> > +  br label %latch
> > +
> > +latch:
> > +  br label %loop
> > +
> > +exit:
> > +  ret void
> > +
> > +}
> >
> >
> > _______________________________________________
> > llvm-commits mailing list
> > llvm-commits at lists.llvm.org
> > http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits


More information about the llvm-commits mailing list