[polly] r312350 - [ISLNodeBuilder] Materialize Fortran array sizes of arrays without memory accesses.

Siddharth Bhat via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 1 11:55:43 PDT 2017


Author: bollu
Date: Fri Sep  1 11:55:43 2017
New Revision: 312350

URL: http://llvm.org/viewvc/llvm-project?rev=312350&view=rev
Log:
[ISLNodeBuilder] Materialize Fortran array sizes of arrays without memory accesses.

 In Polly, we specifically add a paramter to represent the outermost dimension
 size of fortran arrays. We do this because this information is statically
 available from the fortran metadata generated by dragonegg.
 However, we were only materializing these parameters (meaning, creating an
 llvm::Value to back the isl_id) from *memory accesses*. This is wrong,
 we should materialize parameters from *scop array info*.

 It is wrong because if there is a case where we detect 2 fortran arrays,
 but only one of them is accessed, we may not materialize the other array's
 dimensions at all.

 This is incorrect. We fix this by looping over all
 `polly::ScopArrayInfo` in a scop, rather that just all `polly::MemoryAccess`.

 Differential Revision: https://reviews.llvm.org/D37379

Added:
    polly/trunk/test/GPGPU/check-unused-fortran-array-size-param-offloaded-to-kernel.ll
Modified:
    polly/trunk/include/polly/ScopInfo.h
    polly/trunk/lib/CodeGen/IslNodeBuilder.cpp

Modified: polly/trunk/include/polly/ScopInfo.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/ScopInfo.h?rev=312350&r1=312349&r2=312350&view=diff
==============================================================================
--- polly/trunk/include/polly/ScopInfo.h (original)
+++ polly/trunk/include/polly/ScopInfo.h Fri Sep  1 11:55:43 2017
@@ -301,6 +301,10 @@ public:
   /// since this information is available for Fortran arrays at runtime.
   void applyAndSetFAD(Value *FAD);
 
+  /// Get the FortranArrayDescriptor corresponding to this array if it exists,
+  /// nullptr otherwise.
+  Value *getFortranArrayDescriptor() const { return this->FAD; }
+
   /// Set the base pointer to @p BP.
   void setBasePtr(Value *BP) { BasePtr = BP; }
 

Modified: polly/trunk/lib/CodeGen/IslNodeBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/CodeGen/IslNodeBuilder.cpp?rev=312350&r1=312349&r2=312350&view=diff
==============================================================================
--- polly/trunk/lib/CodeGen/IslNodeBuilder.cpp (original)
+++ polly/trunk/lib/CodeGen/IslNodeBuilder.cpp Fri Sep  1 11:55:43 2017
@@ -1176,44 +1176,35 @@ static Value *buildFADOutermostDimension
 }
 
 bool IslNodeBuilder::materializeFortranArrayOutermostDimension() {
-  for (const ScopStmt &Stmt : S) {
-    for (const MemoryAccess *Access : Stmt) {
-      if (!Access->isArrayKind())
-        continue;
-
-      const ScopArrayInfo *Array = Access->getScopArrayInfo();
-      if (!Array)
-        continue;
-
-      if (Array->getNumberOfDimensions() == 0)
-        continue;
-
-      Value *FAD = Access->getFortranArrayDescriptor();
-      if (!FAD)
-        continue;
-
-      isl_pw_aff *ParametricPwAff = Array->getDimensionSizePw(0).release();
-      assert(ParametricPwAff && "parametric pw_aff corresponding "
-                                "to outermost dimension does not "
-                                "exist");
-
-      isl_id *Id = isl_pw_aff_get_dim_id(ParametricPwAff, isl_dim_param, 0);
-      isl_pw_aff_free(ParametricPwAff);
-
-      assert(Id && "pw_aff is not parametric");
-
-      if (IDToValue.count(Id)) {
-        isl_id_free(Id);
-        continue;
-      }
-
-      Value *FinalValue =
-          buildFADOutermostDimensionLoad(FAD, Builder, Array->getName());
-      assert(FinalValue && "unable to build Fortran array "
-                           "descriptor load of outermost dimension");
-      IDToValue[Id] = FinalValue;
+  for (ScopArrayInfo *Array : S.arrays()) {
+    if (Array->getNumberOfDimensions() == 0)
+      continue;
+
+    Value *FAD = Array->getFortranArrayDescriptor();
+    if (!FAD)
+      continue;
+
+    isl_pw_aff *ParametricPwAff = Array->getDimensionSizePw(0).release();
+    assert(ParametricPwAff && "parametric pw_aff corresponding "
+                              "to outermost dimension does not "
+                              "exist");
+
+    isl_id *Id = isl_pw_aff_get_dim_id(ParametricPwAff, isl_dim_param, 0);
+    isl_pw_aff_free(ParametricPwAff);
+
+    assert(Id && "pw_aff is not parametric");
+
+    if (IDToValue.count(Id)) {
       isl_id_free(Id);
+      continue;
     }
+
+    Value *FinalValue =
+        buildFADOutermostDimensionLoad(FAD, Builder, Array->getName());
+    assert(FinalValue && "unable to build Fortran array "
+                         "descriptor load of outermost dimension");
+    IDToValue[Id] = FinalValue;
+    isl_id_free(Id);
   }
   return true;
 }

Added: polly/trunk/test/GPGPU/check-unused-fortran-array-size-param-offloaded-to-kernel.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/GPGPU/check-unused-fortran-array-size-param-offloaded-to-kernel.ll?rev=312350&view=auto
==============================================================================
--- polly/trunk/test/GPGPU/check-unused-fortran-array-size-param-offloaded-to-kernel.ll (added)
+++ polly/trunk/test/GPGPU/check-unused-fortran-array-size-param-offloaded-to-kernel.ll Fri Sep  1 11:55:43 2017
@@ -0,0 +1,102 @@
+; RUN: opt %loadPolly -analyze -polly-scops \
+; RUN:     -polly-detect-fortran-arrays \
+; RUN:     -polly-invariant-load-hoisting \
+; RUN:     -polly-use-llvm-names \
+; RUN:     < %s | FileCheck %s --check-prefix=SCOP
+
+; RUN: opt %loadPolly -S \
+; RUN:     -polly-detect-fortran-arrays \
+; RUN:     -polly-codegen-ppcg \
+; RUN:     -polly-invariant-load-hoisting \
+; RUN:     -polly-use-llvm-names \
+; RUN:     -polly-acc-fail-on-verify-module-failure \
+; RUN:     < %s | FileCheck %s --check-prefix=HOST-IR
+
+; REQUIRES: pollyacc
+
+; In Polly, we specifically add a parameter to represent the outermost dimension
+; size of fortran arrays. We do this because this information is statically
+; available from the fortran metadata generated by dragonegg.
+; However, we were only materializing these parameters (meaning, creating an
+; llvm::Value to back the isl_id) from *memory accesses*. This is wrong,
+; we should materialize parameters from *scop array info*.
+
+; It is wrong because if there is a case where we detect 2 fortran arrays,
+; but only one of them is accessed, we may not materialize the other array's
+; dimensions at all.
+
+; This test case checks that we do not fail if there is an array that does
+; not have an access (In this case, `memory`), we still generate the
+; parameter.
+
+; Check that we detect the function as a Scop.
+; SCOP:      Function: f
+; SCOP-NEXT: Region: %loop.prepare---%for.exit
+; SCOP-NEXT: Max Loop Depth:  1
+
+; Check that we detect fortran arrays.
+; SCOP:    Arrays (Bounds as pw_affs) {
+; SCOP:             double* MemRef_global_arr[*]; // Element size 8
+; SCOP-NEXT:        double MemRef_memory[ [MemRef_memory_fortranarr_size] -> { [] -> [(MemRef_memory_fortranarr_size)] } ]; [BasePtrOrigin: MemRef_global_arr] // Element size 8
+; SCOP-NEXT:        double MemRef_memory2[ [MemRef_memory2_fortranarr_size] -> { [] -> [(MemRef_memory2_fortranarr_size)] } ]; [BasePtrOrigin: MemRef_global_arr] // Element size 8
+; SCOP-NEXT:    }
+
+; Check that we have writes *only* into memory2, not into memory.
+; SCOP:    Statements {
+; SCOP:    	Stmt_for_body
+; SCOP:            MustWriteAccess :=	[Reduction Type: NONE] [Fortran array descriptor: global_arr] [Scalar: 0]
+; SCOP-NEXT:                [start_val, end_val, offset, MemRef_memory_fortranarr_size, MemRef_memory2_fortranarr_size] -> { Stmt_for_body[i0] -> MemRef_memory2[start_val + offset + i0] };
+; SCOP-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Fortran array descriptor: global_arr] [Scalar: 0]
+; SCOP-NEXT:                [start_val, end_val, offset, MemRef_memory_fortranarr_size, MemRef_memory2_fortranarr_size] -> { Stmt_for_body[i0] -> MemRef_memory2[start_val + offset + i0] };
+; SCOP-NEXT:    }
+
+; Check that we materialize the sizes and send it across to the kernel.
+; HOST-IR: store i64 %MemRef_memory_size, i64* %polly_launch_0_param_4
+; HOST-IR: store i64 %MemRef_memory2_size, i64* %polly_launch_0_param_5
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+module asm "\09.ident\09\22GCC: (GNU) 4.6.4 LLVM: 3.3.1\22"
+
+%"struct.array1_real(kind=8)" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] }
+%struct.descriptor_dimension = type { i64, i64, i64 }
+
+ at global_arr = external unnamed_addr global %"struct.array1_real(kind=8)", align 32
+
+; Function Attrs: nounwind uwtable
+define void @f(i32* noalias %ipstart, i32* noalias %ipend) unnamed_addr #0 {
+entry:
+  br label %loop.prepare
+
+
+loop.prepare:                                              ; preds = %"6", %"3.preheader"
+  %start.val = load i32, i32* %ipstart, align 4
+  %end.val = load i32, i32* %ipend, align 4
+  %should.loop = icmp sgt i32 %start.val, %end.val
+  br i1 %should.loop, label %for.exit, label %for.body
+
+
+for.body:                                              ; preds = %for.body, %"4.preheader"
+  %i = phi i32 [ %i.next, %for.body ], [ %start.val, %loop.prepare ]
+  %i.sext = sext i32 %i to i64
+  %memory = load double*, double** bitcast (%"struct.array1_real(kind=8)"* @global_arr to double**), align 32
+  %offset = load i64, i64* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @global_arr, i64 0, i32 1), align 8
+  %idx = add i64 %offset, %i.sext
+  %slot = getelementptr double, double* %memory, i64 %idx
+  store double 1.0, double* %slot, align 8
+
+  %memory2 = load double*, double** bitcast (%"struct.array1_real(kind=8)"* @global_arr to double**), align 32
+  %offset2 = load i64, i64* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @global_arr, i64 0, i32 1), align 8
+  %idx2 = add i64 %offset2, %i.sext
+  %slot2 = getelementptr double, double* %memory2, i64 %idx2
+  %val = load double, double* %slot2, align 8
+
+  %should.loopexit = icmp eq i32 %i, %end.val
+  %i.next = add i32 %i, 1
+  br i1 %should.loopexit, label %for.exit, label %for.body
+
+for.exit:                                     ; preds = %for.body
+  ret void
+}
+
+attributes #0 = { nounwind uwtable }




More information about the llvm-commits mailing list