[LLVMdev] How to make Polly ignore some non-affine memory accesses
Tobias Grosser
tobias at grosser.es
Mon Nov 14 00:41:59 PST 2011
On 11/14/2011 01:24 AM, Marcello Maggioni wrote:
> Hi Tobias.
>
> I worked on enabling Polly accepting non affine memory accesses and I
> produced a patch.
Great.
> I saw that there were a lot of updates in Polly recently, so I had to
> redo a lot of the work I did and that slowed me quite a bit.
Ups, sorry! However, I believe without these changes detecting
non-affine memory access functions would have been a lot more complicated.
> I tested the patch on some programs and it seems to work and not to
> break anything, but you know the topic much better than me, so if you
> find something wrong please tell me! (at least it shouldn't produce a
> crash I believe ... I tested the patch quite a lot from that point of
> view ...). The patch is in the attachment to this mail and was last
> tested on LLVM SVN revision 144502 .
OK. Review is inlined in the patch.
> I also found a bug in polly or ISL/GMP libraries. If polly encounters
> an array access of type:
>
> A[i][i]
>
> it enters an infinite loop (I believe it is an infinite loop because I
> waited 5 minutes and it didn't terminate compiling a code that was
> like 15 lines long). I tried to track down the problem with gdb , but
> it seems to be in some gmp function called by ISL of which I'm not a
> very expert of.
[remove backtrace & code]
> I actually don't know if it is an ISL bug or an improper use by polly.
> To compile isl I use gmp-5.0.2
I will look into this.
> --- ./include/polly/ScopDetection.h 2011-11-13 02:37:59.000000000 +0100
> +++ ../llvm2/tools/polly/./include/polly/ScopDetection.h 2011-11-13 01:11:17.000000000 +0100
> @@ -145,6 +145,8 @@
> /// @return True if the call instruction is valid, false otherwise.
> static bool isValidCallInst(CallInst&CI);
>
> + const Value *GetBaseValue(const SCEV *S) const;
Why is this function needed? For me it looks like it implements
the same as
SCEVValue *Operand = dyn_cast<SCEVValue>(getPointerOperand())
if (!Operand)
return invalid Value;
return Operand->getValue();
> /// @brief Check if a memory access can be part of a Scop.
> ///
> /// @param Inst The instruction accessing the memory.
> --- ./include/polly/TempScopInfo.h 2011-11-13 02:37:59.000000000 +0100
> +++ ../llvm2/tools/polly/./include/polly/TempScopInfo.h 2011-11-13 02:34:47.000000000 +0100
> @@ -45,12 +45,13 @@
> private:
> unsigned ElemBytes;
> TypeKind Type;
> + bool is_affine;
I think IsAffine matches more the LLVM coding conventions.
>
> public:
> explicit IRAccess (TypeKind Type, const Value *BaseAddress,
> - const SCEV *Offset, unsigned elemBytes)
> + const SCEV *Offset, unsigned elemBytes, bool affine)
'affine' should start with an uppercase letter. Polly itself has some
inconsistent naming, but we started to follow the LLVM coding
conventions since a while.
> : BaseAddress(BaseAddress), Offset(Offset),
> - ElemBytes(elemBytes), Type(Type) {}
> + ElemBytes(elemBytes), Type(Type), is_affine(affine) {}
>
> enum TypeKind getType() const { return Type; }
>
> @@ -60,7 +61,10 @@
>
> unsigned getElemSizeInBytes() const { return ElemBytes; }
>
> + bool isAffine() const { return is_affine; }
> +
> bool isRead() const { return Type == READ; }
> +
> };
>
> class Comparison {
> --- ./lib/Analysis/ScopDetection.cpp 2011-11-13 02:38:06.000000000 +0100
> +++ ../llvm2/tools/polly/./lib/Analysis/ScopDetection.cpp 2011-11-13 01:28:00.000000000 +0100
> @@ -226,6 +226,24 @@
> return false;
> }
>
> +const Value *ScopDetection::GetBaseValue(const SCEV *S) const {
> + if (const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(S)) {
> + // In an addrec, assume that the base will be in the start, rather
> + // than the step.
> + return GetBaseValue(AR->getStart());
> + } else if (const SCEVAddExpr *A = dyn_cast<SCEVAddExpr>(S)) {
> + // If there's a pointer operand, it'll be sorted at the end of the list.
> + const SCEV *Last = A->getOperand(A->getNumOperands()-1);
> + if (Last->getType()->isPointerTy())
> + return GetBaseValue(Last);
> + } else if (const SCEVUnknown *U = dyn_cast<SCEVUnknown>(S)) {
> + // This is a leaf node.
> + return U->getValue();
> + }
> + // No Identified object found.
> + return 0;
> +}
As remarked earlier, I believ this can be replaced by getPointerOperand().
> bool ScopDetection::isValidMemoryAccess(Instruction&Inst,
> DetectionContext&Context) const {
> Value *Ptr = getPointerOperand(Inst);
> @@ -236,8 +254,12 @@
> BasePointer = dyn_cast<SCEVUnknown>(SE->getPointerBase(AccessFunction));
>
> if (!BasePointer)
> - INVALID(AffFunc, "No base pointer");
> -
> + {
> +// INVALID(AffFunc, "No base pointer");
> + BaseValue = (Value*) GetBaseValue(AccessFunction);
> + }
> + else
> + {
> BaseValue = BasePointer->getValue();
I don't see a need for any change here. Both functions get the base
pointer and we should fail, if we cannot derive a base pointer. Do you
have a test case where getPointerBase() does not yield a valid base
pointer, but GetBaseValue(AccessFunction) does?
> if (isa<UndefValue>(BaseValue))
> @@ -245,8 +267,9 @@
>
> AccessFunction = SE->getMinusSCEV(AccessFunction, BasePointer);
>
> - if (!isAffineExpr(&Context.CurRegion, AccessFunction, *SE, BaseValue))
> - INVALID(AffFunc, "Bad memory address "<< *AccessFunction);
> + //if (!isAffineExpr(&Context.CurRegion, AccessFunction, *SE, BaseValue))
> + // INVALID(AffFunc, "Bad memory address "<< *AccessFunction);
Can you leave this and add a command line option
'-polly-allow-nonaffine' to allow non affine access functions.
> + }
>
> // FIXME: Alias Analysis thinks IntToPtrInst aliases with alloca instructions
> // created by IndependentBlocks Pass.
> --- ./lib/Analysis/ScopInfo.cpp 2011-11-13 02:38:06.000000000 +0100
> +++ ../llvm2/tools/polly/./lib/Analysis/ScopInfo.cpp 2011-11-13 02:36:12.000000000 +0100
> @@ -310,9 +310,13 @@
> Type = Access.isRead() ? Read : Write;
> statement = Statement;
>
> - isl_pw_aff *Affine = SCEVAffinator::getPwAff(Statement, Access.getOffset());
> BaseAddr = Access.getBase();
>
> + if (Access.isAffine())
> + {
This should be
if (Access.isAffine()) {
> +
> + isl_pw_aff *Affine = SCEVAffinator::getPwAff(Statement, Access.getOffset());
> +
> setBaseName();
>
> // Devide the access function by the size of the elements in the array.
> @@ -334,6 +338,12 @@
> AccessRelation = isl_map_set_tuple_name(AccessRelation, isl_dim_out,
> getBaseName().c_str());
> }
> + else
> + {
this should be
} else {
> + Type = MayWrite;
You are right, we should use may-accesses here. But why always setting
the type to may-write? A read should remain a read (as there is no
difference between read and may-read).
> + AccessRelation = isl_map_from_basic_map(createBasicAccessMap(Statement));
> + }
> +}
>
> void MemoryAccess::realignParams() {
> isl_space *ParamSpace = statement->getParent()->getParamSpace();
> --- ./lib/Analysis/TempScopInfo.cpp 2011-11-13 02:38:06.000000000 +0100
> +++ ../llvm2/tools/polly/./lib/Analysis/TempScopInfo.cpp 2011-11-13 02:35:22.000000000 +0100
> @@ -98,13 +98,24 @@
> dyn_cast<SCEVUnknown>(SE->getPointerBase(AccessFunction));
>
> assert(BasePointer&& "Could not find base pointer");
> -
> AccessFunction = SE->getMinusSCEV(AccessFunction, BasePointer);
> +
> + if (isAffineExpr(&R, AccessFunction, *SE, BasePointer->getValue()))
> + {
Put the '{' in the previous line.
> +
> Functions.push_back(std::make_pair(IRAccess(Type,
> BasePointer->getValue(),
> - AccessFunction, Size),
> + AccessFunction, Size, true),
> &Inst));
> }
> + else
> + {
This should be
} else {
> + Functions.push_back(std::make_pair(IRAccess(Type,
> + BasePointer->getValue(),
> + AccessFunction, Size, false),
> +&Inst));
> + }
> + }
> }
>
> if (Functions.empty())
Besides the comments above, the patch looks great. It is a nice
improvement to Polly. Can you repost it after the comments are
addressed? Also could you include a minimal test case in the patch, that
verifies this features is working correctly.
Thanks
Tobi
P.S.: Please post patches to the mailing lists.
More information about the llvm-dev
mailing list