From 1a28a8938ef66d03fe1d29115853a5901df14b27 Mon Sep 17 00:00:00 2001 From: Johannes Doerfert Date: Sun, 5 Oct 2014 11:32:18 +0000 Subject: [PATCH] Introduce the ScopArrayInfo class. This class allows to store information about the arrays in the SCoP. For each base pointer in the SCoP one object is created storing the type and dimension sizes of the array. The objects can be obtained via the SCoP, a MemoryAccess or the isl_id associated with the output dimension of a MemoryAccess (the description of what is accessed). So far we use the information in the IslExprBuilder to create the right base type before indexing into the base array. This fixes the bug http://llvm.org/bugs/show_bug.cgi?id=21113 (both test cases are included). On top of that we can now build runtime alias checks for delinearized arrays as the dimension sizes are also part of the ScopArrayInfo objects. Differential Revision: http://reviews.llvm.org/D5613 llvm-svn: 219077 --- polly/include/polly/ScopInfo.h | 87 ++++++++++++++++-- polly/lib/Analysis/ScopInfo.cpp | 89 +++++++++++++++++-- polly/lib/CodeGen/IslCodeGeneration.cpp | 1 - polly/lib/CodeGen/IslExprBuilder.cpp | 42 ++++----- polly/lib/Exchange/JSONExporter.cpp | 3 + .../MemAccess/codegen_constant_offset.ll | 2 +- .../Isl/CodeGen/MemAccess/codegen_simple.ll | 2 +- .../CodeGen/MemAccess/codegen_simple_float.ll | 2 +- .../CodeGen/MemAccess/codegen_simple_md.ll | 4 +- .../MemAccess/codegen_simple_md_float.ll | 4 +- ...aliasing_different_base_and_access_type.ll | 44 +++++++++ .../Isl/CodeGen/aliasing_struct_element.ll | 53 +++++++++++ 12 files changed, 287 insertions(+), 46 deletions(-) create mode 100644 polly/test/Isl/CodeGen/aliasing_different_base_and_access_type.ll create mode 100644 polly/test/Isl/CodeGen/aliasing_struct_element.ll diff --git a/polly/include/polly/ScopInfo.h b/polly/include/polly/ScopInfo.h index 02eb6597a8614..80480adcc7d4a 100644 --- a/polly/include/polly/ScopInfo.h +++ b/polly/include/polly/ScopInfo.h @@ -59,7 +59,70 @@ class TempScop; class SCEVAffFunc; class Comparison; -//===----------------------------------------------------------------------===// +/// @brief A class to store information about arrays in the SCoP. +/// +/// Objects are accessible via the ScoP, MemoryAccess or the id associated with +/// the MemoryAccess access function. +/// +class ScopArrayInfo { +public: + /// @brief Construct a ScopArrayInfo object. + /// + /// @param BasePtr The array base pointer. + /// @param AccessType The type used to access this array. + /// @param IslCtx The isl context used to create the base pointer id. + /// @param DimensionSizes A vector containing the size of each dimension. + ScopArrayInfo(Value *BasePtr, Type *AccessType, isl_ctx *IslCtx, + const SmallVector &DimensionSizes); + + /// @brief Destructor to free the isl id of the base pointer. + ~ScopArrayInfo(); + + /// @brief Return the base pointer. + Value *getBasePtr() const { return BasePtr; } + + /// @brief Return the number of dimensions. + unsigned getNumberOfDimensions() const { return DimensionSizes.size(); } + + /// @brief Return the size of dimension @p dim. + const SCEV *getDimensionSize(unsigned dim) const { + assert(dim < getNumberOfDimensions() && "Invalid dimension"); + return DimensionSizes[dim]; + } + + /// @brief Return the type used to access this array in the SCoP. + Type *getType() const { return AccessType; } + + /// @brief Return the isl id for the base pointer. + __isl_give isl_id *getBasePtrId() const; + + /// @brief Dump a readable representation to stderr. + void dump() const; + + /// @brief Print a readable representation to @p OS. + void print(raw_ostream &OS) const; + + /// @brief Access the ScopArrayInfo associated with an access function. + static const ScopArrayInfo * + getFromAccessFunction(__isl_keep isl_pw_multi_aff *PMA); + + /// @brief Access the ScopArrayInfo associated with an isl Id. + static const ScopArrayInfo *getFromId(__isl_take isl_id *Id); + +private: + /// @brief The base pointer. + Value *BasePtr; + + /// @brief The type used to access this array. + Type *AccessType; + + /// @brief The isl id for the base pointer. + isl_id *Id; + + /// @brief The sizes of each dimension. + SmallVector DimensionSizes; +}; + /// @brief Represent memory accesses in statements. class MemoryAccess { public: @@ -148,11 +211,12 @@ class MemoryAccess { public: /// @brief Create a memory access from an access in LLVM-IR. /// - /// @param Access The memory access. - /// @param Statement The statement that contains the access. - /// @param SE The ScalarEvolution analysis. + /// @param Access The memory access. + /// @param AccInst The access instruction. + /// @param Statement The statement that contains the access. + /// @param SAI The ScopArrayInfo object for this base pointer. MemoryAccess(const IRAccess &Access, Instruction *AccInst, - ScopStmt *Statement); + ScopStmt *Statement, const ScopArrayInfo *SAI); ~MemoryAccess(); @@ -188,6 +252,9 @@ class MemoryAccess { /// @brief Get the base array isl_id for this access. __isl_give isl_id *getArrayId() const; + /// @brief Get the ScopArrayInfo object for the base address. + const ScopArrayInfo *getScopArrayInfo() const; + /// @brief Return a string representation of the accesse's reduction type. const std::string getReductionOperatorStr() const; @@ -534,6 +601,9 @@ class Scop { /// Constraints on parameters. isl_set *Context; + /// @brief A map to remember ScopArrayInfo objects for all base pointers. + DenseMap ScopArrayInfoMap; + /// @brief The assumptions under which this scop was built. /// /// When constructing a scop sometimes the exact representation of a statement @@ -728,6 +798,13 @@ class Scop { const_reverse_iterator rend() const { return Stmts.rend(); } //@} + /// @brief Return the (possibly new) ScopArrayInfo object for @p Access. + const ScopArrayInfo *getOrCreateScopArrayInfo(const IRAccess &Access, + Instruction *AccessInst); + + /// @brief Return the cached ScopArrayInfo object for @p BasePtr. + const ScopArrayInfo *getScopArrayInfo(Value *BasePtr); + void setContext(isl_set *NewContext); /// @brief Align the parameters in the statement to the scop context diff --git a/polly/lib/Analysis/ScopInfo.cpp b/polly/lib/Analysis/ScopInfo.cpp index d166153e454f2..fc3807ccca17f 100644 --- a/polly/lib/Analysis/ScopInfo.cpp +++ b/polly/lib/Analysis/ScopInfo.cpp @@ -278,6 +278,43 @@ int SCEVAffinator::getLoopDepth(const Loop *L) { return L->getLoopDepth() - outerLoop->getLoopDepth(); } +ScopArrayInfo::ScopArrayInfo(Value *BasePtr, Type *AccessType, isl_ctx *Ctx, + const SmallVector &DimensionSizes) + : BasePtr(BasePtr), AccessType(AccessType), DimensionSizes(DimensionSizes) { + const std::string BasePtrName = getIslCompatibleName("MemRef_", BasePtr, ""); + Id = isl_id_alloc(Ctx, BasePtrName.c_str(), this); +} + +ScopArrayInfo::~ScopArrayInfo() { isl_id_free(Id); } + +isl_id *ScopArrayInfo::getBasePtrId() const { return isl_id_copy(Id); } + +void ScopArrayInfo::dump() const { print(errs()); } + +void ScopArrayInfo::print(raw_ostream &OS) const { + OS << "ScopArrayInfo:\n"; + OS << " Base: " << *getBasePtr() << "\n"; + OS << " Type: " << *getType() << "\n"; + OS << " Dimension Sizes:\n"; + for (unsigned u = 0; u < getNumberOfDimensions(); u++) + OS << " " << u << ") " << *DimensionSizes[u] << "\n"; + OS << "\n"; +} + +const ScopArrayInfo * +ScopArrayInfo::getFromAccessFunction(__isl_keep isl_pw_multi_aff *PMA) { + isl_id *Id = isl_pw_multi_aff_get_tuple_id(PMA, isl_dim_out); + assert(Id && "Output dimension didn't have an ID"); + return getFromId(Id); +} + +const ScopArrayInfo *ScopArrayInfo::getFromId(isl_id *Id) { + void *User = isl_id_get_user(Id); + const ScopArrayInfo *SAI = static_cast(User); + isl_id_free(Id); + return SAI; +} + const std::string MemoryAccess::getReductionOperatorStr(MemoryAccess::ReductionType RT) { switch (RT) { @@ -348,6 +385,14 @@ static MemoryAccess::AccessType getMemoryAccessType(const IRAccess &Access) { llvm_unreachable("Unknown IRAccess type!"); } +const ScopArrayInfo *MemoryAccess::getScopArrayInfo() const { + isl_id *ArrayId = getArrayId(); + void *User = isl_id_get_user(ArrayId); + const ScopArrayInfo *SAI = static_cast(User); + isl_id_free(ArrayId); + return SAI; +} + isl_id *MemoryAccess::getArrayId() const { return isl_map_get_tuple_id(AccessRelation, isl_dim_out); } @@ -433,14 +478,15 @@ void MemoryAccess::assumeNoOutOfBound(const IRAccess &Access) { } MemoryAccess::MemoryAccess(const IRAccess &Access, Instruction *AccInst, - ScopStmt *Statement) + ScopStmt *Statement, const ScopArrayInfo *SAI) : Type(getMemoryAccessType(Access)), Statement(Statement), Inst(AccInst), newAccessRelation(nullptr) { isl_ctx *Ctx = Statement->getIslCtx(); BaseAddr = Access.getBase(); BaseName = getIslCompatibleName("MemRef_", getBaseAddr(), ""); - isl_id *BaseAddrId = isl_id_alloc(Ctx, getBaseName().c_str(), nullptr); + + isl_id *BaseAddrId = SAI->getBasePtrId(); if (!Access.isAffine()) { // We overapproximate non-affine accesses with a possible access to the @@ -666,18 +712,23 @@ void ScopStmt::buildScattering(SmallVectorImpl &Scatter) { } void ScopStmt::buildAccesses(TempScop &tempScop, const Region &CurRegion) { - for (auto &&Access : *tempScop.getAccessFunctions(BB)) { - MemAccs.push_back(new MemoryAccess(Access.first, Access.second, this)); + for (const auto &AccessPair : *tempScop.getAccessFunctions(BB)) { + const IRAccess &Access = AccessPair.first; + Instruction *AccessInst = AccessPair.second; + + const ScopArrayInfo *SAI = + getParent()->getOrCreateScopArrayInfo(Access, AccessInst); + MemAccs.push_back(new MemoryAccess(Access, AccessInst, this, SAI)); // We do not track locations for scalar memory accesses at the moment. // // We do not have a use for this information at the moment. If we need this // at some point, the "instruction -> access" mapping needs to be enhanced // as a single instruction could then possibly perform multiple accesses. - if (!Access.first.isScalar()) { - assert(!InstructionToAccess.count(Access.second) && + if (!Access.isScalar()) { + assert(!InstructionToAccess.count(AccessInst) && "Unexpected 1-to-N mapping on instruction to access map!"); - InstructionToAccess[Access.second] = MemAccs.back(); + InstructionToAccess[AccessInst] = MemAccs.back(); } } } @@ -1373,6 +1424,10 @@ Scop::~Scop() { for (ScopStmt *Stmt : *this) delete Stmt; + // Free the ScopArrayInfo objects. + for (auto &ScopArrayInfoPair : ScopArrayInfoMap) + delete ScopArrayInfoPair.second; + // Free the alias groups for (MinMaxVectorTy *MinMaxAccesses : MinMaxAliasGroups) { for (MinMaxAccessTy &MMA : *MinMaxAccesses) { @@ -1383,6 +1438,26 @@ Scop::~Scop() { } } +const ScopArrayInfo *Scop::getOrCreateScopArrayInfo(const IRAccess &Access, + Instruction *AccessInst) { + Value *BasePtr = Access.getBase(); + const ScopArrayInfo *&SAI = ScopArrayInfoMap[BasePtr]; + if (!SAI) { + Type *AccessType = getPointerOperand(*AccessInst)->getType(); + SAI = new ScopArrayInfo(BasePtr, AccessType, getIslCtx(), Access.Sizes); + } + return SAI; +} + +const ScopArrayInfo *Scop::getScopArrayInfo(Value *BasePtr) { + const SCEV *PtrSCEV = SE->getSCEV(BasePtr); + const SCEVUnknown *PtrBaseSCEV = + cast(SE->getPointerBase(PtrSCEV)); + const ScopArrayInfo *SAI = ScopArrayInfoMap[PtrBaseSCEV->getValue()]; + assert(SAI && "No ScopArrayInfo available for this base pointer"); + return SAI; +} + std::string Scop::getContextStr() const { return stringFromIslObj(Context); } std::string Scop::getAssumedContextStr() const { return stringFromIslObj(AssumedContext); diff --git a/polly/lib/CodeGen/IslCodeGeneration.cpp b/polly/lib/CodeGen/IslCodeGeneration.cpp index ed8b0d683b827..7b4b76091c06e 100644 --- a/polly/lib/CodeGen/IslCodeGeneration.cpp +++ b/polly/lib/CodeGen/IslCodeGeneration.cpp @@ -23,7 +23,6 @@ #include "polly/CodeGen/BlockGenerators.h" #include "polly/CodeGen/CodeGeneration.h" #include "polly/CodeGen/IslAst.h" -#include "polly/CodeGen/IslExprBuilder.h" #include "polly/CodeGen/LoopGenerators.h" #include "polly/CodeGen/Utils.h" #include "polly/Dependences.h" diff --git a/polly/lib/CodeGen/IslExprBuilder.cpp b/polly/lib/CodeGen/IslExprBuilder.cpp index f8bf4b7553e6b..4ccdb003d340a 100644 --- a/polly/lib/CodeGen/IslExprBuilder.cpp +++ b/polly/lib/CodeGen/IslExprBuilder.cpp @@ -11,6 +11,7 @@ #include "polly/CodeGen/IslExprBuilder.h" +#include "polly/ScopInfo.h" #include "polly/Support/GICHelper.h" #include "llvm/Support/Debug.h" @@ -103,39 +104,28 @@ Value *IslExprBuilder::createAccessAddress(isl_ast_expr *Expr) { assert(isl_ast_expr_get_op_n_arg(Expr) == 2 && "Multidimensional access functions are not supported yet"); - Value *Base, *IndexOp, *Zero, *Access; - SmallVector Indices; - Type *PtrElTy; + Value *Base, *IndexOp, *Access; + isl_ast_expr *BaseExpr; + isl_id *BaseId; - Base = create(isl_ast_expr_get_op_arg(Expr, 0)); + BaseExpr = isl_ast_expr_get_op_arg(Expr, 0); + BaseId = isl_ast_expr_get_id(BaseExpr); + isl_ast_expr_free(BaseExpr); + + const ScopArrayInfo *SAI = ScopArrayInfo::getFromId(BaseId); + Base = SAI->getBasePtr(); assert(Base->getType()->isPointerTy() && "Access base should be a pointer"); + const Twine &BaseName = Base->getName(); + + if (Base->getType() != SAI->getType()) + Base = Builder.CreateBitCast(Base, SAI->getType(), + "polly.access.cast." + BaseName); IndexOp = create(isl_ast_expr_get_op_arg(Expr, 1)); assert(IndexOp->getType()->isIntegerTy() && "Access index should be an integer"); - Zero = ConstantInt::getNullValue(IndexOp->getType()); - - // If base is a array type like, - // int A[N][M][K]; - // we have to adjust the GEP. The easiest way is to transform accesses like, - // A[i][j][k] - // into equivalent ones like, - // A[0][0][ i*N*M + j*M + k] - // because SCEV already folded the "peudo dimensions" into one. Thus our index - // operand will be 'i*N*M + j*M + k' anyway. - PtrElTy = Base->getType()->getPointerElementType(); - while (PtrElTy->isArrayTy()) { - Indices.push_back(Zero); - PtrElTy = PtrElTy->getArrayElementType(); - } - - Indices.push_back(IndexOp); - assert((PtrElTy->isIntOrIntVectorTy() || PtrElTy->isFPOrFPVectorTy() || - PtrElTy->isPtrOrPtrVectorTy()) && - "We do not yet change the type of the access base during code " - "generation."); - Access = Builder.CreateGEP(Base, Indices, "polly.access." + Base->getName()); + Access = Builder.CreateGEP(Base, IndexOp, "polly.access." + BaseName); isl_ast_expr_free(Expr); return Access; diff --git a/polly/lib/Exchange/JSONExporter.cpp b/polly/lib/Exchange/JSONExporter.cpp index 36e302b152292..e462ece97918a 100644 --- a/polly/lib/Exchange/JSONExporter.cpp +++ b/polly/lib/Exchange/JSONExporter.cpp @@ -277,6 +277,9 @@ bool JSONImporter::runOnScop(Scop &scop) { return false; } + isl_id *OutId = isl_map_get_tuple_id(currentAccessMap, isl_dim_out); + newAccessMap = isl_map_set_tuple_id(newAccessMap, isl_dim_out, OutId); + // We keep the old alignment, thus we cannot allow accesses to memory // locations that were not accessed before. isl_set *newAccessSet = isl_map_range(isl_map_copy(newAccessMap)); diff --git a/polly/test/Isl/CodeGen/MemAccess/codegen_constant_offset.ll b/polly/test/Isl/CodeGen/MemAccess/codegen_constant_offset.ll index 05874f3c735f3..36dbf12448aeb 100644 --- a/polly/test/Isl/CodeGen/MemAccess/codegen_constant_offset.ll +++ b/polly/test/Isl/CodeGen/MemAccess/codegen_constant_offset.ll @@ -40,4 +40,4 @@ for.inc: ; preds = %for.body for.end: ; preds = %for.cond ret i32 0 } -; CHECK: load i32* getelementptr inbounds ([100 x i32]* @A, i64 0, i64 10) +; CHECK: load i32* getelementptr inbounds ([100 x i32]* @A, i{{(32|64)}} 0, i{{(32|64)}} 10) diff --git a/polly/test/Isl/CodeGen/MemAccess/codegen_simple.ll b/polly/test/Isl/CodeGen/MemAccess/codegen_simple.ll index 8fd660ae770ff..0afcff89aa58a 100644 --- a/polly/test/Isl/CodeGen/MemAccess/codegen_simple.ll +++ b/polly/test/Isl/CodeGen/MemAccess/codegen_simple.ll @@ -40,4 +40,4 @@ for.inc: ; preds = %for.body for.end: ; preds = %for.cond ret i32 0 } -; CHECK: load i32* getelementptr inbounds ([100 x i32]* @A, i64 0, i64 0) +; CHECK: load i32* getelementptr inbounds ([100 x i32]* @A, i{{(32|64)}} 0, i{{(32|64)}} 0) diff --git a/polly/test/Isl/CodeGen/MemAccess/codegen_simple_float.ll b/polly/test/Isl/CodeGen/MemAccess/codegen_simple_float.ll index 01b1b55bb8b6b..ccc01df783134 100644 --- a/polly/test/Isl/CodeGen/MemAccess/codegen_simple_float.ll +++ b/polly/test/Isl/CodeGen/MemAccess/codegen_simple_float.ll @@ -38,4 +38,4 @@ for.inc: ; preds = %for.body for.end: ; preds = %for.cond ret i32 0 } -; CHECK: load float* getelementptr inbounds ([100 x float]* @A, i64 0, i64 0) +; CHECK: load float* getelementptr inbounds ([100 x float]* @A, i{{(32|64)}} 0, i{{(32|64)}} 0) diff --git a/polly/test/Isl/CodeGen/MemAccess/codegen_simple_md.ll b/polly/test/Isl/CodeGen/MemAccess/codegen_simple_md.ll index aeb302ed029e9..78a221024243a 100644 --- a/polly/test/Isl/CodeGen/MemAccess/codegen_simple_md.ll +++ b/polly/test/Isl/CodeGen/MemAccess/codegen_simple_md.ll @@ -63,7 +63,7 @@ for.end6: ; preds = %for.cond ; WITHCONST: %[[MUL2:[._a-zA-Z0-9]+]] = mul nsw i64 2, %[[IVIn]] ; WITHCONST: %[[SUM1:[._a-zA-Z0-9]+]] = add nsw i64 %[[MUL1]], %[[MUL2]] ; WITHCONST: %[[SUM2:[._a-zA-Z0-9]+]] = add nsw i64 %[[SUM1]], 5 -; WITHCONST: %[[ACC:[._a-zA-Z0-9]*]] = getelementptr [1040 x i32]* @A, i64 0, i64 %[[SUM2]] +; WITHCONST: %[[ACC:[._a-zA-Z0-9]*]] = getelementptr i32* getelementptr inbounds ([1040 x i32]* @A, i{{(32|64)}} 0, i{{(32|64)}} 0), i64 %[[SUM2]] ; WITHCONST: store i32 100, i32* %[[ACC]] ; WITHOUTCONST: %[[IVOut:polly.indvar[0-9]*]] = phi i64 [ 0, %polly.loop_preheader{{[0-9]*}} ], [ %polly.indvar_next{{[0-9]*}}, %polly.{{[._a-zA-Z0-9]*}} ] @@ -71,5 +71,5 @@ for.end6: ; preds = %for.cond ; WITHOUTCONST: %[[MUL1:[._a-zA-Z0-9]+]] = mul nsw i64 16, %[[IVOut]] ; WITHOUTCONST: %[[MUL2:[._a-zA-Z0-9]+]] = mul nsw i64 2, %[[IVIn]] ; WITHOUTCONST: %[[SUM1:[._a-zA-Z0-9]+]] = add nsw i64 %[[MUL1]], %[[MUL2]] -; WITHOUTCONST: %[[ACC:[._a-zA-Z0-9]*]] = getelementptr [1040 x i32]* @A, i64 0, i64 %[[SUM1]] +; WITHOUTCONST: %[[ACC:[._a-zA-Z0-9]*]] = getelementptr i32* getelementptr inbounds ([1040 x i32]* @A, i{{(32|64)}} 0, i{{(32|64)}} 0), i64 %[[SUM1]] ; WITHOUTCONST: store i32 100, i32* %[[ACC]] diff --git a/polly/test/Isl/CodeGen/MemAccess/codegen_simple_md_float.ll b/polly/test/Isl/CodeGen/MemAccess/codegen_simple_md_float.ll index 01bd46d369ea4..6f3119d458dde 100644 --- a/polly/test/Isl/CodeGen/MemAccess/codegen_simple_md_float.ll +++ b/polly/test/Isl/CodeGen/MemAccess/codegen_simple_md_float.ll @@ -59,7 +59,7 @@ for.end6: ; preds = %for.cond ; WITHCONST: %[[MUL2:[._a-zA-Z0-9]+]] = mul nsw i64 2, %[[IVIn]] ; WITHCONST: %[[SUM1:[._a-zA-Z0-9]+]] = add nsw i64 %[[MUL1]], %[[MUL2]] ; WITHCONST: %[[SUM2:[._a-zA-Z0-9]+]] = add nsw i64 %[[SUM1]], 5 -; WITHCONST: %[[ACC:[._a-zA-Z0-9]*]] = getelementptr [1040 x float]* @A, i64 0, i64 %[[SUM2]] +; WITHCONST: %[[ACC:[._a-zA-Z0-9]*]] = getelementptr float* getelementptr inbounds ([1040 x float]* @A, i{{(32|64)}} 0, i{{(32|64)}} 0), i64 %[[SUM2]] ; WITHCONST: store float 1.000000e+02, float* %[[ACC]] ; WITHOUTCONST: %[[IVOut:polly.indvar[0-9]*]] = phi i64 [ 0, %polly.loop_preheader{{[0-9]*}} ], [ %polly.indvar_next{{[0-9]*}}, %polly.{{[._a-zA-Z0-9]*}} ] @@ -67,5 +67,5 @@ for.end6: ; preds = %for.cond ; WITHOUTCONST: %[[MUL1:[._a-zA-Z0-9]+]] = mul nsw i64 16, %[[IVOut]] ; WITHOUTCONST: %[[MUL2:[._a-zA-Z0-9]+]] = mul nsw i64 2, %[[IVIn]] ; WITHOUTCONST: %[[SUM1:[._a-zA-Z0-9]+]] = add nsw i64 %[[MUL1]], %[[MUL2]] -; WITHOUTCONST: %[[ACC:[._a-zA-Z0-9]*]] = getelementptr [1040 x float]* @A, i64 0, i64 %[[SUM1]] +; WITHOUTCONST: %[[ACC:[._a-zA-Z0-9]*]] = getelementptr float* getelementptr inbounds ([1040 x float]* @A, i{{(32|64)}} 0, i{{(32|64)}} 0), i64 %[[SUM1]] ; WITHOUTCONST: store float 1.000000e+02, float* %[[ACC]] diff --git a/polly/test/Isl/CodeGen/aliasing_different_base_and_access_type.ll b/polly/test/Isl/CodeGen/aliasing_different_base_and_access_type.ll new file mode 100644 index 0000000000000..23c8070d29bc5 --- /dev/null +++ b/polly/test/Isl/CodeGen/aliasing_different_base_and_access_type.ll @@ -0,0 +1,44 @@ +; RUN: opt %loadPolly -S -polly-code-generator=isl -polly-codegen-isl < %s | FileCheck %s +; +; We have to cast %B to "short *" before we create RTCs. +; +; CHECK: entry: +; CHECK-NEXT: %polly.access.cast.B = bitcast i32* %B to i16* +; CHECK-NEXT: %polly.access.B = getelementptr i16* %polly.access.cast.B, i64 1024 +; +; We should never access %B as an i32 pointer: +; +; CHECK-NOT: getelementptr i32* %B +; +; void jd(int *A, int *B) { +; for (int i = 0; i < 1024; i++) +; A[i] = ((short *)B)[i]; +; } +; +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +define void @jd(i32* %A, i32* %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 + %tmp = bitcast i32* %B to i16* + %arrayidx = getelementptr inbounds i16* %tmp, i64 %indvars.iv + %tmp1 = load i16* %arrayidx, align 2 + %conv = sext i16 %tmp1 to i32 + %arrayidx2 = getelementptr inbounds i32* %A, i64 %indvars.iv + store i32 %conv, i32* %arrayidx2, 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 +} diff --git a/polly/test/Isl/CodeGen/aliasing_struct_element.ll b/polly/test/Isl/CodeGen/aliasing_struct_element.ll new file mode 100644 index 0000000000000..cb75d2ecbed71 --- /dev/null +++ b/polly/test/Isl/CodeGen/aliasing_struct_element.ll @@ -0,0 +1,53 @@ +; RUN: opt %loadPolly -S -polly-code-generator=isl -polly-codegen-isl < %s | FileCheck %s +; +; We should only access (or compute the address of) "the first element" of %S +; as it is a single struct not a struct array. The maximal access to S, thus +; S->B[1023] is for ScalarEvolution an access with offset of 1423, 1023 for the +; index inside the B part of S and 400 to skip the Dummy array in S. Note that +; these numbers are relative to the actual type of &S->B[i] (char*) not to the +; type of S (struct st *) or something else. +; +; Verify that we do not use the offset 1423 into a non existent S array when we +; compute runtime alias checks but treat it as if it was a char array. +; +; CHECK: %polly.access.cast.S = bitcast %struct.st* %S to i8* +; CHECK: %polly.access.S = getelementptr i8* %polly.access.cast.S, i64 1424 +; +; struct st { +; int Dummy[100]; +; char B[100]; +; }; +; +; void jd(int *A, struct st *S) { +; for (int i = 0; i < 1024; i++) +; A[i] = S->B[i]; +; } +; +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +%struct.st = type { [100 x i32], [100 x i8] } + +define void @jd(i32* %A, %struct.st* %S) { +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 %struct.st* %S, i64 0, i32 1, i64 %indvars.iv + %tmp = load i8* %arrayidx, align 1 + %conv = sext i8 %tmp to i32 + %arrayidx2 = getelementptr inbounds i32* %A, i64 %indvars.iv + store i32 %conv, i32* %arrayidx2, 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 +}