[polly] r261489 - Support memory intrinsics
Johannes Doerfert via llvm-commits
llvm-commits at lists.llvm.org
Sun Feb 21 11:13:19 PST 2016
Author: jdoerfert
Date: Sun Feb 21 13:13:19 2016
New Revision: 261489
URL: http://llvm.org/viewvc/llvm-project?rev=261489&view=rev
Log:
Support memory intrinsics
This patch adds support for memcpy, memset and memmove intrinsics. They are
represented as one (memset) or two (memcpy, memmove) memory accesses in the
polyhedral model. These accesses have an access range that describes the
summarized effect of the intrinsic, i.e.,
memset(&A[i], '$', N);
is represented as a write access from A[i] to A[i+N].
Differential Revision: http://reviews.llvm.org/D5226
Added:
polly/trunk/test/ScopInfo/memcpy.ll
polly/trunk/test/ScopInfo/memmove.ll
polly/trunk/test/ScopInfo/memset.ll
Modified:
polly/trunk/include/polly/ScopDetection.h
polly/trunk/include/polly/ScopInfo.h
polly/trunk/include/polly/Support/ScopHelper.h
polly/trunk/lib/Analysis/ScopDetection.cpp
polly/trunk/lib/Analysis/ScopInfo.cpp
Modified: polly/trunk/include/polly/ScopDetection.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/ScopDetection.h?rev=261489&r1=261488&r2=261489&view=diff
==============================================================================
--- polly/trunk/include/polly/ScopDetection.h (original)
+++ polly/trunk/include/polly/ScopDetection.h Sun Feb 21 13:13:19 2016
@@ -70,6 +70,7 @@ class SCEVUnknown;
class CallInst;
class Instruction;
class Value;
+class IntrinsicInst;
}
namespace polly {
@@ -328,11 +329,21 @@ private:
/// @return True if R is a Scop, false otherwise.
bool isValidRegion(DetectionContext &Context) const;
+ /// @brief Check if an intrinsic call can be part of a Scop.
+ ///
+ /// @param II The intrinsic call instruction to check.
+ /// @param Context The current detection context.
+ ///
+ /// @return True if the call instruction is valid, false otherwise.
+ bool isValidIntrinsicInst(IntrinsicInst &II, DetectionContext &Context) const;
+
/// @brief Check if a call instruction can be part of a Scop.
///
- /// @param CI The call instruction to check.
+ /// @param CI The call instruction to check.
+ /// @param Context The current detection context.
+ ///
/// @return True if the call instruction is valid, false otherwise.
- static bool isValidCallInst(CallInst &CI);
+ bool isValidCallInst(CallInst &CI, DetectionContext &Context) const;
/// @brief Check if the given loads could be invariant and can be hoisted.
///
@@ -355,6 +366,15 @@ private:
/// identified by Reg.
bool isInvariant(const Value &Val, const Region &Reg) const;
+ /// @brief Check if the memory access caused by @p Inst is valid.
+ ///
+ /// @param Inst The access instruction.
+ /// @param AF The access function.
+ /// @param BP The access base pointer.
+ /// @param Context The current detection context.
+ bool isValidAccess(Instruction *Inst, const SCEV *AF, const SCEVUnknown *BP,
+ DetectionContext &Context) const;
+
/// @brief Check if a memory access can be part of a Scop.
///
/// @param Inst The instruction accessing the memory.
Modified: polly/trunk/include/polly/ScopInfo.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/ScopInfo.h?rev=261489&r1=261488&r2=261489&view=diff
==============================================================================
--- polly/trunk/include/polly/ScopInfo.h (original)
+++ polly/trunk/include/polly/ScopInfo.h Sun Feb 21 13:13:19 2016
@@ -497,8 +497,8 @@ private:
/// @brief An unique name of the accessed array.
std::string BaseName;
- /// @brief Size in bytes of a single array element.
- unsigned ElemBytes;
+ /// @brief Type a single array element wrt. this access.
+ Type *ElementType;
/// @brief Size of each dimension of the accessed array.
SmallVector<const SCEV *, 4> Sizes;
@@ -529,7 +529,8 @@ private:
/// @brief The value associated with this memory access.
///
/// - For array memory accesses (MK_Array) it is the loaded result or the
- /// stored value.
+ /// stored value. If the access instruction is a memory intrinsic it
+ /// the access value is also the memory intrinsic.
/// - For accesses of kind MK_Value it is the access instruction itself.
/// - For accesses of kind MK_PHI or MK_ExitPHI it is the PHI node itself
/// (for both, READ and WRITE accesses).
@@ -574,8 +575,6 @@ private:
isl_map *NewAccessRelation;
// @}
- unsigned getElemSizeInBytes() const { return ElemBytes; }
-
bool isAffine() const { return IsAffine; }
__isl_give isl_basic_map *createBasicAccessMap(ScopStmt *Statement);
@@ -627,6 +626,9 @@ private:
__isl_give isl_map *foldAccess(__isl_take isl_map *AccessRelation,
ScopStmt *Statement);
+ /// @brief Create the access relation for the underlying memory intrinsic.
+ void buildMemIntrinsicAccessRelation();
+
/// @brief Assemble the access relation from all availbale information.
///
/// In particular, used the information passes in the constructor and the
@@ -641,15 +643,15 @@ public:
/// @param Stmt The parent statement.
/// @param AccessInst The instruction doing the access.
/// @param BaseAddr The accessed array's address.
- /// @param ElemBytes Number of accessed bytes.
+ /// @param ElemType The type of the accessed array elements.
/// @param AccType Whether read or write access.
/// @param IsAffine Whether the subscripts are affine expressions.
/// @param Kind The kind of memory accessed.
/// @param Subscripts Subscipt expressions
/// @param Sizes Dimension lengths of the accessed array.
/// @param BaseName Name of the acessed array.
- MemoryAccess(ScopStmt *Stmt, Instruction *AccessInst, AccessType Type,
- Value *BaseAddress, unsigned ElemBytes, bool Affine,
+ MemoryAccess(ScopStmt *Stmt, Instruction *AccessInst, AccessType AccType,
+ Value *BaseAddress, Type *ElemType, bool Affine,
ArrayRef<const SCEV *> Subscripts, ArrayRef<const SCEV *> Sizes,
Value *AccessValue, ScopArrayInfo::MemoryKind Kind,
StringRef BaseName);
@@ -754,6 +756,9 @@ public:
const std::string &getBaseName() const { return BaseName; }
+ /// @brief Return the element type of the accessed array wrt. this access.
+ Type *getElementType() const { return ElementType; }
+
/// @brief Return the access value of this memory access.
Value *getAccessValue() const { return AccessValue; }
@@ -2066,6 +2071,19 @@ class ScopInfo : public RegionPass {
const InvariantLoadsSetTy &ScopRIL,
const MapInsnToMemAcc &InsnToMemAcc);
+ /// @brief Try to build a MemoryAccess for a memory intrinsic.
+ ///
+ /// @param Inst The 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 buildAccessMemIntrinsic(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.
///
@@ -2147,9 +2165,9 @@ class ScopInfo : public RegionPass {
/// @param BB The block where the access takes place.
/// @param Inst The instruction doing the access. It is not necessarily
/// inside @p BB.
- /// @param Type The kind of access.
+ /// @param AccType The kind of access.
/// @param BaseAddress The accessed array's base address.
- /// @param ElemBytes Size of accessed array element.
+ /// @param ElemType The type of the accessed array elements.
/// @param Affine Whether all subscripts are affine expressions.
/// @param AccessValue Value read or written.
/// @param Subscripts Access subscripts per dimension.
@@ -2159,9 +2177,9 @@ class ScopInfo : public RegionPass {
/// @return The created MemoryAccess, or nullptr if the access is not within
/// the SCoP.
MemoryAccess *addMemoryAccess(BasicBlock *BB, Instruction *Inst,
- MemoryAccess::AccessType Type,
- Value *BaseAddress, unsigned ElemBytes,
- bool Affine, Value *AccessValue,
+ MemoryAccess::AccessType AccType,
+ Value *BaseAddress, Type *ElemType, bool Affine,
+ Value *AccessValue,
ArrayRef<const SCEV *> Subscripts,
ArrayRef<const SCEV *> Sizes,
ScopArrayInfo::MemoryKind Kind);
@@ -2170,17 +2188,17 @@ class ScopInfo : public RegionPass {
/// StoreInst.
///
/// @param MemAccInst The LoadInst or StoreInst.
- /// @param Type The kind of access.
+ /// @param AccType The kind of access.
/// @param BaseAddress The accessed array's base address.
- /// @param ElemBytes Size of accessed array element.
+ /// @param ElemType The type of the accessed array elements.
/// @param IsAffine Whether all subscripts are affine expressions.
/// @param Subscripts Access subscripts per dimension.
/// @param Sizes The array dimension's sizes.
/// @param AccessValue Value read or written.
///
/// @see ScopArrayInfo::MemoryKind
- void addArrayAccess(MemAccInst MemAccInst, MemoryAccess::AccessType Type,
- Value *BaseAddress, unsigned ElemBytes, bool IsAffine,
+ void addArrayAccess(MemAccInst MemAccInst, MemoryAccess::AccessType AccType,
+ Value *BaseAddress, Type *ElemType, bool IsAffine,
ArrayRef<const SCEV *> Subscripts,
ArrayRef<const SCEV *> Sizes, Value *AccessValue);
Modified: polly/trunk/include/polly/Support/ScopHelper.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/Support/ScopHelper.h?rev=261489&r1=261488&r2=261489&view=diff
==============================================================================
--- polly/trunk/include/polly/Support/ScopHelper.h (original)
+++ polly/trunk/include/polly/Support/ScopHelper.h Sun Feb 21 13:13:19 2016
@@ -17,6 +17,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/ValueHandle.h"
namespace llvm {
@@ -42,7 +43,7 @@ using InvariantLoadsSetTy = llvm::SetVec
/// @brief Utility proxy to wrap the common members of LoadInst and StoreInst.
///
/// This works like the LLVM utility class CallSite, ie. it forwards all calls
-/// to either a LoadInst or StoreInst.
+/// to either a LoadInst, StoreInst, MemIntrinsic or MemTransferInst.
/// It is similar to LLVM's utility classes IntrinsicInst, MemIntrinsic,
/// MemTransferInst, etc. in that it offers a common interface, but does not act
/// as a fake base class.
@@ -50,10 +51,12 @@ using InvariantLoadsSetTy = llvm::SetVec
/// referenced object and should be passed by-value as it is small enough.
///
/// This proxy can either represent a LoadInst instance, a StoreInst instance,
-/// or a nullptr (only creatable using the default constructor); never an
-/// Instruction that is not a load or store.
-/// When representing a nullptr, only the following methods are defined:
-/// isNull(), isInstruction(), isLoad(), isStore(), operator bool(), operator!()
+/// 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:
+/// isNull(), isInstruction(), isLoad(), isStore(), ..., isMemTransferInst(),
+/// operator bool(), operator!()
///
/// The functions isa, cast, cast_or_null, dyn_cast are modeled te resemble
/// those from llvm/Support/Casting.h. Partial template function specialization
@@ -71,14 +74,17 @@ public:
/* implicit */ MemAccInst(llvm::LoadInst *LI) : I(LI) {}
/* implicit */ MemAccInst(llvm::StoreInst &SI) : I(&SI) {}
/* implicit */ MemAccInst(llvm::StoreInst *SI) : I(SI) {}
+ /* implicit */ MemAccInst(llvm::MemIntrinsic *MI) : I(MI) {}
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<llvm::LoadInst>(V) || llvm::isa<llvm::StoreInst>(V);
+ return llvm::isa<llvm::LoadInst>(V) || llvm::isa<llvm::StoreInst>(V) ||
+ llvm::isa<llvm::MemIntrinsic>(V);
}
static bool isa(const llvm::Value *V) {
- return llvm::isa<llvm::LoadInst>(V) || llvm::isa<llvm::StoreInst>(V);
+ return llvm::isa<llvm::LoadInst>(V) || llvm::isa<llvm::StoreInst>(V) ||
+ llvm::isa<llvm::MemIntrinsic>(V);
}
static MemAccInst cast(llvm::Value &V) {
return MemAccInst(llvm::cast<llvm::Instruction>(V));
@@ -126,6 +132,14 @@ public:
I = SI;
return *this;
}
+ MemAccInst &operator=(llvm::MemIntrinsic &MI) {
+ I = &MI;
+ return *this;
+ }
+ MemAccInst &operator=(llvm::MemIntrinsic *MI) {
+ I = MI;
+ return *this;
+ }
operator llvm::Instruction *() const { return asInstruction(); }
explicit operator bool() const { return isInstruction(); }
@@ -152,6 +166,8 @@ public:
return asLoad();
if (isStore())
return asStore()->getValueOperand();
+ if (isMemIntrinsic())
+ return nullptr;
llvm_unreachable("Operation not supported on nullptr");
}
llvm::Value *getPointerOperand() const {
@@ -159,6 +175,8 @@ public:
return asLoad()->getPointerOperand();
if (isStore())
return asStore()->getPointerOperand();
+ if (isMemIntrinsic())
+ return asMemIntrinsic()->getDest();
llvm_unreachable("Operation not supported on nullptr");
}
@@ -167,6 +185,8 @@ public:
return asLoad()->getAlignment();
if (isStore())
return asStore()->getAlignment();
+ if (isMemIntrinsic())
+ return asMemIntrinsic()->getAlignment();
llvm_unreachable("Operation not supported on nullptr");
}
bool isVolatile() const {
@@ -174,6 +194,8 @@ public:
return asLoad()->isVolatile();
if (isStore())
return asStore()->isVolatile();
+ if (isMemIntrinsic())
+ return asMemIntrinsic()->isVolatile();
llvm_unreachable("Operation not supported on nullptr");
}
bool isSimple() const {
@@ -181,6 +203,8 @@ public:
return asLoad()->isSimple();
if (isStore())
return asStore()->isSimple();
+ if (isMemIntrinsic())
+ return !asMemIntrinsic()->isVolatile();
llvm_unreachable("Operation not supported on nullptr");
}
llvm::AtomicOrdering getOrdering() const {
@@ -188,6 +212,8 @@ public:
return asLoad()->getOrdering();
if (isStore())
return asStore()->getOrdering();
+ if (isMemIntrinsic())
+ return llvm::AtomicOrdering::NotAtomic;
llvm_unreachable("Operation not supported on nullptr");
}
bool isUnordered() const {
@@ -195,6 +221,9 @@ public:
return asLoad()->isUnordered();
if (isStore())
return asStore()->isUnordered();
+ // Copied from the Load/Store implementation of isUnordered:
+ if (isMemIntrinsic())
+ return !asMemIntrinsic()->isVolatile();
llvm_unreachable("Operation not supported on nullptr");
}
@@ -202,10 +231,24 @@ public:
bool isInstruction() const { return I; }
bool isLoad() const { return I && llvm::isa<llvm::LoadInst>(I); }
bool isStore() const { return I && llvm::isa<llvm::StoreInst>(I); }
+ bool isMemIntrinsic() const { return I && llvm::isa<llvm::MemIntrinsic>(I); }
+ bool isMemSetInst() const { return I && llvm::isa<llvm::MemSetInst>(I); }
+ bool isMemTransferInst() const {
+ return I && llvm::isa<llvm::MemTransferInst>(I);
+ }
llvm::Instruction *asInstruction() const { return I; }
llvm::LoadInst *asLoad() const { return llvm::cast<llvm::LoadInst>(I); }
llvm::StoreInst *asStore() const { return llvm::cast<llvm::StoreInst>(I); }
+ llvm::MemIntrinsic *asMemIntrinsic() const {
+ return llvm::cast<llvm::MemIntrinsic>(I);
+ }
+ llvm::MemSetInst *asMemSetInst() const {
+ return llvm::cast<llvm::MemSetInst>(I);
+ }
+ llvm::MemTransferInst *asMemTransferInst() const {
+ return llvm::cast<llvm::MemTransferInst>(I);
+ }
};
/// @brief Check if the PHINode has any incoming Invoke edge.
Modified: polly/trunk/lib/Analysis/ScopDetection.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Analysis/ScopDetection.cpp?rev=261489&r1=261488&r2=261489&view=diff
==============================================================================
--- polly/trunk/lib/Analysis/ScopDetection.cpp (original)
+++ polly/trunk/lib/Analysis/ScopDetection.cpp Sun Feb 21 13:13:19 2016
@@ -34,8 +34,8 @@
//
// * Side effect free functions call
//
-// Only function calls and intrinsics that do not have side effects are allowed
-// (readnone).
+// Function calls and intrinsics that do not have side effects (readnone)
+// or memory intrinsics (memset, memcpy, memmove) are allowed.
//
// The Scop detection finds the largest Scops by checking if the largest
// region is a Scop. If this is not the case, its canonical subregions are
@@ -453,21 +453,64 @@ bool ScopDetection::isValidCFG(BasicBloc
return isValidSwitch(BB, SI, Condition, IsLoopBranch, Context);
}
-bool ScopDetection::isValidCallInst(CallInst &CI) {
+bool ScopDetection::isValidCallInst(CallInst &CI,
+ DetectionContext &Context) const {
if (CI.doesNotReturn())
return false;
if (CI.doesNotAccessMemory())
return true;
+ if (auto *II = dyn_cast<IntrinsicInst>(&CI))
+ return isValidIntrinsicInst(*II, Context);
+
Function *CalledFunction = CI.getCalledFunction();
// Indirect calls are not supported.
if (CalledFunction == 0)
return false;
- if (isIgnoredIntrinsic(&CI))
+ return false;
+}
+
+bool ScopDetection::isValidIntrinsicInst(IntrinsicInst &II,
+ DetectionContext &Context) const {
+ if (isIgnoredIntrinsic(&II))
+ return true;
+
+ // The closest loop surrounding the call instruction.
+ Loop *L = LI->getLoopFor(II.getParent());
+
+ // The access function and base pointer for memory intrinsics.
+ const SCEV *AF;
+ const SCEVUnknown *BP;
+
+ switch (II.getIntrinsicID()) {
+ // Memory intrinsics that can be represented are supported.
+ case llvm::Intrinsic::memmove:
+ case llvm::Intrinsic::memcpy:
+ AF = SE->getSCEVAtScope(cast<MemTransferInst>(II).getSource(), L);
+ BP = dyn_cast<SCEVUnknown>(SE->getPointerBase(AF));
+ // Bail if the source pointer is not valid.
+ if (!isValidAccess(&II, AF, BP, Context))
+ return false;
+ // Fall through
+ case llvm::Intrinsic::memset:
+ AF = SE->getSCEVAtScope(cast<MemIntrinsic>(II).getDest(), L);
+ BP = dyn_cast<SCEVUnknown>(SE->getPointerBase(AF));
+ // Bail if the destination pointer is not valid.
+ if (!isValidAccess(&II, AF, BP, Context))
+ return false;
+
+ // Bail if the length is not affine.
+ if (!isAffine(SE->getSCEVAtScope(cast<MemIntrinsic>(II).getLength(), L),
+ Context))
+ return false;
+
return true;
+ default:
+ break;
+ }
return false;
}
@@ -762,78 +805,78 @@ bool ScopDetection::hasAffineMemoryAcces
return true;
}
-bool ScopDetection::isValidMemoryAccess(MemAccInst Inst,
- DetectionContext &Context) const {
- Region &CurRegion = Context.CurRegion;
-
- Value *Ptr = Inst.getPointerOperand();
- Loop *L = LI->getLoopFor(Inst.getParent());
- const SCEV *AccessFunction = SE->getSCEVAtScope(Ptr, L);
- const SCEVUnknown *BasePointer;
- Value *BaseValue;
-
- BasePointer = dyn_cast<SCEVUnknown>(SE->getPointerBase(AccessFunction));
+bool ScopDetection::isValidAccess(Instruction *Inst, const SCEV *AF,
+ const SCEVUnknown *BP,
+ DetectionContext &Context) const {
- if (!BasePointer)
+ if (!BP)
return invalid<ReportNoBasePtr>(Context, /*Assert=*/true, Inst);
- BaseValue = BasePointer->getValue();
-
- if (isa<UndefValue>(BaseValue))
+ auto *BV = BP->getValue();
+ if (isa<UndefValue>(BV))
return invalid<ReportUndefBasePtr>(Context, /*Assert=*/true, Inst);
+ // FIXME: Think about allowing IntToPtrInst
+ if (IntToPtrInst *Inst = dyn_cast<IntToPtrInst>(BV))
+ return invalid<ReportIntToPtr>(Context, /*Assert=*/true, Inst);
+
// Check that the base address of the access is invariant in the current
// region.
- if (!isInvariant(*BaseValue, CurRegion))
- return invalid<ReportVariantBasePtr>(Context, /*Assert=*/true, BaseValue,
- Inst);
-
- AccessFunction = SE->getMinusSCEV(AccessFunction, BasePointer);
-
- const SCEV *Size = SE->getElementSize(Inst);
- if (Context.ElementSize[BasePointer]) {
- if (!AllowDifferentTypes && Context.ElementSize[BasePointer] != Size)
+ if (!isInvariant(*BV, Context.CurRegion))
+ return invalid<ReportVariantBasePtr>(Context, /*Assert=*/true, BV, Inst);
+
+ AF = SE->getMinusSCEV(AF, BP);
+
+ const SCEV *Size;
+ if (!isa<MemIntrinsic>(Inst)) {
+ Size = SE->getElementSize(Inst);
+ } else {
+ auto *SizeTy =
+ SE->getEffectiveSCEVType(PointerType::getInt8PtrTy(SE->getContext()));
+ Size = SE->getConstant(SizeTy, 8);
+ }
+
+ if (Context.ElementSize[BP]) {
+ if (!AllowDifferentTypes && Context.ElementSize[BP] != Size)
return invalid<ReportDifferentArrayElementSize>(Context, /*Assert=*/true,
- Inst, BaseValue);
+ Inst, BV);
- Context.ElementSize[BasePointer] =
- SE->getSMinExpr(Size, Context.ElementSize[BasePointer]);
+ Context.ElementSize[BP] = SE->getSMinExpr(Size, Context.ElementSize[BP]);
} else {
- Context.ElementSize[BasePointer] = Size;
+ Context.ElementSize[BP] = Size;
}
- bool isVariantInNonAffineLoop = false;
+ bool IsVariantInNonAffineLoop = false;
SetVector<const Loop *> Loops;
- findLoops(AccessFunction, Loops);
+ findLoops(AF, Loops);
for (const Loop *L : Loops)
if (Context.BoxedLoopsSet.count(L))
- isVariantInNonAffineLoop = true;
-
- if (PollyDelinearize && !isVariantInNonAffineLoop) {
- Context.Accesses[BasePointer].push_back({Inst, AccessFunction});
+ IsVariantInNonAffineLoop = true;
- if (!isAffine(AccessFunction, Context, BaseValue))
- Context.NonAffineAccesses.insert(BasePointer);
- } else if (!AllowNonAffine) {
- if (isVariantInNonAffineLoop ||
- !isAffine(AccessFunction, Context, BaseValue))
- return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true,
- AccessFunction, Inst, BaseValue);
+ bool IsAffine = !IsVariantInNonAffineLoop && isAffine(AF, Context, BV);
+ // Do not try to delinearize memory intrinsics and force them to be affine.
+ if (isa<MemIntrinsic>(Inst) && !IsAffine) {
+ return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF, Inst,
+ BV);
+ } else if (PollyDelinearize && !IsVariantInNonAffineLoop) {
+ Context.Accesses[BP].push_back({Inst, AF});
+
+ if (!IsAffine)
+ Context.NonAffineAccesses.insert(BP);
+ } else if (!AllowNonAffine && !IsAffine) {
+ return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF, Inst,
+ BV);
}
- // FIXME: Think about allowing IntToPtrInst
- if (IntToPtrInst *Inst = dyn_cast<IntToPtrInst>(BaseValue))
- return invalid<ReportIntToPtr>(Context, /*Assert=*/true, Inst);
-
if (IgnoreAliasing)
return true;
// Check if the base pointer of the memory access does alias with
// any other pointer. This cannot be handled at the moment.
AAMDNodes AATags;
- Inst.getAAMetadata(AATags);
+ Inst->getAAMetadata(AATags);
AliasSet &AS = Context.AST.getAliasSetForPointer(
- BaseValue, MemoryLocation::UnknownSize, AATags);
+ BP->getValue(), MemoryLocation::UnknownSize, AATags);
if (!AS.isMustAlias()) {
if (PollyUseRuntimeAliasChecks) {
@@ -845,9 +888,9 @@ bool ScopDetection::isValidMemoryAccess(
// However, we can ignore loads that will be hoisted.
for (const auto &Ptr : AS) {
Instruction *Inst = dyn_cast<Instruction>(Ptr.getValue());
- if (Inst && CurRegion.contains(Inst)) {
+ if (Inst && Context.CurRegion.contains(Inst)) {
auto *Load = dyn_cast<LoadInst>(Inst);
- if (Load && isHoistableLoad(Load, CurRegion, *LI, *SE)) {
+ if (Load && isHoistableLoad(Load, Context.CurRegion, *LI, *SE)) {
Context.RequiredILS.insert(Load);
continue;
}
@@ -866,6 +909,18 @@ bool ScopDetection::isValidMemoryAccess(
return true;
}
+bool ScopDetection::isValidMemoryAccess(MemAccInst Inst,
+ DetectionContext &Context) const {
+ Value *Ptr = Inst.getPointerOperand();
+ Loop *L = LI->getLoopFor(Inst.getParent());
+ const SCEV *AccessFunction = SE->getSCEVAtScope(Ptr, L);
+ const SCEVUnknown *BasePointer;
+
+ BasePointer = dyn_cast<SCEVUnknown>(SE->getPointerBase(AccessFunction));
+
+ return isValidAccess(Inst, AccessFunction, BasePointer, Context);
+}
+
bool ScopDetection::isValidInstruction(Instruction &Inst,
DetectionContext &Context) const {
for (auto &Op : Inst.operands()) {
@@ -880,7 +935,7 @@ bool ScopDetection::isValidInstruction(I
// We only check the call instruction but not invoke instruction.
if (CallInst *CI = dyn_cast<CallInst>(&Inst)) {
- if (isValidCallInst(*CI))
+ if (isValidCallInst(*CI, Context))
return true;
return invalid<ReportFuncCall>(Context, /*Assert=*/true, &Inst);
Modified: polly/trunk/lib/Analysis/ScopInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Analysis/ScopInfo.cpp?rev=261489&r1=261488&r2=261489&view=diff
==============================================================================
--- polly/trunk/lib/Analysis/ScopInfo.cpp (original)
+++ polly/trunk/lib/Analysis/ScopInfo.cpp Sun Feb 21 13:13:19 2016
@@ -303,7 +303,10 @@ void MemoryAccess::updateDimensionality(
auto DimsAccess = isl_space_dim(AccessSpace, isl_dim_set);
auto DimsMissing = DimsArray - DimsAccess;
+ auto *BB = getStatement()->getParent()->getRegion().getEntry();
+ auto &DL = BB->getModule()->getDataLayout();
unsigned ArrayElemSize = SAI->getElemSizeInBytes();
+ unsigned ElemBytes = DL.getTypeAllocSize(getElementType());
auto *Map = isl_map_from_domain_and_range(
isl_set_universe(AccessSpace),
@@ -612,10 +615,34 @@ void MemoryAccess::assumeNoOutOfBound()
isl_space_free(Space);
}
+void MemoryAccess::buildMemIntrinsicAccessRelation() {
+ auto MAI = MemAccInst(getAccessInstruction());
+ 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);
+ 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());
+}
+
void MemoryAccess::computeBoundsOnAccessRelation(unsigned ElementSize) {
ScalarEvolution *SE = Statement->getParent()->getSE();
- Value *Ptr = MemAccInst(getAccessInstruction()).getPointerOperand();
+ auto MAI = MemAccInst(getAccessInstruction());
+ if (MAI.isMemIntrinsic())
+ return;
+
+ Value *Ptr = MAI.getPointerOperand();
if (!Ptr || !SE->isSCEVable(Ptr->getType()))
return;
@@ -731,11 +758,16 @@ void MemoryAccess::buildAccessRelation(c
isl_id *BaseAddrId = SAI->getBasePtrId();
if (!isAffine()) {
+ if (isa<MemIntrinsic>(getAccessInstruction()))
+ buildMemIntrinsicAccessRelation();
+
// We overapproximate non-affine accesses with a possible access to the
// whole array. For read accesses it does not make a difference, if an
// access must or may happen. However, for write accesses it is important to
// differentiate between writes that must happen and writes that may happen.
- AccessRelation = isl_map_from_basic_map(createBasicAccessMap(Statement));
+ if (!AccessRelation)
+ AccessRelation = isl_map_from_basic_map(createBasicAccessMap(Statement));
+
AccessRelation =
isl_map_set_tuple_id(AccessRelation, isl_dim_out, BaseAddrId);
return;
@@ -764,19 +796,19 @@ void MemoryAccess::buildAccessRelation(c
}
MemoryAccess::MemoryAccess(ScopStmt *Stmt, Instruction *AccessInst,
- AccessType Type, Value *BaseAddress,
- unsigned ElemBytes, bool Affine,
+ AccessType AccType, Value *BaseAddress,
+ Type *ElementType, bool Affine,
ArrayRef<const SCEV *> Subscripts,
ArrayRef<const SCEV *> Sizes, Value *AccessValue,
ScopArrayInfo::MemoryKind Kind, StringRef BaseName)
- : Kind(Kind), AccType(Type), RedType(RT_NONE), Statement(Stmt),
- BaseAddr(BaseAddress), BaseName(BaseName), ElemBytes(ElemBytes),
+ : Kind(Kind), AccType(AccType), RedType(RT_NONE), Statement(Stmt),
+ BaseAddr(BaseAddress), BaseName(BaseName), ElementType(ElementType),
Sizes(Sizes.begin(), Sizes.end()), AccessInstruction(AccessInst),
AccessValue(AccessValue), IsAffine(Affine),
Subscripts(Subscripts.begin(), Subscripts.end()), AccessRelation(nullptr),
NewAccessRelation(nullptr) {
static const std::string TypeStrings[] = {"", "_Read", "_Write", "_MayWrite"};
- const std::string Access = TypeStrings[Type] + utostr(Stmt->size()) + "_";
+ const std::string Access = TypeStrings[AccType] + utostr(Stmt->size()) + "_";
std::string IdName =
getIslCompatibleName(Stmt->getBaseName(), Access, BaseName);
@@ -948,7 +980,7 @@ void ScopStmt::restrictDomain(__isl_take
void ScopStmt::buildAccessRelations() {
Scop &S = *getParent();
for (MemoryAccess *Access : MemAccs) {
- Type *ElementType = Access->getAccessValue()->getType();
+ Type *ElementType = Access->getElementType();
ScopArrayInfo::MemoryKind Ty;
if (Access->isPHIKind())
@@ -2566,7 +2598,10 @@ bool Scop::buildAliasGroups(AliasAnalysi
if (!MA->isRead())
HasWriteAccess.insert(MA->getBaseAddr());
MemAccInst Acc(MA->getAccessInstruction());
- PtrToAcc[Acc.getPointerOperand()] = MA;
+ if (MA->isRead() && Acc.isMemTransferInst())
+ PtrToAcc[Acc.asMemTransferInst()->getSource()] = MA;
+ else
+ PtrToAcc[Acc.getPointerOperand()] = MA;
AST.add(Acc);
}
}
@@ -2578,8 +2613,8 @@ bool Scop::buildAliasGroups(AliasAnalysi
AliasGroupTy AG;
for (auto &PR : AS)
AG.push_back(PtrToAcc[PR.getValue()]);
- assert(AG.size() > 1 &&
- "Alias groups should contain at least two accesses");
+ if (AG.size() < 2)
+ continue;
AliasGroups.push_back(std::move(AG));
}
@@ -3774,8 +3809,7 @@ bool ScopInfo::buildAccessMultiDimFixed(
const ScopDetection::BoxedLoopsSetTy *BoxedLoops,
const InvariantLoadsSetTy &ScopRIL) {
Value *Val = Inst.getValueOperand();
- Type *SizeType = Val->getType();
- unsigned ElementSize = DL->getTypeAllocSize(SizeType);
+ Type *ElementType = Val->getType();
Value *Address = Inst.getPointerOperand();
const SCEV *AccessFunction = SE->getSCEVAtScope(Address, L);
const SCEVUnknown *BasePointer =
@@ -3816,7 +3850,7 @@ bool ScopInfo::buildAccessMultiDimFixed(
SizesSCEV.push_back(SE->getSCEV(ConstantInt::get(
IntegerType::getInt64Ty(BasePtr->getContext()), V)));
- addArrayAccess(Inst, Type, BasePointer->getValue(), ElementSize, true,
+ addArrayAccess(Inst, Type, BasePointer->getValue(), ElementType, true,
Subscripts, SizesSCEV, Val);
return true;
}
@@ -3831,8 +3865,8 @@ bool ScopInfo::buildAccessMultiDimParam(
const InvariantLoadsSetTy &ScopRIL, const MapInsnToMemAcc &InsnToMemAcc) {
Value *Address = Inst.getPointerOperand();
Value *Val = Inst.getValueOperand();
- Type *SizeType = Val->getType();
- unsigned ElementSize = DL->getTypeAllocSize(SizeType);
+ Type *ElementType = Val->getType();
+ unsigned ElementSize = DL->getTypeAllocSize(ElementType);
enum MemoryAccess::AccessType Type =
Inst.isLoad() ? MemoryAccess::READ : MemoryAccess::MUST_WRITE;
@@ -3860,21 +3894,58 @@ bool ScopInfo::buildAccessMultiDimParam(
if (ElementSize != DelinearizedSize)
scop->invalidate(DELINEARIZATION, Inst.getDebugLoc());
- addArrayAccess(Inst, Type, BasePointer->getValue(), ElementSize, true,
+ addArrayAccess(Inst, Type, BasePointer->getValue(), ElementType, true,
AccItr->second.DelinearizedSubscripts, Sizes, Val);
return true;
}
return false;
}
+bool ScopInfo::buildAccessMemIntrinsic(
+ MemAccInst Inst, Loop *L, Region *R,
+ const ScopDetection::BoxedLoopsSetTy *BoxedLoops,
+ const InvariantLoadsSetTy &ScopRIL) {
+ if (!Inst.isMemIntrinsic())
+ return false;
+
+ auto *LengthVal = SE->getSCEVAtScope(Inst.asMemIntrinsic()->getLength(), L);
+ assert(LengthVal);
+
+ auto *DestPtrVal = Inst.asMemIntrinsic()->getDest();
+ assert(DestPtrVal);
+ auto *DestAccFunc = SE->getSCEVAtScope(DestPtrVal, L);
+ assert(DestAccFunc);
+ auto *DestPtrSCEV = dyn_cast<SCEVUnknown>(SE->getPointerBase(DestAccFunc));
+ assert(DestPtrSCEV);
+ DestAccFunc = SE->getMinusSCEV(DestAccFunc, DestPtrSCEV);
+ addArrayAccess(Inst, MemoryAccess::MUST_WRITE, DestPtrSCEV->getValue(),
+ IntegerType::getInt8Ty(DestPtrVal->getContext()), false,
+ {DestAccFunc, LengthVal}, {}, Inst.getValueOperand());
+
+ if (!Inst.isMemTransferInst())
+ return true;
+
+ auto *SrcPtrVal = Inst.asMemTransferInst()->getSource();
+ assert(SrcPtrVal);
+ auto *SrcAccFunc = SE->getSCEVAtScope(SrcPtrVal, L);
+ assert(SrcAccFunc);
+ auto *SrcPtrSCEV = dyn_cast<SCEVUnknown>(SE->getPointerBase(SrcAccFunc));
+ assert(SrcPtrSCEV);
+ SrcAccFunc = SE->getMinusSCEV(SrcAccFunc, SrcPtrSCEV);
+ addArrayAccess(Inst, MemoryAccess::READ, SrcPtrSCEV->getValue(),
+ IntegerType::getInt8Ty(SrcPtrVal->getContext()), false,
+ {SrcAccFunc, LengthVal}, {}, Inst.getValueOperand());
+
+ return true;
+}
+
void ScopInfo::buildAccessSingleDim(
MemAccInst Inst, Loop *L, Region *R,
const ScopDetection::BoxedLoopsSetTy *BoxedLoops,
const InvariantLoadsSetTy &ScopRIL) {
Value *Address = Inst.getPointerOperand();
Value *Val = Inst.getValueOperand();
- Type *SizeType = Val->getType();
- unsigned ElementSize = DL->getTypeAllocSize(SizeType);
+ Type *ElementType = Val->getType();
enum MemoryAccess::AccessType Type =
Inst.isLoad() ? MemoryAccess::READ : MemoryAccess::MUST_WRITE;
@@ -3907,7 +3978,7 @@ void ScopInfo::buildAccessSingleDim(
if (!IsAffine && Type == MemoryAccess::MUST_WRITE)
Type = MemoryAccess::MAY_WRITE;
- addArrayAccess(Inst, Type, BasePointer->getValue(), ElementSize, IsAffine,
+ addArrayAccess(Inst, Type, BasePointer->getValue(), ElementType, IsAffine,
{AccessFunction}, {}, Val);
}
@@ -3916,6 +3987,9 @@ void ScopInfo::buildMemoryAccess(
const ScopDetection::BoxedLoopsSetTy *BoxedLoops,
const InvariantLoadsSetTy &ScopRIL, const MapInsnToMemAcc &InsnToMemAcc) {
+ if (buildAccessMemIntrinsic(Inst, L, R, BoxedLoops, ScopRIL))
+ return;
+
if (buildAccessMultiDimFixed(Inst, L, R, BoxedLoops, ScopRIL))
return;
@@ -3999,8 +4073,8 @@ void ScopInfo::buildAccessFunctions(Regi
}
MemoryAccess *ScopInfo::addMemoryAccess(BasicBlock *BB, Instruction *Inst,
- MemoryAccess::AccessType Type,
- Value *BaseAddress, unsigned ElemBytes,
+ MemoryAccess::AccessType AccType,
+ Value *BaseAddress, Type *ElementType,
bool Affine, Value *AccessValue,
ArrayRef<const SCEV *> Subscripts,
ArrayRef<const SCEV *> Sizes,
@@ -4037,24 +4111,23 @@ MemoryAccess *ScopInfo::addMemoryAccess(
if (Kind == ScopArrayInfo::MK_PHI || Kind == ScopArrayInfo::MK_ExitPHI)
isKnownMustAccess = true;
- if (!isKnownMustAccess && Type == MemoryAccess::MUST_WRITE)
- Type = MemoryAccess::MAY_WRITE;
+ if (!isKnownMustAccess && AccType == MemoryAccess::MUST_WRITE)
+ AccType = MemoryAccess::MAY_WRITE;
- AccList.emplace_back(Stmt, Inst, Type, BaseAddress, ElemBytes, Affine,
+ AccList.emplace_back(Stmt, Inst, AccType, BaseAddress, ElementType, Affine,
Subscripts, Sizes, AccessValue, Kind, BaseName);
Stmt->addAccess(&AccList.back());
return &AccList.back();
}
void ScopInfo::addArrayAccess(MemAccInst MemAccInst,
- MemoryAccess::AccessType Type, Value *BaseAddress,
- unsigned ElemBytes, bool IsAffine,
- ArrayRef<const SCEV *> Subscripts,
+ MemoryAccess::AccessType AccType,
+ Value *BaseAddress, Type *ElementType,
+ bool IsAffine, ArrayRef<const SCEV *> Subscripts,
ArrayRef<const SCEV *> Sizes,
Value *AccessValue) {
- assert(MemAccInst.isLoad() == (Type == MemoryAccess::READ));
- addMemoryAccess(MemAccInst.getParent(), MemAccInst, Type, BaseAddress,
- ElemBytes, IsAffine, AccessValue, Subscripts, Sizes,
+ addMemoryAccess(MemAccInst.getParent(), MemAccInst, AccType, BaseAddress,
+ ElementType, IsAffine, AccessValue, Subscripts, Sizes,
ScopArrayInfo::MK_Array);
}
@@ -4069,8 +4142,8 @@ void ScopInfo::ensureValueWrite(Instruct
if (Stmt->lookupValueWriteOf(Inst))
return;
- addMemoryAccess(Inst->getParent(), Inst, MemoryAccess::MUST_WRITE, Inst, 1,
- true, Inst, ArrayRef<const SCEV *>(),
+ addMemoryAccess(Inst->getParent(), Inst, MemoryAccess::MUST_WRITE, Inst,
+ Inst->getType(), true, Inst, ArrayRef<const SCEV *>(),
ArrayRef<const SCEV *>(), ScopArrayInfo::MK_Value);
}
@@ -4119,7 +4192,7 @@ void ScopInfo::ensureValueRead(Value *V,
if (UserStmt->lookupValueReadOf(V))
return;
- addMemoryAccess(UserBB, nullptr, MemoryAccess::READ, V, 1, true, V,
+ addMemoryAccess(UserBB, nullptr, MemoryAccess::READ, V, V->getType(), true, V,
ArrayRef<const SCEV *>(), ArrayRef<const SCEV *>(),
ScopArrayInfo::MK_Value);
if (ValueInst)
@@ -4149,7 +4222,7 @@ void ScopInfo::ensurePHIWrite(PHINode *P
MemoryAccess *Acc = addMemoryAccess(
IncomingStmt->isBlockStmt() ? IncomingBlock
: IncomingStmt->getRegion()->getEntry(),
- PHI, MemoryAccess::MUST_WRITE, PHI, 1, true, PHI,
+ PHI, MemoryAccess::MUST_WRITE, PHI, PHI->getType(), true, PHI,
ArrayRef<const SCEV *>(), ArrayRef<const SCEV *>(),
IsExitBlock ? ScopArrayInfo::MK_ExitPHI : ScopArrayInfo::MK_PHI);
assert(Acc);
@@ -4157,9 +4230,9 @@ void ScopInfo::ensurePHIWrite(PHINode *P
}
void ScopInfo::addPHIReadAccess(PHINode *PHI) {
- addMemoryAccess(PHI->getParent(), PHI, MemoryAccess::READ, PHI, 1, true, PHI,
- ArrayRef<const SCEV *>(), ArrayRef<const SCEV *>(),
- ScopArrayInfo::MK_PHI);
+ addMemoryAccess(PHI->getParent(), PHI, MemoryAccess::READ, PHI,
+ PHI->getType(), true, PHI, ArrayRef<const SCEV *>(),
+ ArrayRef<const SCEV *>(), ScopArrayInfo::MK_PHI);
}
void ScopInfo::buildScop(Region &R, AssumptionCache &AC) {
Added: polly/trunk/test/ScopInfo/memcpy.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/ScopInfo/memcpy.ll?rev=261489&view=auto
==============================================================================
--- polly/trunk/test/ScopInfo/memcpy.ll (added)
+++ polly/trunk/test/ScopInfo/memcpy.ll Sun Feb 21 13:13:19 2016
@@ -0,0 +1,80 @@
+; RUN: opt %loadPolly -basicaa -polly-allow-differing-element-types -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -S -basicaa -polly-allow-differing-element-types -polly-codegen < %s | FileCheck --check-prefix=IR %s
+;
+; CHECK: Arrays {
+; CHECK-NEXT: i8 MemRef_A[*]; // Element size 1
+; CHECK-NEXT: i8 MemRef_B[*]; // Element size 1
+; CHECK-NEXT: }
+; CHECK: Statements {
+; CHECK-NEXT: Stmt_for_body3
+; CHECK-NEXT: Domain :=
+; CHECK-NEXT: { Stmt_for_body3[i0, i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 };
+; CHECK-NEXT: Schedule :=
+; CHECK-NEXT: { Stmt_for_body3[i0, i1] -> [i0, i1] };
+; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT: { Stmt_for_body3[i0, i1] -> MemRef_A[o0] : -16 <= o0 <= 20 };
+; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT: { Stmt_for_body3[i0, i1] -> MemRef_B[o0] : 64 <= o0 <= 100 };
+;
+; IR: polly.loop_preheader:
+; IR: %[[r1:[a-zA-Z0-9]*]] = getelementptr i32, i32* %A, i64 -4
+; IR: %[[r2:[a-zA-Z0-9]*]] = bitcast i32* %scevgep to i8*
+; IR: %[[r3:[a-zA-Z0-9]*]] = getelementptr i64, i64* %B, i64 8
+; IR: %[[r4:[a-zA-Z0-9]*]] = bitcast i64* %scevgep8 to i8*
+;
+; IR: polly.stmt.for.body3:
+; IR: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %[[r2]], i8* %[[r4]], i64 37, i32 4, i1 false)
+;
+;
+; #include <string.h>
+;
+; void jd(int *restrict A, long *restrict B) {
+; for (int i = 0; i < 1024; i++)
+; for (int j = 0; j < 1024; j++)
+; memcpy(A - 4, B + 8, 37);
+; }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* noalias %A, i64* noalias %B) {
+entry:
+ br label %for.cond
+
+for.cond: ; preds = %for.inc5, %entry
+ %i.0 = phi i32 [ 0, %entry ], [ %inc6, %for.inc5 ]
+ %exitcond1 = icmp ne i32 %i.0, 1024
+ br i1 %exitcond1, label %for.body, label %for.end7
+
+for.body: ; preds = %for.cond
+ br label %for.cond1
+
+for.cond1: ; preds = %for.inc, %for.body
+ %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+ %exitcond = icmp ne i32 %j.0, 1024
+ br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3: ; preds = %for.cond1
+ %add.ptr = getelementptr inbounds i32, i32* %A, i64 -4
+ %tmp = bitcast i32* %add.ptr to i8*
+ %add.ptr4 = getelementptr inbounds i64, i64* %B, i64 8
+ %tmp2 = bitcast i64* %add.ptr4 to i8*
+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* %tmp, i8* %tmp2, i64 37, i32 4, i1 false)
+ br label %for.inc
+
+for.inc: ; preds = %for.body3
+ %inc = add nsw i32 %j.0, 1
+ br label %for.cond1
+
+for.end: ; preds = %for.cond1
+ br label %for.inc5
+
+for.inc5: ; preds = %for.end
+ %inc6 = add nsw i32 %i.0, 1
+ br label %for.cond
+
+for.end7: ; preds = %for.cond
+ ret void
+}
+
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #1
+
Added: polly/trunk/test/ScopInfo/memmove.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/ScopInfo/memmove.ll?rev=261489&view=auto
==============================================================================
--- polly/trunk/test/ScopInfo/memmove.ll (added)
+++ polly/trunk/test/ScopInfo/memmove.ll Sun Feb 21 13:13:19 2016
@@ -0,0 +1,79 @@
+; RUN: opt %loadPolly -basicaa -polly-allow-differing-element-types -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -S -basicaa -polly-allow-differing-element-types -polly-codegen < %s | FileCheck --check-prefix=IR %s
+;
+; CHECK: Arrays {
+; CHECK-NEXT: i8 MemRef_A[*]; // Element size 1
+; CHECK-NEXT: i8 MemRef_B[*]; // Element size 1
+; CHECK-NEXT: }
+; CHECK: Statements {
+; CHECK-NEXT: Stmt_for_body3
+; CHECK-NEXT: Domain :=
+; CHECK-NEXT: { Stmt_for_body3[i0, i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 };
+; CHECK-NEXT: Schedule :=
+; CHECK-NEXT: { Stmt_for_body3[i0, i1] -> [i0, i1] };
+; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT: { Stmt_for_body3[i0, i1] -> MemRef_A[o0] : -16 <= o0 <= 15 };
+; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT: { Stmt_for_body3[i0, i1] -> MemRef_B[o0] : 64 <= o0 <= 95 };
+;
+; IR: polly.loop_preheader:
+; IR: %[[r1:[a-zA-Z0-9]*]] = getelementptr i32, i32* %A, i64 -4
+; IR: %[[r2:[a-zA-Z0-9]*]] = bitcast i32* %scevgep to i8*
+; IR: %[[r3:[a-zA-Z0-9]*]] = getelementptr i64, i64* %B, i64 8
+; IR: %[[r4:[a-zA-Z0-9]*]] = bitcast i64* %scevgep8 to i8*
+;
+; IR: polly.stmt.for.body3:
+; IR: call void @llvm.memmove.p0i8.p0i8.i64(i8* %[[r2]], i8* %[[r4]], i64 32, i32 4, i1 false)
+;
+; #include <string.h>
+;
+; void jd(int *restrict A, long *restrict B) {
+; for (int i = 0; i < 1024; i++)
+; for (int j = 0; j < 1024; j++)
+; memmove(A - 4, B + 8, 32);
+; }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* noalias %A, i64* noalias %B) {
+entry:
+ br label %for.cond
+
+for.cond: ; preds = %for.inc5, %entry
+ %i.0 = phi i32 [ 0, %entry ], [ %inc6, %for.inc5 ]
+ %exitcond1 = icmp ne i32 %i.0, 1024
+ br i1 %exitcond1, label %for.body, label %for.end7
+
+for.body: ; preds = %for.cond
+ br label %for.cond1
+
+for.cond1: ; preds = %for.inc, %for.body
+ %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+ %exitcond = icmp ne i32 %j.0, 1024
+ br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3: ; preds = %for.cond1
+ %add.ptr = getelementptr inbounds i32, i32* %A, i64 -4
+ %tmp = bitcast i32* %add.ptr to i8*
+ %add.ptr4 = getelementptr inbounds i64, i64* %B, i64 8
+ %tmp2 = bitcast i64* %add.ptr4 to i8*
+ call void @llvm.memmove.p0i8.p0i8.i64(i8* %tmp, i8* %tmp2, i64 32, i32 4, i1 false)
+ br label %for.inc
+
+for.inc: ; preds = %for.body3
+ %inc = add nsw i32 %j.0, 1
+ br label %for.cond1
+
+for.end: ; preds = %for.cond1
+ br label %for.inc5
+
+for.inc5: ; preds = %for.end
+ %inc6 = add nsw i32 %i.0, 1
+ br label %for.cond
+
+for.end7: ; preds = %for.cond
+ ret void
+}
+
+declare void @llvm.memmove.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #1
+
Added: polly/trunk/test/ScopInfo/memset.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/ScopInfo/memset.ll?rev=261489&view=auto
==============================================================================
--- polly/trunk/test/ScopInfo/memset.ll (added)
+++ polly/trunk/test/ScopInfo/memset.ll Sun Feb 21 13:13:19 2016
@@ -0,0 +1,69 @@
+; RUN: opt %loadPolly -polly-allow-differing-element-types -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -S -polly-allow-differing-element-types -polly-codegen < %s | FileCheck --check-prefix=IR %s
+;
+; CHECK: Arrays {
+; CHECK-NEXT: i8 MemRef_A[*]; // Element size 1
+; CHECK-NEXT: }
+; CHECK: Statements {
+; CHECK-NEXT: Stmt_for_body3
+; CHECK-NEXT: Domain :=
+; CHECK-NEXT: { Stmt_for_body3[i0, i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 };
+; CHECK-NEXT: Schedule :=
+; CHECK-NEXT: { Stmt_for_body3[i0, i1] -> [i0, i1] };
+; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT: { Stmt_for_body3[i0, i1] -> MemRef_A[o0] : 0 <= o0 <= 186 };
+;
+; IR: %[[r1:[a-zA-Z0-9]*]] = bitcast i32* %A to i8*
+;
+; IR: polly.stmt.for.body3:
+; IR: call void @llvm.memset.p0i8.i64(i8* %[[r1]], i8 36, i64 187, i32 4, i1 false)
+;
+; #include <string.h>
+;
+; void jd(int *A) {
+; for (int i = 0; i < 1024; i++)
+; for (int j = 0; j < 1024; j++)
+; memset(A, '$', 187);
+; }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* noalias %A) {
+entry:
+ br label %for.cond
+
+for.cond: ; preds = %for.inc4, %entry
+ %i.0 = phi i32 [ 0, %entry ], [ %inc5, %for.inc4 ]
+ %exitcond1 = icmp ne i32 %i.0, 1024
+ br i1 %exitcond1, label %for.body, label %for.end6
+
+for.body: ; preds = %for.cond
+ br label %for.cond1
+
+for.cond1: ; preds = %for.inc, %for.body
+ %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+ %exitcond = icmp ne i32 %j.0, 1024
+ br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3: ; preds = %for.cond1
+ %tmp = bitcast i32* %A to i8*
+ call void @llvm.memset.p0i8.i64(i8* %tmp, i8 36, i64 187, i32 4, i1 false)
+ br label %for.inc
+
+for.inc: ; preds = %for.body3
+ %inc = add nsw i32 %j.0, 1
+ br label %for.cond1
+
+for.end: ; preds = %for.cond1
+ br label %for.inc4
+
+for.inc4: ; preds = %for.end
+ %inc5 = add nsw i32 %i.0, 1
+ br label %for.cond
+
+for.end6: ; preds = %for.cond
+ ret void
+}
+
+declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) #1
+
More information about the llvm-commits
mailing list