Index: include/polly/CodeGen/IslNodeBuilder.h =================================================================== --- include/polly/CodeGen/IslNodeBuilder.h +++ include/polly/CodeGen/IslNodeBuilder.h @@ -75,6 +75,13 @@ void addParameters(__isl_take isl_set *Context); + /// Create Values which hold the sizes of the outermost dimension of all + /// Fortran arrays in the current scop. + /// + /// @returns False, if a problem occurred and a Fortran array was not + /// materialized. True otherwise. + bool materializeFortranArrayOutermostDimensionParameters(); + /// Generate code that evaluates @p Condition at run-time. /// /// This function is typically called to generate the LLVM-IR for the Index: include/polly/ScopBuilder.h =================================================================== --- include/polly/ScopBuilder.h +++ include/polly/ScopBuilder.h @@ -57,21 +57,21 @@ // Methods for pattern matching against Fortran code generated by dragonegg. // @{ - /// Try to match for the descriptor of a Fortran Array that has been declared - /// global, and is allocated in this module. + /// Try to match for the descriptor of a Fortran Array whose allocation + /// is not visible. That is, the Array's memory is loaded. /// - /// "@globaldescriptor" is the descriptor of the Fortran Array. + /// "" is the descriptor of the Fortran Array. /// - /// Pattern match for "@globaldescriptor": + /// Pattern match for "@descriptor": /// 1. %mem = load double*, double** bitcast (%"struct.array1_real(kind=8)"* - /// @globaldescriptor to double**), align 32 + /// to double**), align 32 /// /// 2. [%slot = getelementptr inbounds i8, i8* %mem, i64 ] /// 2 is optional because if you are writing to the 0th index, you don't /// need a GEP. /// - /// 3.1 store/load , * %slot, align 8 - /// 3.2 store/load , * %mem, align 8 + /// 3.1 store/load , * %slot + /// 3.2 store/load , * %mem /// /// @see polly::MemoryAccess, polly::ScopArrayInfo /// @@ -79,19 +79,18 @@ /// /// @param Inst The LoadInst/StoreInst that accesses the memory. /// - /// @returns Reference to @globaldescriptor on success, nullptr on failure. - Value *findFADGlobalAlloc(MemAccInst Inst); + /// @returns Reference to on success, nullptr on failure. + Value *findFADAllocationInvisible(MemAccInst Inst); - /// Try to match for the descriptor of a Fortran Array that has been declared - /// global, has not been allocated, and is being allocated here. + /// Try to match for the descriptor of a Fortran Array whose allocation + /// call is visible. /// - /// Pattern match for "@globaldescriptor": + /// Pattern match for "%untypedmem": /// 1. %untypedmem = i8* @malloc(...) /// - /// 2. %typedmem = bitcast i8* %untypedmem to * + /// 2. %typedmem = bitcast i8* %untypedmem to /// - /// 3. [%slot = getelementptr inbounds - /// , * %typedmem, i64 ] + /// 3. [%slot = getelementptr inbounds i8, i8* %typedmem, i64 ] /// 3 is optional because if you are writing to the 0th index, you don't /// need a GEP. /// @@ -104,30 +103,9 @@ /// /// @param Inst The LoadInst/StoreInst that accesses the memory. /// - /// @returns Reference to @globaldescriptor on success, nullptr on failure. - Value *findFADGlobalNonAlloc(MemAccInst Inst); + /// @returns Reference to %untypedmem on success, nullptr on failure. + Value *findFADAllocationVisible(MemAccInst Inst); - /// Try to match for the descriptor of a Fortran array that is a parameter - /// to a function, and has not been allocated. - /// - /// Pattern match for "%param": - /// 1. %mem = bitcast %"struct.array1_integer(kind=4)"* %param to i32** - /// - /// 2. [%slot = getelementptr inbounds i8, i8* %mem, i64 ] - /// 2 is optional because if you are writing to the 0th index, you don't - /// need a GEP. - /// - /// 3.1 store/load , * %slot, align 8 - /// 3.2 store/load , * %mem, align 8 - /// - /// @see polly::MemoryAccess, polly::ScopArrayInfo - /// - /// @note assumes -polly-canonicalize has been run. - /// - /// @param Inst The LoadInst/StoreInst that accesses the memory. - /// - /// @returns Reference to "%param" on success, nullptr on failure. - Value *findFADLocalNonAlloc(MemAccInst Inst); // @} // Build the SCoP for Region @p R. Index: include/polly/ScopInfo.h =================================================================== --- include/polly/ScopInfo.h +++ include/polly/ScopInfo.h @@ -264,6 +264,9 @@ /// with old sizes bool updateSizes(ArrayRef Sizes, bool CheckConsistency = true); + /// Make the ScopArrayInfo model a Fortran Array + void makeFortranArray(Value *FAD); + /// Destructor to free the isl id of the base pointer. ~ScopArrayInfo(); @@ -420,6 +423,10 @@ /// The scop this SAI object belongs to. Scop &S; + + /// If this arrays models a Fortran array, contains a pointer + /// to the Fortran array descriptor + Value *FAD; }; /// Represent memory accesses in statements. @@ -896,6 +903,10 @@ /// the dimension of the innermost loop containing the statement. __isl_give isl_set *getStride(__isl_take const isl_map *Schedule) const; + /// Get the FortranArrayDescriptor corresponding to this memory access if + /// it exists, and nullptr otherwise. + Value *getFortranArrayDescriptor() const { return this->FAD; }; + /// Is the stride of the access equal to a certain width? Schedule is a map /// from the statement to a schedule where the innermost dimension is the /// dimension of the innermost loop containing the statement. @@ -2065,6 +2076,10 @@ /// all memory accesses have been modeled and canonicalized. void assumeNoOutOfBounds(); + /// Mark Arrays that have memory accesses with FortranArrayDescriptor + /// as fortran arrays + void markFortranArrays(); + /// Finalize all access relations. /// /// When building up access relations, temporary access relations that Index: lib/Analysis/ScopBuilder.cpp =================================================================== --- lib/Analysis/ScopBuilder.cpp +++ lib/Analysis/ScopBuilder.cpp @@ -201,7 +201,7 @@ return true; } -Value *ScopBuilder::findFADGlobalNonAlloc(MemAccInst Inst) { +Value *ScopBuilder::findFADAllocationVisible(MemAccInst Inst) { // match: 4.1 & 4.2 store/load if (!isa(Inst) && !isa(Inst)) return nullptr; @@ -272,15 +272,11 @@ return nullptr; } -Value *ScopBuilder::findFADGlobalAlloc(MemAccInst Inst) { +Value *ScopBuilder::findFADAllocationInvisible(MemAccInst Inst) { // match: 3 if (!isa(Inst) && !isa(Inst)) return nullptr; - // match: 3 - if (Inst.getAlignment() != 8) - return nullptr; - Value *Slot = Inst.getPointerOperand(); LoadInst *MemLoad = nullptr; @@ -311,40 +307,6 @@ return Descriptor; } -Value *ScopBuilder::findFADLocalNonAlloc(MemAccInst Inst) { - // match: 3 - if (!isa(Inst) && !isa(Inst)) - return nullptr; - - // match: 3 - if (Inst.getAlignment() != 8) - return nullptr; - - Value *Slot = Inst.getPointerOperand(); - - BitCastOperator *MemBitcast = nullptr; - // [match: 2] - if (auto *SlotGEP = dyn_cast(Slot)) { - // match: 1 - MemBitcast = dyn_cast(SlotGEP->getPointerOperand()); - } else { - // match: 1 - MemBitcast = dyn_cast(Slot); - } - - if (!MemBitcast) - return nullptr; - - Value *Descriptor = dyn_cast(MemBitcast->getOperand(0)); - if (!Descriptor) - return nullptr; - - if (!isFortranArrayDescriptor(Descriptor)) - return nullptr; - - return Descriptor; -} - bool ScopBuilder::buildAccessMultiDimFixed(MemAccInst Inst, ScopStmt *Stmt) { Value *Val = Inst.getValueOperand(); Type *ElementType = Val->getType(); @@ -771,11 +733,9 @@ if (!DetectFortranArrays) return; - if (Value *FAD = findFADGlobalNonAlloc(MemAccInst)) - MemAccess->setFortranArrayDescriptor(FAD); - else if (Value *FAD = findFADGlobalAlloc(MemAccInst)) + if (Value *FAD = findFADAllocationInvisible(MemAccInst)) MemAccess->setFortranArrayDescriptor(FAD); - else if (Value *FAD = findFADLocalNonAlloc(MemAccInst)) + else if (Value *FAD = findFADAllocationVisible(MemAccInst)) MemAccess->setFortranArrayDescriptor(FAD); } Index: lib/Analysis/ScopInfo.cpp =================================================================== --- lib/Analysis/ScopInfo.cpp +++ lib/Analysis/ScopInfo.cpp @@ -240,7 +240,8 @@ ArrayRef Sizes, MemoryKind Kind, const DataLayout &DL, Scop *S, const char *BaseName) - : BasePtr(BasePtr), ElementType(ElementType), Kind(Kind), DL(DL), S(*S) { + : BasePtr(BasePtr), ElementType(ElementType), Kind(Kind), DL(DL), S(*S), + FAD(nullptr) { std::string BasePtrName = BaseName ? BaseName : getIslCompatibleName("MemRef", BasePtr, S->getNextArrayIdx(), @@ -311,6 +312,36 @@ } } +/// Make the ScopArrayInfo model a Fortran Array +void ScopArrayInfo::makeFortranArray(Value *FAD) { + assert(FAD && "got invalid Fortran array descriptor"); + if (this->FAD) { + assert(this->FAD == FAD && + "receiving different array descriptors for same array"); + return; + } + + assert(DimensionSizesPw.size() > 0 && DimensionSizesPw[0] == nullptr); + assert(this->FAD == nullptr); + this->FAD = FAD; + + isl_space *space = isl_space_set_alloc(S.getIslCtx(), 1, 0); + + std::string param_name = this->getName(); + param_name += "_fortranarr_size"; + isl_id *id_for_pa = isl_id_alloc(S.getIslCtx(), param_name.c_str(), nullptr); + + space = isl_space_set_dim_id(space, isl_dim_param, 0, id_for_pa); + isl_basic_set *identity = isl_basic_set_universe(space); + isl_local_space *ls = isl_basic_set_get_local_space(identity); + isl_basic_set_free(identity); + + isl_aff *aff = isl_aff_var_on_domain(ls, isl_dim_param, 0); + isl_pw_aff *pa = isl_pw_aff_from_aff(aff); + + DimensionSizesPw[0] = pa; +} + bool ScopArrayInfo::updateSizes(ArrayRef NewSizes, bool CheckConsistency) { int SharedDims = std::min(NewSizes.size(), DimensionSizes.size()); @@ -367,7 +398,12 @@ void ScopArrayInfo::print(raw_ostream &OS, bool SizeAsPwAff) const { OS.indent(8) << *getElementType() << " " << getName(); unsigned u = 0; - if (getNumberOfDimensions() > 0 && !getDimensionSize(0)) { + // If this is a Fortran array, then we can print the outermost dimension + // as a pwAff even though there is no SCEV information. + const bool ShouldPrintOutermostDim = SizeAsPwAff && FAD; + + if (!ShouldPrintOutermostDim && getNumberOfDimensions() > 0 && + !getDimensionSize(0)) { OS << "[*]"; u++; } @@ -2168,6 +2204,33 @@ } } +isl_set *getContextWithFortranArrays(__isl_keep isl_set *ScopContext, + Scop::array_range arrays) { + isl_set *FortranContext = isl_set_copy(ScopContext); + int ContextNParams = isl_set_dim(FortranContext, isl_dim_param); + for (auto arr : arrays) { + // is a fortran array + // HACK: actually need to check if it has a FAD, but for now this works + if (arr->getNumberOfDimensions() > 0) { + isl_pw_aff *pwaff = arr->getDimensionSizePw(0); + if (pwaff == nullptr) + continue; + isl_id *id_for_pa = isl_pw_aff_get_dim_id(pwaff, isl_dim_param, 0); + + assert(id_for_pa); + + FortranContext = isl_set_add_dims(FortranContext, isl_dim_param, 1); + FortranContext = isl_set_set_dim_id(FortranContext, isl_dim_param, + ContextNParams, id_for_pa); + ContextNParams++; + + isl_pw_aff_free(pwaff); + } + } + + return FortranContext; +} + void Scop::realignParams() { if (PollyIgnoreParamBounds) return; @@ -2190,8 +2253,9 @@ for (ScopStmt &Stmt : *this) Stmt.realignParams(); - // Simplify the schedule according to the context too. - Schedule = isl_schedule_gist_domain_params(Schedule, getContext()); + isl_set *FortranArraysContext = + getContextWithFortranArrays(Context, arrays()); + Schedule = isl_schedule_gist_domain_params(Schedule, FortranArraysContext); } static __isl_give isl_set * @@ -3416,11 +3480,28 @@ return; } +void Scop::markFortranArrays() { + for (ScopStmt &Stmt : Stmts) { + for (MemoryAccess *memAccess : Stmt) { + Value *FAD = memAccess->getFortranArrayDescriptor(); + if (!FAD) + continue; + // HACK: const_cast-ing to edit + ScopArrayInfo *SAI = + const_cast(memAccess->getLatestScopArrayInfo()); + assert(SAI && "memory access into a fortran array does not " + "have an associated ScopArrayInfo"); + SAI->makeFortranArray(FAD); + } + } +} + void Scop::finalizeAccesses() { updateAccessDimensionality(); foldSizeConstantsToRight(); foldAccessRelations(); assumeNoOutOfBounds(); + markFortranArrays(); } Scop::~Scop() { Index: lib/CodeGen/IslNodeBuilder.cpp =================================================================== --- lib/CodeGen/IslNodeBuilder.cpp +++ lib/CodeGen/IslNodeBuilder.cpp @@ -995,6 +995,89 @@ return true; } +/// %"struct.array3_integer(kind=4)" = type { i8*, i64, i64, [3 x +/// %struct.descriptor_dimension] } %struct.descriptor_dimension = type { i64, +/// i64, i64 } +/// @__src_soil_MOD_arr = global %"struct.array3_integer(kind=4)" +/// zeroinitializer, align 32 +/// ... +/// %0 = load i64, i64* getelementptr inbounds +/// (%"struct.array3_integer(kind=4)", %"struct.array3_integer(kind=4)"* +/// @__src_soil_MOD_arr, i64 0, i32 3, i64 0, i32 2), align 8, !tbaa !0 %1 = +/// load i64, i64* getelementptr inbounds (%"struct.array3_integer(kind=4)", +/// %"struct.array3_integer(kind=4)"* @__src_soil_MOD_arr, i64 0, i32 3, i64 0, +/// i32 1), align 8, !tbaa !0 %2 = sub nsw i64 %0, %1 %3 = add nsw i64 %2, 1 +Value *buildFortranArrayDescriptorOutermostDimensionLoad( + Value *GlobalDescriptor, PollyIRBuilder &Builder, std::string ArrayName) { + assert(GlobalDescriptor && "invalid global descriptor given"); + + Value *endIdx[4] = {Builder.getInt64(0), Builder.getInt32(3), + Builder.getInt64(0), Builder.getInt32(2)}; + Value *endPtr = Builder.CreateInBoundsGEP(GlobalDescriptor, endIdx, + ArrayName + "_end_ptr"); + Value *end = Builder.CreateLoad(endPtr, ArrayName + "_end"); + + Value *beginIdx[4] = {Builder.getInt64(0), Builder.getInt32(3), + Builder.getInt64(0), Builder.getInt32(1)}; + Value *beginPtr = Builder.CreateInBoundsGEP(GlobalDescriptor, beginIdx, + ArrayName + "_begin_ptr"); + Value *begin = Builder.CreateLoad(beginPtr, ArrayName + "_begin"); + + Value *size = + Builder.CreateNSWSub(end, begin, ArrayName + "_end_begin_delta"); + Type *endType = dyn_cast(end->getType()); + assert(endType && "expected type of end to be integral"); + + size = Builder.CreateNSWAdd(end, + ConstantInt::get(endType, 1, /* signed = */ true), + ArrayName + "_size"); + + return size; +} + +bool IslNodeBuilder::materializeFortranArrayOutermostDimensionParameters() { + 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 = const_cast(Access->getFortranArrayDescriptor()); + if (FAD == nullptr) + continue; + + isl_pw_aff *parametric_pw_aff = Array->getDimensionSizePw(0); + assert(parametric_pw_aff && "parameteric pw_aff corresponding " + "to outermost dimension does not " + "exist"); + + isl_id *Id = isl_pw_aff_get_dim_id(parametric_pw_aff, isl_dim_param, 0); + isl_pw_aff_free(parametric_pw_aff); + + assert(Id && "pw_aff is not parametric"); + + if (IDToValue.count(Id)) { + isl_id_free(Id); + continue; + } + + Value *finalValue = buildFortranArrayDescriptorOutermostDimensionLoad( + dyn_cast(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; +} + /// Add the number of dimensions in @p BS to @p U. static isl_stat countTotalDims(__isl_take isl_basic_set *BS, void *U) { unsigned *NumTotalDim = static_cast(U); @@ -1313,6 +1396,12 @@ // Materialize values for the parameters of the SCoP. materializeParameters(); + // materialize the outermost dimension parameters for a fortran array. + // NOTE: materializeParameters() does not work since it looks through + // the SCEVs. We don't have a corresponding SCEV for the array size + // parameter + materializeFortranArrayOutermostDimensionParameters(); + // Generate values for the current loop iteration for all surrounding loops. // // We may also reference loops outside of the scop which do not contain the Index: lib/CodeGen/PPCGCodeGeneration.cpp =================================================================== --- lib/CodeGen/PPCGCodeGeneration.cpp +++ lib/CodeGen/PPCGCodeGeneration.cpp @@ -2163,9 +2163,17 @@ for (unsigned i = 1; i < NumDims; ++i) Extent = isl_set_lower_bound_si(Extent, isl_dim_set, i, 0); - for (unsigned i = 1; i < NumDims; ++i) { + for (unsigned i = 0; i < NumDims; ++i) { isl_pw_aff *PwAff = const_cast(Array->getDimensionSizePw(i)); + + // pwAff can be NULL for zero dimension. only in the case of a fortran + // array will we have a legitimate dimension + if (!PwAff) { + assert(i == 0 && "invalid dimension pwAff for nonzero dimension"); + continue; + } + isl_pw_aff *Val = isl_pw_aff_from_aff(isl_aff_var_on_domain( isl_local_space_from_space(Array->getSpace()), isl_dim_set, i)); PwAff = isl_pw_aff_add_dims(PwAff, isl_dim_in, Index: test/Isl/CodeGen/fortran_array_runtime_size_generation.ll =================================================================== --- /dev/null +++ test/Isl/CodeGen/fortran_array_runtime_size_generation.ll @@ -0,0 +1,82 @@ +; Check that the runtime size computation is generated for Fortran arrays. + +; PPCG code generation backend: +; RUN: opt %loadPolly -S -polly-detect-fortran-arrays \ +; RUN: -polly-target=gpu -polly-acc-mincompute=0 \ +; RUN: -polly-codegen-ppcg < %s | FileCheck %s + +; Regular code generation backend: +; RUN: opt %loadPolly -S -polly-detect-fortran-arrays \ +; RUN: -polly-codegen < %s | FileCheck %s + +; What the input fortran code should look like. NOTE: this is fake, the +; .ll file was hand-written. +; +; MODULE testmod +; USE data_parameters, ONLY : & +; IMPLICIT NONE +; +; INTEGER (KIND=iintegers), ALLOCATABLE, PRIVATE :: & +; arrin(:), arrout(:) +; CONTAINS +; +; SUBROUTINE test() +; INTEGER (KIND=iintegers) :: i +; +; DO i = 1, 100 +; arrout(i) = arrin(i) * arrin(i) +; END DO +; END SUBROUTINE test +; END MODULE testmod + +target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i32: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*, i32, i32, [1 x %struct.descriptor_dimension] } +%struct.descriptor_dimension = type { i32, i32, i32 } + +@arrin = unnamed_addr global %"struct.array1_real(kind=8)" zeroinitializer, align 32 +@arrout = unnamed_addr global %"struct.array1_real(kind=8)" zeroinitializer, align 32 + +; Function Attrs: nounwind uwtable +define void @__src_soil_MOD_terra1() unnamed_addr #0 { +entry: + br label %entry.split + +entry.split: ; preds = %entry + %rawmemin1 = load i32*, i32** bitcast (%"struct.array1_real(kind=8)"* @arrin to i32**), align 32, !tbaa !0 + %rawmemout2 = load i32*, i32** bitcast (%"struct.array1_real(kind=8)"* @arrout to i32**), align 32, !tbaa !0 + br label %for.body + +for.body: ; preds = %entry.split, %for.body + %indvars.iv = phi i64 [ 1, %entry.split ], [ %indvars.iv.next4, %for.body ] + %inslot = getelementptr inbounds i32, i32* %rawmemin1, i64 %indvars.iv + %inval = load i32, i32* %inslot, align 8 + %outslot = getelementptr inbounds i32, i32* %rawmemout2, i64 %indvars.iv + %out = mul nsw i32 %inval, %inval + store i32 %out, i32* %outslot, align 8 + %indvars.iv.next4 = add nuw nsw i64 %indvars.iv, 1 + %exitcond = icmp eq i64 %indvars.iv.next4, 100 + br i1 %exitcond, label %return, label %for.body + +return: ; preds = %for.body + ret void +} + +attributes #0 = { nounwind uwtable } + +!0 = !{!1, !1, i32 0} +!1 = !{!"alias set 3: void*", !2} +!2 = distinct !{!2} + + +; CHECK: %MemRef_rawmemin1_end = load i32, i32* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @arrin, i64 0, i32 3, i64 0, i32 2) +; CHECK-NEXT: %MemRef_rawmemin1_begin = load i32, i32* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @arrin, i64 0, i32 3, i64 0, i32 1) +; CHECK-NEXT: %MemRef_rawmemin1_end_begin_delta = sub nsw i32 %MemRef_rawmemin1_end, %MemRef_rawmemin1_begin +; CHECK-NEXT: %MemRef_rawmemin1_size = add nsw i32 %MemRef_rawmemin1_end, 1 +; CHECK-NEXT: %MemRef_rawmemout2_end = load i32, i32* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @arrout, i64 0, i32 3, i64 0, i32 2) +; CHECK-NEXT: %MemRef_rawmemout2_begin = load i32, i32* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @arrout, i64 0, i32 3, i64 0, i32 1) +; CHECK-NEXT: %MemRef_rawmemout2_end_begin_delta = sub nsw i32 %MemRef_rawmemout2_end, %MemRef_rawmemout2_begin +; CHECK-NEXT: %MemRef_rawmemout2_size = add nsw i32 %MemRef_rawmemout2_end, 1 Index: test/ScopInfo/fortran_array_param_nonmalloc_nonvectored.ll =================================================================== --- test/ScopInfo/fortran_array_param_nonmalloc_nonvectored.ll +++ test/ScopInfo/fortran_array_param_nonmalloc_nonvectored.ll @@ -52,6 +52,7 @@ %tmp10 = mul i64 %tmp3, %tmp9 %tmp11 = sub i64 %tmp10, %tmp3 %tmp12 = getelementptr i32, i32* %tmp5, i64 %tmp11 + ; store store i32 1, i32* %tmp12, align 4 %tmp13 = icmp eq i32 %tmp8, %tmp6 %tmp14 = add i32 %tmp8, 1 @@ -64,4 +65,4 @@ ret void } -; CHECK: ReadAccess := [Reduction Type: NONE] [Fortran array descriptor: xs] [Scalar: 0] +; CHECK: MayWriteAccess := [Reduction Type: NONE] [Fortran array descriptor: xs] [Scalar: 0] \ No newline at end of file Index: test/ScopInfo/fortran_array_param_nonmalloc_nonvectored_read_and_write.ll =================================================================== --- /dev/null +++ test/ScopInfo/fortran_array_param_nonmalloc_nonvectored_read_and_write.ll @@ -0,0 +1,93 @@ +; RUN: opt %loadPolly -analyze -polly-detect-fortran-arrays \ +; RUN: -polly-scops -polly-allow-nonaffine -polly-ignore-aliasing < %s | FileCheck %s + +; PROGRAM main +; ... +; CONTAINS +; SUBROUTINE copy(xs, ys, n) +; IMPLICIT NONE +; INTEGER, DIMENSION(:), INTENT(INOUT) :: xs, ys +; INTEGER, INTENT(IN) :: n +; INTEGER :: i +; +; DO i = 1, n +; ys(i * i) = xs(i * i) +; END DO +; +; END SUBROUTINE copy +; END PROGRAM + +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_integer(kind=4)" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] } +%struct.descriptor_dimension = type { i64, i64, i64 } +%"struct.array1_integer(kind=4).0" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] } +%"struct.array1_integer(kind=4).1" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] } +%"struct.array1_integer(kind=4).2" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] } +%struct.__st_parameter_dt = type { %struct.__st_parameter_common, i64, i64*, i64*, i8*, i8*, i32, i32, i8*, i8*, i32, i32, i8*, [256 x i8], i32*, i64, i8*, i32, i32, i8*, i8*, i32, i32, i8*, i8*, i32, i32, i8*, i8*, i32, [4 x i8] } +%struct.__st_parameter_common = type { i32, i32, i8*, i32, i32, i8*, i32* } +%"struct.array1_integer(kind=4).3" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] } + +@0 = internal constant i32 10 +@.cst = private constant [12 x i8] c"program.f90\00", align 8 +@options.12.1603 = internal constant [8 x i32] [i32 68, i32 511, i32 0, i32 0, i32 0, i32 1, i32 0, i32 1], align 32 + +; Function Attrs: nounwind uwtable +define internal void @copy.1550(%"struct.array1_integer(kind=4)"* noalias %xs, %"struct.array1_integer(kind=4).0"* noalias %ys, i32* noalias %n) { +entry: + br label %entry.split + +entry.split: ; preds = %entry + %0 = getelementptr inbounds %"struct.array1_integer(kind=4).0", %"struct.array1_integer(kind=4).0"* %ys, i64 0, i32 3, i64 0, i32 0 + %1 = load i64, i64* %0, align 8 + %2 = icmp eq i64 %1, 0 + %3 = select i1 %2, i64 1, i64 %1 + %4 = bitcast %"struct.array1_integer(kind=4).0"* %ys to i32** + %5 = load i32*, i32** %4, align 8 + %6 = getelementptr inbounds %"struct.array1_integer(kind=4)", %"struct.array1_integer(kind=4)"* %xs, i64 0, i32 3, i64 0, i32 0 + %7 = load i64, i64* %6, align 8 + %8 = icmp eq i64 %7, 0 + %. = select i1 %8, i64 1, i64 %7 + %9 = bitcast %"struct.array1_integer(kind=4)"* %xs to i32** + %10 = load i32*, i32** %9, align 8 + %11 = load i32, i32* %n, align 4 + %12 = icmp sgt i32 %11, 0 + br i1 %12, label %"9.preheader", label %return + +"9.preheader": ; preds = %entry.split + br label %"9" + +"9": ; preds = %"9.preheader", %"9" + %13 = phi i32 [ %26, %"9" ], [ 1, %"9.preheader" ] + %14 = mul i32 %13, %13 + %15 = sext i32 %14 to i64 + %16 = mul i64 %3, %15 + %17 = sub i64 %16, %3 + %18 = mul i32 %13, %13 + %19 = sext i32 %18 to i64 + %20 = mul i64 %., %19 + %21 = sub i64 %20, %. + %22 = getelementptr i32, i32* %10, i64 %21 + ; load + %23 = load i32, i32* %22, align 4 + %24 = getelementptr i32, i32* %5, i64 %17 + ; write + store i32 %23, i32* %24, align 4 + %25 = icmp eq i32 %13, %11 + %26 = add i32 %13, 1 + br i1 %25, label %return.loopexit, label %"9" + +return.loopexit: ; preds = %"9" + br label %return + +return: ; preds = %return.loopexit, %entry.split + ret void +} + +; CHECK: ReadAccess := [Reduction Type: NONE] [Fortran array descriptor: xs] [Scalar: 0] +; CHECK-NEXT: [p_0_loaded_from_n] -> { Stmt_9[i0] -> MemRef0[o0] }; +; CHECK-NEXT: MayWriteAccess := [Reduction Type: NONE] [Fortran array descriptor: ys] [Scalar: 0] +; CHECK-NEXT: [p_0_loaded_from_n] -> { Stmt_9[i0] -> MemRef1[o0] };