Index: include/polly/ScopInfo.h =================================================================== --- include/polly/ScopInfo.h +++ include/polly/ScopInfo.h @@ -301,6 +301,10 @@ /// 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; } Index: lib/CodeGen/IslNodeBuilder.cpp =================================================================== --- lib/CodeGen/IslNodeBuilder.cpp +++ lib/CodeGen/IslNodeBuilder.cpp @@ -1176,44 +1176,35 @@ } 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; + for (ScopArrayInfo *Array : S.arrays()) { + if (Array->getNumberOfDimensions() == 0) + continue; - isl_pw_aff *ParametricPwAff = Array->getDimensionSizePw(0).release(); - assert(ParametricPwAff && "parametric pw_aff corresponding " - "to outermost dimension does not " - "exist"); + Value *FAD = Array->getFortranArrayDescriptor(); + if (!FAD) + continue; - isl_id *Id = isl_pw_aff_get_dim_id(ParametricPwAff, isl_dim_param, 0); - isl_pw_aff_free(ParametricPwAff); + isl_pw_aff *ParametricPwAff = Array->getDimensionSizePw(0).release(); + assert(ParametricPwAff && "parametric pw_aff corresponding " + "to outermost dimension does not " + "exist"); - assert(Id && "pw_aff is not parametric"); + isl_id *Id = isl_pw_aff_get_dim_id(ParametricPwAff, isl_dim_param, 0); + isl_pw_aff_free(ParametricPwAff); - if (IDToValue.count(Id)) { - isl_id_free(Id); - continue; - } + assert(Id && "pw_aff is not parametric"); - Value *FinalValue = - buildFADOutermostDimensionLoad(FAD, Builder, Array->getName()); - assert(FinalValue && "unable to build Fortran array " - "descriptor load of outermost dimension"); - IDToValue[Id] = FinalValue; + 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; } Index: test/GPGPU/check-unused-fortran-array-size-param-offloaded-to-kernel.ll =================================================================== --- /dev/null +++ test/GPGPU/check-unused-fortran-array-size-param-offloaded-to-kernel.ll @@ -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 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 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 } + +@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 }