Index: polly/trunk/include/polly/ScopDetection.h =================================================================== --- polly/trunk/include/polly/ScopDetection.h +++ polly/trunk/include/polly/ScopDetection.h @@ -156,6 +156,9 @@ /// @brief The region has at least one store instruction. bool hasStores; + /// @brief Flag to indicate the region has at least one unknown access. + bool HasUnknownAccess; + /// @brief The set of non-affine subregions in the region we analyze. NonAffineSubRegionSetTy NonAffineSubRegionSet; @@ -172,7 +175,7 @@ /// @brief Initialize a DetectionContext from scratch. DetectionContext(Region &R, AliasAnalysis &AA, bool Verify) : CurRegion(R), AST(AA), Verifying(Verify), Log(&R), hasLoads(false), - hasStores(false) {} + hasStores(false), HasUnknownAccess(false) {} /// @brief Initialize a DetectionContext with the data from @p DC. DetectionContext(const DetectionContext &&DC) @@ -181,7 +184,7 @@ Accesses(std::move(DC.Accesses)), NonAffineAccesses(std::move(DC.NonAffineAccesses)), ElementSize(std::move(DC.ElementSize)), hasLoads(DC.hasLoads), - hasStores(DC.hasStores), + hasStores(DC.hasStores), HasUnknownAccess(DC.HasUnknownAccess), NonAffineSubRegionSet(std::move(DC.NonAffineSubRegionSet)), BoxedLoopsSet(std::move(DC.BoxedLoopsSet)), RequiredILS(std::move(DC.RequiredILS)) { Index: polly/trunk/include/polly/ScopInfo.h =================================================================== --- polly/trunk/include/polly/ScopInfo.h +++ polly/trunk/include/polly/ScopInfo.h @@ -327,6 +327,9 @@ /// normal scalar array modeling. bool isPHIKind() const { return Kind == MK_PHI; }; + /// @brief Is this array info modeling an array? + bool isArrayKind() const { return Kind == MK_Array; }; + /// @brief Dump a readable representation to stderr. void dump() const; @@ -2052,6 +2055,12 @@ /// @brief The ScalarEvolution to help building Scop. ScalarEvolution *SE; + /// @brief Set of instructions that might read any memory location. + SmallVector GlobalReads; + + /// @brief Set of all accessed array base pointers. + SmallSetVector ArrayBasePointers; + // The Scop std::unique_ptr scop; @@ -2106,6 +2115,19 @@ const ScopDetection::BoxedLoopsSetTy *BoxedLoops, const InvariantLoadsSetTy &ScopRIL); + /// @brief Try to build a MemoryAccess for a call instruction. + /// + /// @param Inst The call instruction that access the memory + /// @param L The parent loop of the instruction + /// @param R The region on which to build the data access dictionary. + /// @param BoxedLoops The set of loops that are overapproximated in @p R. + /// @param ScopRIL The required invariant loads equivalence classes. + /// + /// @returns True if the access could be built, False otherwise. + bool buildAccessCallInst(MemAccInst Inst, Loop *L, Region *R, + const ScopDetection::BoxedLoopsSetTy *BoxedLoops, + const InvariantLoadsSetTy &ScopRIL); + /// @brief Build a single-dimensional parameteric sized MemoryAccess /// from the Load/Store instruction. /// Index: polly/trunk/include/polly/Support/ScopHelper.h =================================================================== --- polly/trunk/include/polly/Support/ScopHelper.h +++ polly/trunk/include/polly/Support/ScopHelper.h @@ -51,10 +51,10 @@ /// referenced object and should be passed by-value as it is small enough. /// /// This proxy can either represent a LoadInst instance, a StoreInst instance, -/// a MemIntrinsic instance (memset, memmove, memcpy) or a nullptr (only -/// creatable using the default constructor); never an Instruction that is -/// neither of the above mentioned. When representing a nullptr, only the -/// following methods are defined: +/// a MemIntrinsic instance (memset, memmove, memcpy), a CallInst instance or a +/// nullptr (only creatable using the default constructor); never an Instruction +/// that is neither of the above mentioned. When representing a nullptr, only +/// the following methods are defined: /// isNull(), isInstruction(), isLoad(), isStore(), ..., isMemTransferInst(), /// operator bool(), operator!() /// @@ -75,16 +75,17 @@ /* implicit */ MemAccInst(llvm::StoreInst &SI) : I(&SI) {} /* implicit */ MemAccInst(llvm::StoreInst *SI) : I(SI) {} /* implicit */ MemAccInst(llvm::MemIntrinsic *MI) : I(MI) {} + /* implicit */ MemAccInst(llvm::CallInst *CI) : I(CI) {} explicit MemAccInst(llvm::Instruction &I) : I(&I) { assert(isa(I)); } explicit MemAccInst(llvm::Instruction *I) : I(I) { assert(isa(I)); } static bool isa(const llvm::Value &V) { return llvm::isa(V) || llvm::isa(V) || - llvm::isa(V); + llvm::isa(V) || llvm::isa(V); } static bool isa(const llvm::Value *V) { return llvm::isa(V) || llvm::isa(V) || - llvm::isa(V); + llvm::isa(V) || llvm::isa(V); } static MemAccInst cast(llvm::Value &V) { return MemAccInst(llvm::cast(V)); @@ -140,6 +141,14 @@ I = MI; return *this; } + MemAccInst &operator=(llvm::CallInst &CI) { + I = &CI; + return *this; + } + MemAccInst &operator=(llvm::CallInst *CI) { + I = CI; + return *this; + } operator llvm::Instruction *() const { return asInstruction(); } explicit operator bool() const { return isInstruction(); } @@ -168,6 +177,8 @@ return asStore()->getValueOperand(); if (isMemIntrinsic()) return nullptr; + if (isCallInst()) + return nullptr; llvm_unreachable("Operation not supported on nullptr"); } llvm::Value *getPointerOperand() const { @@ -177,6 +188,8 @@ return asStore()->getPointerOperand(); if (isMemIntrinsic()) return asMemIntrinsic()->getDest(); + if (isCallInst()) + return nullptr; llvm_unreachable("Operation not supported on nullptr"); } @@ -187,6 +200,8 @@ return asStore()->getAlignment(); if (isMemIntrinsic()) return asMemIntrinsic()->getAlignment(); + if (isCallInst()) + return 0; llvm_unreachable("Operation not supported on nullptr"); } bool isVolatile() const { @@ -196,6 +211,8 @@ return asStore()->isVolatile(); if (isMemIntrinsic()) return asMemIntrinsic()->isVolatile(); + if (isCallInst()) + return false; llvm_unreachable("Operation not supported on nullptr"); } bool isSimple() const { @@ -205,6 +222,8 @@ return asStore()->isSimple(); if (isMemIntrinsic()) return !asMemIntrinsic()->isVolatile(); + if (isCallInst()) + return true; llvm_unreachable("Operation not supported on nullptr"); } llvm::AtomicOrdering getOrdering() const { @@ -214,6 +233,8 @@ return asStore()->getOrdering(); if (isMemIntrinsic()) return llvm::AtomicOrdering::NotAtomic; + if (isCallInst()) + return llvm::AtomicOrdering::NotAtomic; llvm_unreachable("Operation not supported on nullptr"); } bool isUnordered() const { @@ -224,6 +245,8 @@ // Copied from the Load/Store implementation of isUnordered: if (isMemIntrinsic()) return !asMemIntrinsic()->isVolatile(); + if (isCallInst()) + return true; llvm_unreachable("Operation not supported on nullptr"); } @@ -231,6 +254,7 @@ bool isInstruction() const { return I; } bool isLoad() const { return I && llvm::isa(I); } bool isStore() const { return I && llvm::isa(I); } + bool isCallInst() const { return I && llvm::isa(I); } bool isMemIntrinsic() const { return I && llvm::isa(I); } bool isMemSetInst() const { return I && llvm::isa(I); } bool isMemTransferInst() const { @@ -240,6 +264,7 @@ llvm::Instruction *asInstruction() const { return I; } llvm::LoadInst *asLoad() const { return llvm::cast(I); } llvm::StoreInst *asStore() const { return llvm::cast(I); } + llvm::CallInst *asCallInst() const { return llvm::cast(I); } llvm::MemIntrinsic *asMemIntrinsic() const { return llvm::cast(I); } Index: polly/trunk/lib/Analysis/ScopDetection.cpp =================================================================== --- polly/trunk/lib/Analysis/ScopDetection.cpp +++ polly/trunk/lib/Analysis/ScopDetection.cpp @@ -451,7 +451,8 @@ return true; if (auto *II = dyn_cast(&CI)) - return isValidIntrinsicInst(*II, Context); + if (isValidIntrinsicInst(*II, Context)) + return true; Function *CalledFunction = CI.getCalledFunction(); @@ -459,6 +460,41 @@ if (CalledFunction == 0) return false; + switch (AA->getModRefBehavior(CalledFunction)) { + case llvm::FMRB_UnknownModRefBehavior: + return false; + case llvm::FMRB_DoesNotAccessMemory: + case llvm::FMRB_OnlyReadsMemory: + // Implicitly disable delinearization since we have an unknown + // accesses with an unknown access function. + Context.HasUnknownAccess = true; + Context.AST.add(&CI); + return true; + case llvm::FMRB_OnlyReadsArgumentPointees: + case llvm::FMRB_OnlyAccessesArgumentPointees: + for (const auto &Arg : CI.arg_operands()) { + if (!Arg->getType()->isPointerTy()) + continue; + + // Bail if a pointer argument has a base address not known to + // ScalarEvolution. Note that a zero pointer is acceptable. + auto *ArgSCEV = SE->getSCEVAtScope(Arg, LI->getLoopFor(CI.getParent())); + if (ArgSCEV->isZero()) + continue; + + auto *BP = dyn_cast(SE->getPointerBase(ArgSCEV)); + if (!BP) + return false; + + // Implicitly disable delinearization since we have an unknown + // accesses with an unknown access function. + Context.HasUnknownAccess = true; + } + + Context.AST.add(&CI); + return true; + } + return false; } @@ -784,6 +820,11 @@ } bool ScopDetection::hasAffineMemoryAccesses(DetectionContext &Context) const { + // TODO: If we have an unknown access and other non-affine accesses we do + // not try to delinearize them for now. + if (Context.HasUnknownAccess && !Context.NonAffineAccesses.empty()) + return AllowNonAffine; + for (const SCEVUnknown *BasePointer : Context.NonAffineAccesses) if (!hasBaseAffineAccesses(Context, BasePointer)) { if (KeepGoing) Index: polly/trunk/lib/Analysis/ScopInfo.cpp =================================================================== --- polly/trunk/lib/Analysis/ScopInfo.cpp +++ polly/trunk/lib/Analysis/ScopInfo.cpp @@ -202,7 +202,7 @@ auto OldElementSize = DL.getTypeAllocSizeInBits(ElementType); auto NewElementSize = DL.getTypeAllocSizeInBits(NewElementType); - if (NewElementSize == OldElementSize) + if (NewElementSize == OldElementSize || NewElementSize == 0) return; if (NewElementSize % OldElementSize == 0 && NewElementSize < OldElementSize) { @@ -620,16 +620,22 @@ assert(MAI.isMemIntrinsic()); assert(Subscripts.size() == 2 && Sizes.size() == 0); - auto *LengthPWA = Statement->getPwAff(Subscripts[1]); - auto *LengthMap = isl_map_from_pw_aff(LengthPWA); - auto *RangeSpace = isl_space_range(isl_map_get_space(LengthMap)); - LengthMap = isl_map_apply_range(LengthMap, isl_map_lex_gt(RangeSpace)); - LengthMap = isl_map_lower_bound_si(LengthMap, isl_dim_out, 0, 0); auto *SubscriptPWA = Statement->getPwAff(Subscripts[0]); auto *SubscriptMap = isl_map_from_pw_aff(SubscriptPWA); + + isl_map *LengthMap; + if (Subscripts[1] == nullptr) { + LengthMap = isl_map_universe(isl_map_get_space(SubscriptMap)); + } else { + auto *LengthPWA = Statement->getPwAff(Subscripts[1]); + LengthMap = isl_map_from_pw_aff(LengthPWA); + auto *RangeSpace = isl_space_range(isl_map_get_space(LengthMap)); + LengthMap = isl_map_apply_range(LengthMap, isl_map_lex_gt(RangeSpace)); + } + LengthMap = isl_map_lower_bound_si(LengthMap, isl_dim_out, 0, 0); + LengthMap = isl_map_align_params(LengthMap, isl_map_get_space(SubscriptMap)); SubscriptMap = isl_map_align_params(SubscriptMap, isl_map_get_space(LengthMap)); - LengthMap = isl_map_align_params(LengthMap, isl_map_get_space(SubscriptMap)); LengthMap = isl_map_sum(LengthMap, SubscriptMap); AccessRelation = isl_map_set_tuple_id(LengthMap, isl_dim_in, getStatement()->getDomainId()); @@ -725,6 +731,7 @@ /// @brief Check if @p Expr is divisible by @p Size. static bool isDivisible(const SCEV *Expr, unsigned Size, ScalarEvolution &SE) { + assert(Size != 0); if (Size == 1) return true; @@ -3937,6 +3944,15 @@ auto *LengthVal = SE->getSCEVAtScope(Inst.asMemIntrinsic()->getLength(), L); assert(LengthVal); + // Check if the length val is actually affine or if we overapproximate it + InvariantLoadsSetTy AccessILS; + bool LengthIsAffine = isAffineExpr(R, LengthVal, *SE, nullptr, &AccessILS); + for (LoadInst *LInst : AccessILS) + if (!ScopRIL.count(LInst)) + LengthIsAffine = false; + if (!LengthIsAffine) + LengthVal = nullptr; + auto *DestPtrVal = Inst.asMemIntrinsic()->getDest(); assert(DestPtrVal); auto *DestAccFunc = SE->getSCEVAtScope(DestPtrVal, L); @@ -3965,6 +3981,51 @@ return true; } +bool ScopInfo::buildAccessCallInst( + MemAccInst Inst, Loop *L, Region *R, + const ScopDetection::BoxedLoopsSetTy *BoxedLoops, + const InvariantLoadsSetTy &ScopRIL) { + if (!Inst.isCallInst()) + return false; + + auto &CI = *Inst.asCallInst(); + if (CI.doesNotAccessMemory() || isIgnoredIntrinsic(&CI)) + return true; + + bool ReadOnly = false; + auto *AF = SE->getConstant(IntegerType::getInt64Ty(CI.getContext()), 0); + auto *CalledFunction = CI.getCalledFunction(); + switch (AA->getModRefBehavior(CalledFunction)) { + case llvm::FMRB_UnknownModRefBehavior: + llvm_unreachable("Unknown mod ref behaviour cannot be represented."); + case llvm::FMRB_DoesNotAccessMemory: + return true; + case llvm::FMRB_OnlyReadsMemory: + GlobalReads.push_back(&CI); + return true; + case llvm::FMRB_OnlyReadsArgumentPointees: + ReadOnly = true; + // Fall through + case llvm::FMRB_OnlyAccessesArgumentPointees: + auto AccType = ReadOnly ? MemoryAccess::READ : MemoryAccess::MAY_WRITE; + for (const auto &Arg : CI.arg_operands()) { + if (!Arg->getType()->isPointerTy()) + continue; + + auto *ArgSCEV = SE->getSCEVAtScope(Arg, L); + if (ArgSCEV->isZero()) + continue; + + auto *ArgBasePtr = cast(SE->getPointerBase(ArgSCEV)); + addArrayAccess(Inst, AccType, ArgBasePtr->getValue(), + ArgBasePtr->getType(), false, {AF}, {}, &CI); + } + return true; + } + + return true; +} + void ScopInfo::buildAccessSingleDim( MemAccInst Inst, Loop *L, Region *R, const ScopDetection::BoxedLoopsSetTy *BoxedLoops, @@ -4016,6 +4077,9 @@ if (buildAccessMemIntrinsic(Inst, L, R, BoxedLoops, ScopRIL)) return; + if (buildAccessCallInst(Inst, L, R, BoxedLoops, ScopRIL)) + return; + if (buildAccessMultiDimFixed(Inst, L, R, BoxedLoops, ScopRIL)) return; @@ -4152,6 +4216,7 @@ bool IsAffine, ArrayRef Subscripts, ArrayRef Sizes, Value *AccessValue) { + ArrayBasePointers.insert(BaseAddress); addMemoryAccess(MemAccInst.getParent(), MemAccInst, AccType, BaseAddress, ElementType, IsAffine, AccessValue, Subscripts, Sizes, ScopArrayInfo::MK_Array); @@ -4277,6 +4342,13 @@ buildAccessFunctions(R, *R.getExit(), *SD->getInsnToMemAccMap(&R), nullptr, /* IsExitBlock */ true); + // Create memory accesses for global reads since all arrays are now known. + auto *AF = SE->getConstant(IntegerType::getInt64Ty(SE->getContext()), 0); + for (auto *GlobalRead : GlobalReads) + for (auto *BP : ArrayBasePointers) + addArrayAccess(MemAccInst(GlobalRead), MemoryAccess::READ, BP, + BP->getType(), false, {AF}, {}, GlobalRead); + scop->init(*AA, AC, *SD, *DT, *LI); } Index: polly/trunk/lib/CodeGen/IRBuilder.cpp =================================================================== --- polly/trunk/lib/CodeGen/IRBuilder.cpp +++ polly/trunk/lib/CodeGen/IRBuilder.cpp @@ -135,7 +135,11 @@ if (!MemInst) return; - auto *PtrSCEV = SE->getSCEV(MemInst.getPointerOperand()); + auto *Ptr = MemInst.getPointerOperand(); + if (!Ptr) + return; + + auto *PtrSCEV = SE->getSCEV(Ptr); auto *BaseSCEV = SE->getPointerBase(PtrSCEV); auto *SU = dyn_cast(BaseSCEV); Index: polly/trunk/test/ScopDetect/mod_ref_read_pointer.ll =================================================================== --- polly/trunk/test/ScopDetect/mod_ref_read_pointer.ll +++ polly/trunk/test/ScopDetect/mod_ref_read_pointer.ll @@ -0,0 +1,41 @@ +; RUN: opt %loadPolly -basicaa -polly-detect -analyze < %s | FileCheck %s +; +; CHECK: Valid Region for Scop: for.cond => for.end +; +; #pragma readonly +; int func(int *A); +; +; void jd(int *A) { +; for (int i = 0; i < 1024; i++) +; A[i + 2] = func(A); +; } +; +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +declare i32 @func(i32* %A) #1 + +define void @jd(i32* %A) { +entry: + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ] + %exitcond = icmp ne i64 %indvars.iv, 1024 + br i1 %exitcond, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %call = call i32 @func(i32* %A) + %tmp = add nsw i64 %indvars.iv, 2 + %arrayidx = getelementptr inbounds i32, i32* %A, i64 %tmp + store i32 %call, i32* %arrayidx, align 4 + br label %for.inc + +for.inc: ; preds = %for.body + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + br label %for.cond + +for.end: ; preds = %for.cond + ret void +} + +attributes #1 = { nounwind readonly } Index: polly/trunk/test/ScopInfo/mod_ref_access_pointee_arguments.ll =================================================================== --- polly/trunk/test/ScopInfo/mod_ref_access_pointee_arguments.ll +++ polly/trunk/test/ScopInfo/mod_ref_access_pointee_arguments.ll @@ -0,0 +1,56 @@ +; RUN: opt %loadPolly -basicaa -polly-scops -analyze < %s | FileCheck %s +; RUN: opt %loadPolly -basicaa -polly-codegen -disable-output < %s +; +; Verify that we model the may-write access of the prefetch intrinsic +; correctly, thus that A is accessed by it but B is not. +; +; CHECK: Stmt_for_body +; CHECK-NEXT: Domain := +; CHECK-NEXT: { Stmt_for_body[i0] : 0 <= i0 <= 1023 }; +; CHECK-NEXT: Schedule := +; CHECK-NEXT: { Stmt_for_body[i0] -> [i0] }; +; CHECK-NEXT: MayWriteAccess := [Reduction Type: NONE] +; CHECK-NEXT: { Stmt_for_body[i0] -> MemRef_A[o0] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] +; CHECK-NEXT: { Stmt_for_body[i0] -> MemRef_B[i0] }; +; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] +; CHECK-NEXT: { Stmt_for_body[i0] -> MemRef_A[i0] }; +; +; void jd(int *restirct A, int *restrict B) { +; for (int i = 0; i < 1024; i++) { +; @llvm.prefetch(A); +; A[i] = B[i]; +; } +; } +; +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +define void @jd(i32* noalias %A, i32* noalias %B) { +entry: + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ] + %exitcond = icmp ne i64 %indvars.iv, 1024 + br i1 %exitcond, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv + %arrayidx2 = getelementptr inbounds i32, i32* %B, i64 %indvars.iv + %bc = bitcast i32* %arrayidx to i8* + call void @f(i8* %bc, i32 1, i32 1, i32 1) + %tmp = load i32, i32* %arrayidx2 + store i32 %tmp, i32* %arrayidx, align 4 + br label %for.inc + +for.inc: ; preds = %for.body + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + br label %for.cond + +for.end: ; preds = %for.cond + ret void +} + +declare void @f(i8*, i32, i32, i32) #0 + +attributes #0 = { argmemonly nounwind } Index: polly/trunk/test/ScopInfo/mod_ref_read_pointee_arguments.ll =================================================================== --- polly/trunk/test/ScopInfo/mod_ref_read_pointee_arguments.ll +++ polly/trunk/test/ScopInfo/mod_ref_read_pointee_arguments.ll @@ -0,0 +1,65 @@ +; RUN: opt %loadPolly -basicaa -polly-scops -analyze < %s | FileCheck %s +; RUN: opt %loadPolly -basicaa -polly-codegen -disable-output < %s +; +; Verify that we model the read access of the gcread intrinsic +; correctly, thus that A is read by it but B is not. +; +; CHECK: Stmt_for_body +; CHECK-NEXT: Domain := +; CHECK-NEXT: { Stmt_for_body[i0] : 0 <= i0 <= 1023 }; +; CHECK-NEXT: Schedule := +; CHECK-NEXT: { Stmt_for_body[i0] -> [i0] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] +; CHECK-NEXT: { Stmt_for_body[i0] -> MemRef_A[o0] }; +; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] +; CHECK-NEXT: { Stmt_for_body[i0] -> MemRef_dummyloc[0] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] +; CHECK-NEXT: { Stmt_for_body[i0] -> MemRef_B[i0] }; +; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] +; CHECK-NEXT: { Stmt_for_body[i0] -> MemRef_A[i0] }; +; +; void jd(int *restirct A, int *restrict B) { +; char **dummyloc; +; for (int i = 0; i < 1024; i++) { +; char *dummy = @llvm.gcread(A, nullptr); +; *dummyloc = dummy; +; A[i] = B[i]; +; } +; } +; +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +define void @jd(i32* noalias %A, i32* noalias %B) gc "dummy" { +entry: + %dummyloc = alloca i8* + br label %entry.split + +entry.split: + br label %for.cond + +for.cond: ; preds = %for.inc, %entry.split + %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry.split ] + %exitcond = icmp ne i64 %indvars.iv, 1024 + br i1 %exitcond, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv + %arrayidx2 = getelementptr inbounds i32, i32* %B, i64 %indvars.iv + %bc = bitcast i32* %arrayidx to i8* + %dummy = call i8* @f(i8* %bc, i8** null) + store i8* %dummy, i8** %dummyloc, align 4 + %tmp = load i32, i32* %arrayidx2 + store i32 %tmp, i32* %arrayidx, align 4 + br label %for.inc + +for.inc: ; preds = %for.body + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + br label %for.cond + +for.end: ; preds = %for.cond + ret void +} + +declare i8* @f(i8*, i8**) #0 + +attributes #0 = { argmemonly readonly nounwind } Index: polly/trunk/test/ScopInfo/mod_ref_read_pointer.ll =================================================================== --- polly/trunk/test/ScopInfo/mod_ref_read_pointer.ll +++ polly/trunk/test/ScopInfo/mod_ref_read_pointer.ll @@ -0,0 +1,52 @@ +; RUN: opt %loadPolly -basicaa -polly-scops -analyze < %s | FileCheck %s +; RUN: opt %loadPolly -basicaa -polly-codegen -disable-output < %s +; +; Check that we assume the call to func has a read on the whole A array. +; +; CHECK: Stmt_for_body +; CHECK-NEXT: Domain := +; CHECK-NEXT: { Stmt_for_body[i0] : 0 <= i0 <= 1023 }; +; CHECK-NEXT: Schedule := +; CHECK-NEXT: { Stmt_for_body[i0] -> [i0] }; +; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] +; CHECK-NEXT: { Stmt_for_body[i0] -> MemRef_A[2 + i0] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] +; CHECK-NEXT: { Stmt_for_body[i0] -> MemRef_A[o0] }; +; +; #pragma readonly +; int func(int *A); +; +; void jd(int *A) { +; for (int i = 0; i < 1024; i++) +; A[i + 2] = func(A); +; } +; +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +define void @jd(i32* %A) { +entry: + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ] + %exitcond = icmp ne i64 %indvars.iv, 1024 + br i1 %exitcond, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %call = call i32 @func(i32* %A) #2 + %tmp = add nsw i64 %indvars.iv, 2 + %arrayidx = getelementptr inbounds i32, i32* %A, i64 %tmp + store i32 %call, i32* %arrayidx, align 4 + br label %for.inc + +for.inc: ; preds = %for.body + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + br label %for.cond + +for.end: ; preds = %for.cond + ret void +} + +declare i32 @func(i32*) #1 + +attributes #1 = { nounwind readonly } Index: polly/trunk/test/ScopInfo/mod_ref_read_pointers.ll =================================================================== --- polly/trunk/test/ScopInfo/mod_ref_read_pointers.ll +++ polly/trunk/test/ScopInfo/mod_ref_read_pointers.ll @@ -0,0 +1,60 @@ +; RUN: opt %loadPolly -basicaa -polly-scops -analyze < %s | FileCheck %s +; RUN: opt %loadPolly -basicaa -polly-codegen -disable-output < %s +; +; Check that the call to func will "read" not only the A array but also the +; B array. The reason is the readonly annotation of func. +; +; CHECK: Stmt_for_body +; CHECK-NEXT: Domain := +; CHECK-NEXT: { Stmt_for_body[i0] : 0 <= i0 <= 1023 }; +; CHECK-NEXT: Schedule := +; CHECK-NEXT: { Stmt_for_body[i0] -> [i0] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] +; CHECK-NEXT: { Stmt_for_body[i0] -> MemRef_B[i0] }; +; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] +; CHECK-NEXT: { Stmt_for_body[i0] -> MemRef_A[2 + i0] }; +; CHECK-DAG: ReadAccess := [Reduction Type: NONE] +; CHECK-DAG: { Stmt_for_body[i0] -> MemRef_B[o0] }; +; CHECK-DAG: ReadAccess := [Reduction Type: NONE] +; CHECK-DAG: { Stmt_for_body[i0] -> MemRef_A[o0] }; +; +; #pragma readonly +; int func(int *A); +; +; void jd(int *restrict A, int *restrict B) { +; for (int i = 0; i < 1024; i++) +; A[i + 2] = func(A) + B[i]; +; } +; +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +define void @jd(i32* noalias %A, i32* noalias %B) { +entry: + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ] + %exitcond = icmp ne i64 %indvars.iv, 1024 + br i1 %exitcond, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %call = call i32 @func(i32* %A) + %arrayidx = getelementptr inbounds i32, i32* %B, i64 %indvars.iv + %tmp = load i32, i32* %arrayidx, align 4 + %add = add nsw i32 %call, %tmp + %tmp2 = add nsw i64 %indvars.iv, 2 + %arrayidx3 = getelementptr inbounds i32, i32* %A, i64 %tmp2 + store i32 %add, i32* %arrayidx3, align 4 + br label %for.inc + +for.inc: ; preds = %for.body + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + br label %for.cond + +for.end: ; preds = %for.cond + ret void +} + +declare i32 @func(i32*) #1 + +attributes #1 = { nounwind readonly } Index: polly/trunk/test/ScopInfo/multidim_2d_with_modref_call.ll =================================================================== --- polly/trunk/test/ScopInfo/multidim_2d_with_modref_call.ll +++ polly/trunk/test/ScopInfo/multidim_2d_with_modref_call.ll @@ -0,0 +1,179 @@ +; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s +; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine -analyze < %s | FileCheck %s --check-prefix=NONAFFINE + +; TODO: We should delinearize the accesses despite the use in a call to a +; readonly function. For now we verify we do not delinearize them though. + +; CHECK: Function: ham +; CHECK-NEXT: Region: %bb12---%bb28 +; CHECK-NEXT: Max Loop Depth: 1 +; CHECK-NEXT: Invariant Accesses: { +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb12[] -> MemRef_arg1[0] }; +; CHECK-NEXT: Execution Context: [tmp14, p_1] -> { : } +; CHECK-NEXT: } +; CHECK-NEXT: Context: +; CHECK-NEXT: [tmp14, p_1] -> { : -9223372036854775808 <= tmp14 <= 9223372036854775807 and -9223372036854775808 <= p_1 <= 9223372036854775807 } +; CHECK-NEXT: Assumed Context: +; CHECK-NEXT: [tmp14, p_1] -> { : } +; CHECK-NEXT: Boundary Context: +; CHECK-NEXT: [tmp14, p_1] -> { : tmp14 <= 1152921504606846976 and (tmp14 <= 0 or (tmp14 > 0 and -1152921504606846976 <= p_1 <= 1152921504606846976 - tmp14)) } +; CHECK-NEXT: p0: %tmp14 +; CHECK-NEXT: p1: {0,+,(0 smax %tmp)}<%bb12> +; CHECK-NEXT: Arrays { +; CHECK-NEXT: i64 MemRef_tmp13; // Element size 8 +; CHECK-NEXT: i64 MemRef_arg1[*]; // Element size 8 +; CHECK-NEXT: double MemRef_arg4[*]; // Element size 8 +; CHECK-NEXT: } +; CHECK-NEXT: Arrays (Bounds as pw_affs) { +; CHECK-NEXT: i64 MemRef_tmp13; // Element size 8 +; CHECK-NEXT: i64 MemRef_arg1[*]; // Element size 8 +; CHECK-NEXT: double MemRef_arg4[*]; // Element size 8 +; CHECK-NEXT: } +; CHECK-NEXT: Alias Groups (0): +; CHECK-NEXT: n/a +; CHECK-NEXT: Statements { +; CHECK-NEXT: Stmt_bb12 +; CHECK-NEXT: Domain := +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb12[] }; +; CHECK-NEXT: Schedule := +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb12[] -> [0, 0] }; +; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb12[] -> MemRef_tmp13[] }; +; CHECK-NEXT: Stmt_bb17 +; CHECK-NEXT: Domain := +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb17[i0] : 0 <= i0 < tmp14 }; +; CHECK-NEXT: Schedule := +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb17[i0] -> [1, i0] }; +; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb17[i0] -> MemRef_arg4[p_1 + i0] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb17[i0] -> MemRef_arg1[o0] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb17[i0] -> MemRef_arg4[o0] }; +; CHECK-NEXT: } + + +; NONAFFINE: Function: ham +; NONAFFINE-NEXT: Region: %bb5---%bb32 +; NONAFFINE-NEXT: Max Loop Depth: 2 +; NONAFFINE-NEXT: Invariant Accesses: { +; NONAFFINE-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb5[] -> MemRef_arg[0] }; +; NONAFFINE-NEXT: Execution Context: [tmp9, tmp14] -> { : } +; NONAFFINE-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb12[i0] -> MemRef_arg1[0] }; +; NONAFFINE-NEXT: Execution Context: [tmp9, tmp14] -> { : } +; NONAFFINE-NEXT: } +; NONAFFINE-NEXT: Context: +; NONAFFINE-NEXT: [tmp9, tmp14] -> { : -9223372036854775808 <= tmp9 <= 9223372036854775807 and -9223372036854775808 <= tmp14 <= 9223372036854775807 } +; NONAFFINE-NEXT: Assumed Context: +; NONAFFINE-NEXT: [tmp9, tmp14] -> { : } +; NONAFFINE-NEXT: Boundary Context: +; NONAFFINE-NEXT: [tmp9, tmp14] -> { : } +; NONAFFINE-NEXT: p0: %tmp9 +; NONAFFINE-NEXT: p1: %tmp14 +; NONAFFINE-NEXT: Arrays { +; NONAFFINE-NEXT: i64 MemRef_arg1[*]; // Element size 8 +; NONAFFINE-NEXT: i64 MemRef_arg[*]; // Element size 8 +; NONAFFINE-NEXT: i64 MemRef_tmp7; // Element size 8 +; NONAFFINE-NEXT: i64 MemRef_tmp8; // Element size 8 +; NONAFFINE-NEXT: double MemRef_arg4[*]; // Element size 8 +; NONAFFINE-NEXT: } +; NONAFFINE-NEXT: Arrays (Bounds as pw_affs) { +; NONAFFINE-NEXT: i64 MemRef_arg1[*]; // Element size 8 +; NONAFFINE-NEXT: i64 MemRef_arg[*]; // Element size 8 +; NONAFFINE-NEXT: i64 MemRef_tmp7; // Element size 8 +; NONAFFINE-NEXT: i64 MemRef_tmp8; // Element size 8 +; NONAFFINE-NEXT: double MemRef_arg4[*]; // Element size 8 +; NONAFFINE-NEXT: } +; NONAFFINE-NEXT: Alias Groups (0): +; NONAFFINE-NEXT: n/a +; NONAFFINE-NEXT: Statements { +; NONAFFINE-NEXT: Stmt_bb5 +; NONAFFINE-NEXT: Domain := +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb5[] }; +; NONAFFINE-NEXT: Schedule := +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb5[] -> [0, 0, 0] }; +; NONAFFINE-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb5[] -> MemRef_tmp7[] }; +; NONAFFINE-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb5[] -> MemRef_tmp8[] }; +; NONAFFINE-NEXT: Stmt_bb17 +; NONAFFINE-NEXT: Domain := +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb17[i0, i1] : 0 <= i0 < tmp9 and 0 <= i1 < tmp14 }; +; NONAFFINE-NEXT: Schedule := +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> [1, i0, i1] }; +; NONAFFINE-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_tmp7[] }; +; NONAFFINE-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_tmp8[] }; +; NONAFFINE-NEXT: MayWriteAccess := [Reduction Type: NONE] [Scalar: 0] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_arg4[o0] : -1152921504606846976 <= o0 <= 1152921504606846975 }; +; NONAFFINE-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_arg1[o0] }; +; NONAFFINE-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_arg[o0] }; +; NONAFFINE-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_arg4[o0] }; + +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" + +define void @ham(i64* noalias %arg, i64* noalias %arg1, i64* noalias %arg2, i64* noalias %arg3, [1000 x double]* noalias %arg4) unnamed_addr { +bb: + br label %bb5 + +bb5: ; preds = %bb + %tmp = load i64, i64* %arg1, align 8 + %tmp6 = icmp slt i64 %tmp, 0 + %tmp7 = select i1 %tmp6, i64 0, i64 %tmp + %tmp8 = xor i64 %tmp7, -1 + %tmp9 = load i64, i64* %arg, align 8 + %tmp10 = icmp sgt i64 %tmp9, 0 + br i1 %tmp10, label %bb11, label %bb32 + +bb11: ; preds = %bb5 + br label %bb12 + +bb12: ; preds = %bb28, %bb11 + %tmp13 = phi i64 [ %tmp30, %bb28 ], [ 1, %bb11 ] + %tmp14 = load i64, i64* %arg1, align 8 + %tmp15 = icmp sgt i64 %tmp14, 0 + br i1 %tmp15, label %bb16, label %bb28 + +bb16: ; preds = %bb12 + br label %bb17 + +bb17: ; preds = %bb17, %bb16 + %tmp18 = phi i64 [ %tmp26, %bb17 ], [ 1, %bb16 ] + %tmp19 = mul i64 %tmp13, %tmp7 + %tmp20 = add i64 %tmp19, %tmp8 + %tmp21 = add i64 %tmp20, %tmp18 + %tmp22 = add i64 %tmp18, %tmp13 + %tmp23 = sitofp i64 %tmp22 to double + %tmp24 = getelementptr [1000 x double], [1000 x double]* %arg4, i64 0, i64 %tmp21 + %call = call double @func(double* %tmp24) #2 + %sum = fadd double %call, %tmp23 + store double %sum, double* %tmp24, align 8 + %tmp25 = icmp eq i64 %tmp18, %tmp14 + %tmp26 = add i64 %tmp18, 1 + br i1 %tmp25, label %bb27, label %bb17 + +bb27: ; preds = %bb17 + br label %bb28 + +bb28: ; preds = %bb27, %bb12 + %tmp29 = icmp eq i64 %tmp13, %tmp9 + %tmp30 = add i64 %tmp13, 1 + br i1 %tmp29, label %bb31, label %bb12 + +bb31: ; preds = %bb28 + br label %bb32 + +bb32: ; preds = %bb31, %bb5 + ret void +} + +declare double @func(double*) #1 + +attributes #1 = { nounwind readonly } Index: polly/trunk/test/ScopInfo/multidim_2d_with_modref_call_2.ll =================================================================== --- polly/trunk/test/ScopInfo/multidim_2d_with_modref_call_2.ll +++ polly/trunk/test/ScopInfo/multidim_2d_with_modref_call_2.ll @@ -0,0 +1,172 @@ +; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s +; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine -analyze < %s | FileCheck %s --check-prefix=NONAFFINE + +; TODO: We should delinearize the accesses despite the use in a call to a +; readonly function. For now we verify we do not delinearize them though. + +; CHECK: Function: ham +; CHECK-NEXT: Region: %bb12---%bb28 +; CHECK-NEXT: Max Loop Depth: 1 +; CHECK-NEXT: Invariant Accesses: { +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb12[] -> MemRef_arg1[0] }; +; CHECK-NEXT: Execution Context: [tmp14, p_1] -> { : } +; CHECK-NEXT: } +; CHECK-NEXT: Context: +; CHECK-NEXT: [tmp14, p_1] -> { : -9223372036854775808 <= tmp14 <= 9223372036854775807 and -9223372036854775808 <= p_1 <= 9223372036854775807 } +; CHECK-NEXT: Assumed Context: +; CHECK-NEXT: [tmp14, p_1] -> { : } +; CHECK-NEXT: Boundary Context: +; CHECK-NEXT: [tmp14, p_1] -> { : tmp14 <= 1152921504606846976 and (tmp14 <= 0 or (tmp14 > 0 and -1152921504606846976 <= p_1 <= 1152921504606846976 - tmp14)) } +; CHECK-NEXT: p0: %tmp14 +; CHECK-NEXT: p1: {0,+,(0 smax %tmp)}<%bb12> +; CHECK-NEXT: Arrays { +; CHECK-NEXT: i64 MemRef_tmp13; // Element size 8 +; CHECK-NEXT: i64 MemRef_arg1[*]; // Element size 8 +; CHECK-NEXT: [1000 x double]* MemRef_arg4[*]; // Element size 8 +; CHECK-NEXT: } +; CHECK-NEXT: Arrays (Bounds as pw_affs) { +; CHECK-NEXT: i64 MemRef_tmp13; // Element size 8 +; CHECK-NEXT: i64 MemRef_arg1[*]; // Element size 8 +; CHECK-NEXT: [1000 x double]* MemRef_arg4[*]; // Element size 8 +; CHECK-NEXT: } +; CHECK-NEXT: Alias Groups (0): +; CHECK-NEXT: n/a +; CHECK-NEXT: Statements { +; CHECK-NEXT: Stmt_bb12 +; CHECK-NEXT: Domain := +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb12[] }; +; CHECK-NEXT: Schedule := +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb12[] -> [0, 0] }; +; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb12[] -> MemRef_tmp13[] }; +; CHECK-NEXT: Stmt_bb17 +; CHECK-NEXT: Domain := +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb17[i0] : 0 <= i0 < tmp14 }; +; CHECK-NEXT: Schedule := +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb17[i0] -> [1, i0] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb17[i0] -> MemRef_arg4[o0] }; +; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb17[i0] -> MemRef_arg4[p_1 + i0] }; +; CHECK-NEXT: } + + +; NONAFFINE: Function: ham +; NONAFFINE-NEXT: Region: %bb5---%bb32 +; NONAFFINE-NEXT: Max Loop Depth: 2 +; NONAFFINE-NEXT: Invariant Accesses: { +; NONAFFINE-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb5[] -> MemRef_arg[0] }; +; NONAFFINE-NEXT: Execution Context: [tmp9, tmp14] -> { : } +; NONAFFINE-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb12[i0] -> MemRef_arg1[0] }; +; NONAFFINE-NEXT: Execution Context: [tmp9, tmp14] -> { : } +; NONAFFINE-NEXT: } +; NONAFFINE-NEXT: Context: +; NONAFFINE-NEXT: [tmp9, tmp14] -> { : -9223372036854775808 <= tmp9 <= 9223372036854775807 and -9223372036854775808 <= tmp14 <= 9223372036854775807 } +; NONAFFINE-NEXT: Assumed Context: +; NONAFFINE-NEXT: [tmp9, tmp14] -> { : } +; NONAFFINE-NEXT: Boundary Context: +; NONAFFINE-NEXT: [tmp9, tmp14] -> { : } +; NONAFFINE-NEXT: p0: %tmp9 +; NONAFFINE-NEXT: p1: %tmp14 +; NONAFFINE-NEXT: Arrays { +; NONAFFINE-NEXT: i64 MemRef_arg1[*]; // Element size 8 +; NONAFFINE-NEXT: i64 MemRef_arg[*]; // Element size 8 +; NONAFFINE-NEXT: i64 MemRef_tmp7; // Element size 8 +; NONAFFINE-NEXT: i64 MemRef_tmp8; // Element size 8 +; NONAFFINE-NEXT: [1000 x double]* MemRef_arg4[*]; // Element size 8 +; NONAFFINE-NEXT: } +; NONAFFINE-NEXT: Arrays (Bounds as pw_affs) { +; NONAFFINE-NEXT: i64 MemRef_arg1[*]; // Element size 8 +; NONAFFINE-NEXT: i64 MemRef_arg[*]; // Element size 8 +; NONAFFINE-NEXT: i64 MemRef_tmp7; // Element size 8 +; NONAFFINE-NEXT: i64 MemRef_tmp8; // Element size 8 +; NONAFFINE-NEXT: [1000 x double]* MemRef_arg4[*]; // Element size 8 +; NONAFFINE-NEXT: } +; NONAFFINE-NEXT: Alias Groups (0): +; NONAFFINE-NEXT: n/a +; NONAFFINE-NEXT: Statements { +; NONAFFINE-NEXT: Stmt_bb5 +; NONAFFINE-NEXT: Domain := +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb5[] }; +; NONAFFINE-NEXT: Schedule := +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb5[] -> [0, 0, 0] }; +; NONAFFINE-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb5[] -> MemRef_tmp7[] }; +; NONAFFINE-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb5[] -> MemRef_tmp8[] }; +; NONAFFINE-NEXT: Stmt_bb17 +; NONAFFINE-NEXT: Domain := +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb17[i0, i1] : 0 <= i0 < tmp9 and 0 <= i1 < tmp14 }; +; NONAFFINE-NEXT: Schedule := +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> [1, i0, i1] }; +; NONAFFINE-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_tmp7[] }; +; NONAFFINE-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_tmp8[] }; +; NONAFFINE-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_arg4[o0] }; +; NONAFFINE-NEXT: MayWriteAccess := [Reduction Type: NONE] [Scalar: 0] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_arg4[o0] : -1152921504606846976 <= o0 <= 1152921504606846975 }; +; NONAFFINE-NEXT: } + +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" + +define void @ham(i64* noalias %arg, i64* noalias %arg1, i64* noalias %arg2, i64* noalias %arg3, [1000 x double]* noalias %arg4) gc "dummy" { +bb: + br label %bb5 + +bb5: ; preds = %bb + %tmp = load i64, i64* %arg1, align 8 + %tmp6 = icmp slt i64 %tmp, 0 + %tmp7 = select i1 %tmp6, i64 0, i64 %tmp + %tmp8 = xor i64 %tmp7, -1 + %tmp9 = load i64, i64* %arg, align 8 + %tmp10 = icmp sgt i64 %tmp9, 0 + br i1 %tmp10, label %bb11, label %bb32 + +bb11: ; preds = %bb5 + br label %bb12 + +bb12: ; preds = %bb28, %bb11 + %tmp13 = phi i64 [ %tmp30, %bb28 ], [ 1, %bb11 ] + %tmp14 = load i64, i64* %arg1, align 8 + %tmp15 = icmp sgt i64 %tmp14, 0 + br i1 %tmp15, label %bb16, label %bb28 + +bb16: ; preds = %bb12 + br label %bb17 + +bb17: ; preds = %bb17, %bb16 + %tmp18 = phi i64 [ %tmp26, %bb17 ], [ 1, %bb16 ] + %tmp19 = mul i64 %tmp13, %tmp7 + %tmp20 = add i64 %tmp19, %tmp8 + %tmp21 = add i64 %tmp20, %tmp18 + %tmp22 = add i64 %tmp18, %tmp13 + %tmp23 = sitofp i64 %tmp22 to double + %tmp24 = getelementptr [1000 x double], [1000 x double]* %arg4, i64 0, i64 %tmp21 + %bc = bitcast double* %tmp24 to i8* + %dummy = call i8* @llvm.gcread(i8* %bc, i8** null) + store double %tmp23, double* %tmp24, align 8 + %tmp25 = icmp eq i64 %tmp18, %tmp14 + %tmp26 = add i64 %tmp18, 1 + br i1 %tmp25, label %bb27, label %bb17 + +bb27: ; preds = %bb17 + br label %bb28 + +bb28: ; preds = %bb27, %bb12 + %tmp29 = icmp eq i64 %tmp13, %tmp9 + %tmp30 = add i64 %tmp13, 1 + br i1 %tmp29, label %bb31, label %bb12 + +bb31: ; preds = %bb28 + br label %bb32 + +bb32: ; preds = %bb31, %bb5 + ret void +} + +declare i8* @llvm.gcread(i8*, i8**) Index: polly/trunk/test/ScopInfo/multidim_fortran_2d_with_modref_call.ll =================================================================== --- polly/trunk/test/ScopInfo/multidim_fortran_2d_with_modref_call.ll +++ polly/trunk/test/ScopInfo/multidim_fortran_2d_with_modref_call.ll @@ -0,0 +1,180 @@ +; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s +; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine -analyze < %s | FileCheck %s --check-prefix=NONAFFINE + +; TODO: We should delinearize the accesses despite the use in a call to a +; readonly function. For now we verify we do not delinearize them though. + +; CHECK: Function: ham +; CHECK-NEXT: Region: %bb12---%bb28 +; CHECK-NEXT: Max Loop Depth: 1 +; CHECK-NEXT: Invariant Accesses: { +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb12[] -> MemRef_arg1[0] }; +; CHECK-NEXT: Execution Context: [tmp14, p_1] -> { : } +; CHECK-NEXT: } +; CHECK-NEXT: Context: +; CHECK-NEXT: [tmp14, p_1] -> { : -9223372036854775808 <= tmp14 <= 9223372036854775807 and -9223372036854775808 <= p_1 <= 9223372036854775807 } +; CHECK-NEXT: Assumed Context: +; CHECK-NEXT: [tmp14, p_1] -> { : } +; CHECK-NEXT: Boundary Context: +; CHECK-NEXT: [tmp14, p_1] -> { : tmp14 <= 1152921504606846976 and (tmp14 <= 0 or (tmp14 > 0 and -1152921504606846976 <= p_1 <= 1152921504606846976 - tmp14)) } +; CHECK-NEXT: p0: %tmp14 +; CHECK-NEXT: p1: {0,+,(0 smax %tmp)}<%bb12> +; CHECK-NEXT: Arrays { +; CHECK-NEXT: i64 MemRef_tmp13; // Element size 8 +; CHECK-NEXT: i64 MemRef_arg1[*]; // Element size 8 +; CHECK-NEXT: double MemRef_arg4[*]; // Element size 8 +; CHECK-NEXT: } +; CHECK-NEXT: Arrays (Bounds as pw_affs) { +; CHECK-NEXT: i64 MemRef_tmp13; // Element size 8 +; CHECK-NEXT: i64 MemRef_arg1[*]; // Element size 8 +; CHECK-NEXT: double MemRef_arg4[*]; // Element size 8 +; CHECK-NEXT: } +; CHECK-NEXT: Alias Groups (0): +; CHECK-NEXT: n/a +; CHECK-NEXT: Statements { +; CHECK-NEXT: Stmt_bb12 +; CHECK-NEXT: Domain := +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb12[] }; +; CHECK-NEXT: Schedule := +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb12[] -> [0, 0] }; +; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb12[] -> MemRef_tmp13[] }; +; CHECK-NEXT: Stmt_bb17 +; CHECK-NEXT: Domain := +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb17[i0] : 0 <= i0 < tmp14 }; +; CHECK-NEXT: Schedule := +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb17[i0] -> [1, i0] }; +; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb17[i0] -> MemRef_arg4[p_1 + i0] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb17[i0] -> MemRef_arg1[o0] }; +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; CHECK-NEXT: [tmp14, p_1] -> { Stmt_bb17[i0] -> MemRef_arg4[o0] }; +; CHECK-NEXT: } + +; NONAFFINE: Function: ham +; NONAFFINE-NEXT: Region: %bb5---%bb32 +; NONAFFINE-NEXT: Max Loop Depth: 2 +; NONAFFINE-NEXT: Invariant Accesses: { +; NONAFFINE-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb5[] -> MemRef_arg[0] }; +; NONAFFINE-NEXT: Execution Context: [tmp9, tmp14] -> { : } +; NONAFFINE-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb12[i0] -> MemRef_arg1[0] }; +; NONAFFINE-NEXT: Execution Context: [tmp9, tmp14] -> { : } +; NONAFFINE-NEXT: } +; NONAFFINE-NEXT: Context: +; NONAFFINE-NEXT: [tmp9, tmp14] -> { : -9223372036854775808 <= tmp9 <= 9223372036854775807 and -9223372036854775808 <= tmp14 <= 9223372036854775807 } +; NONAFFINE-NEXT: Assumed Context: +; NONAFFINE-NEXT: [tmp9, tmp14] -> { : } +; NONAFFINE-NEXT: Boundary Context: +; NONAFFINE-NEXT: [tmp9, tmp14] -> { : } +; NONAFFINE-NEXT: p0: %tmp9 +; NONAFFINE-NEXT: p1: %tmp14 +; NONAFFINE-NEXT: Arrays { +; NONAFFINE-NEXT: i64 MemRef_arg1[*]; // Element size 8 +; NONAFFINE-NEXT: i64 MemRef_arg[*]; // Element size 8 +; NONAFFINE-NEXT: i64 MemRef_tmp7; // Element size 8 +; NONAFFINE-NEXT: i64 MemRef_tmp8; // Element size 8 +; NONAFFINE-NEXT: double MemRef_arg4[*]; // Element size 8 +; NONAFFINE-NEXT: } +; NONAFFINE-NEXT: Arrays (Bounds as pw_affs) { +; NONAFFINE-NEXT: i64 MemRef_arg1[*]; // Element size 8 +; NONAFFINE-NEXT: i64 MemRef_arg[*]; // Element size 8 +; NONAFFINE-NEXT: i64 MemRef_tmp7; // Element size 8 +; NONAFFINE-NEXT: i64 MemRef_tmp8; // Element size 8 +; NONAFFINE-NEXT: double MemRef_arg4[*]; // Element size 8 +; NONAFFINE-NEXT: } +; NONAFFINE-NEXT: Alias Groups (0): +; NONAFFINE-NEXT: n/a +; NONAFFINE-NEXT: Statements { +; NONAFFINE-NEXT: Stmt_bb5 +; NONAFFINE-NEXT: Domain := +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb5[] }; +; NONAFFINE-NEXT: Schedule := +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb5[] -> [0, 0, 0] }; +; NONAFFINE-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb5[] -> MemRef_tmp7[] }; +; NONAFFINE-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb5[] -> MemRef_tmp8[] }; +; NONAFFINE-NEXT: Stmt_bb17 +; NONAFFINE-NEXT: Domain := +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb17[i0, i1] : 0 <= i0 < tmp9 and 0 <= i1 < tmp14 }; +; NONAFFINE-NEXT: Schedule := +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> [1, i0, i1] }; +; NONAFFINE-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_tmp7[] }; +; NONAFFINE-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_tmp8[] }; +; NONAFFINE-NEXT: MayWriteAccess := [Reduction Type: NONE] [Scalar: 0] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_arg4[o0] : -1152921504606846976 <= o0 <= 1152921504606846975 }; +; NONAFFINE-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_arg1[o0] }; +; NONAFFINE-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_arg[o0] }; +; NONAFFINE-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; NONAFFINE-NEXT: [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_arg4[o0] }; +; NONAFFINE-NEXT: } + + +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" + +define void @ham(i64* noalias %arg, i64* noalias %arg1, i64* noalias %arg2, i64* noalias %arg3, [0 x double]* noalias %arg4) unnamed_addr { +bb: + br label %bb5 + +bb5: ; preds = %bb + %tmp = load i64, i64* %arg1, align 8 + %tmp6 = icmp slt i64 %tmp, 0 + %tmp7 = select i1 %tmp6, i64 0, i64 %tmp + %tmp8 = xor i64 %tmp7, -1 + %tmp9 = load i64, i64* %arg, align 8 + %tmp10 = icmp sgt i64 %tmp9, 0 + br i1 %tmp10, label %bb11, label %bb32 + +bb11: ; preds = %bb5 + br label %bb12 + +bb12: ; preds = %bb28, %bb11 + %tmp13 = phi i64 [ %tmp30, %bb28 ], [ 1, %bb11 ] + %tmp14 = load i64, i64* %arg1, align 8 + %tmp15 = icmp sgt i64 %tmp14, 0 + br i1 %tmp15, label %bb16, label %bb28 + +bb16: ; preds = %bb12 + br label %bb17 + +bb17: ; preds = %bb17, %bb16 + %tmp18 = phi i64 [ %tmp26, %bb17 ], [ 1, %bb16 ] + %tmp19 = mul i64 %tmp13, %tmp7 + %tmp20 = add i64 %tmp19, %tmp8 + %tmp21 = add i64 %tmp20, %tmp18 + %tmp22 = add i64 %tmp18, %tmp13 + %tmp23 = sitofp i64 %tmp22 to double + %tmp24 = getelementptr [0 x double], [0 x double]* %arg4, i64 0, i64 %tmp21 + %call = call double @func(double* %tmp24) #2 + %sum = fadd double %call, %tmp23 + store double %sum, double* %tmp24, align 8 + %tmp25 = icmp eq i64 %tmp18, %tmp14 + %tmp26 = add i64 %tmp18, 1 + br i1 %tmp25, label %bb27, label %bb17 + +bb27: ; preds = %bb17 + br label %bb28 + +bb28: ; preds = %bb27, %bb12 + %tmp29 = icmp eq i64 %tmp13, %tmp9 + %tmp30 = add i64 %tmp13, 1 + br i1 %tmp29, label %bb31, label %bb12 + +bb31: ; preds = %bb28 + br label %bb32 + +bb32: ; preds = %bb31, %bb5 + ret void +} + +declare double @func(double*) #1 + +attributes #1 = { nounwind readonly }