[llvm-commits] [PATCH] BasicBlock Autovectorization Pass

Tobias Grosser tobias at grosser.es
Fri Nov 11 15:37:35 PST 2011


On 11/12/2011 12:11 AM, Hal Finkel wrote:
> On Fri, 2011-11-11 at 23:55 +0100, Tobias Grosser wrote:
>> On 11/11/2011 11:36 PM, Hal Finkel wrote:
>>> On Thu, 2011-11-10 at 23:07 +0100, Tobias Grosser wrote:
>>>> On 11/08/2011 11:29 PM, Hal Finkel wrote: Talking about this I
>>>> looked again into ScalarEvolution.
>>>>
>>>> To analyze a load, you would do:
>>>>
>>>> LoadInst *Load = ... Value *Pointer = Load->getPointer(); const
>>>> SCEV *PointerSCEV = SE->getSCEV(Pointer); const SCEVUnknown
>>>> *PointerBase =
>>>> dyn_cast<SCEVUnknown>(SE->getPointerBase(PointerSCEV));
>>>>
>>>> if (!PointerBase) return 'Analysis failed'
>>>>
>>>> const Value *BaseValue = PointerBase->getValue();
>>>>
>>>> You get the offset between two load addresses with
>>>> SE->getMinusSCEV(). The size of an element is
>>>> SE->getSizeOfExpr().
>>>>
>>>
>>> The AliasAnalysis class has a set of interfaces that can be used
>>> to preserve the analysis even when some things are changed. Does
>>> ScalarEvolution have a similar capability?
>>
>> You can state that your pass preserves ScalarEvolution. In this
>> case all analysis results are by default preserved and it is your
>> job to invalidate the scalar evolution for the loops/values where
>> it needs to be recalculated.
>>
>> The relevant functions are
>>
>> ScalarEvolution::forgetValue(Value *)
>
> Since the vectorization pass is currently just a basic-block pass, I
> think that I should need only forgetValue, right? I suppose that I
> would call that on all of the values that are fused.

You call it on all the values/instructions that are removed and for
those where the result calculated has changed.

> Also, using getPointerBase to get the base pointer seems simple
> enough, but how should I use getMinusSCEV to get the offset.

This should give you the offset from the base pointer:

LoadInst *Load = ...
Value *Pointer = Load->getPointer();
const SCEV *PointerSCEV = SE->getSCEV(Pointer);
const SCEVUnknown *PointerBase =
	dyn_cast<SCEVUnknown>(SE->getPointerBase(PointerSCEV));

if (!PointerBase)
   return 'Analysis failed'

const SCEV *OffsetFromBase = SE->getMinusSCEV(Pointer, PointerBase);

> Should I call it on each load pointer and its base pointer, or
> between the two load pointers once I know that they share the same
> base.
That depends what you want.

> And once I do that, how do I get the offset (if known). I see the
> get[Uns|S]ignedRange functions, but if there is a way to directly get
> a constant value, then that would be more straightforward.

I assume you want to know if two load addresses are either identical, 
have stride one (have a offset of +1) or some other more complicated stuff.

What might work is the following (entirely untested):

LoadInst *LoadOne = ...
LoadInst *LoadTwo = ...

Value *PointerOne = LoadOne->getPointer();
Value *PointerTwo = LoadTwo->getPointer();

const SCEV *PointerOneSCEV = SE->getSCEV(PointerOne);
const SCEV *PointerTwoSCEV = SE->getSCEV(PointerTwo);

// If this is a trivial offset we get something like 1*sizeof(long)
const SCEV *Offset = SE->getMinusSCEV(PointerOneSCEV, PointerTwoSCEV);

// Now we devide it by the element size
Type *AllocTy = LoadOne->getType()->getAllocTy();
const SCEV *TypeOfSCEV = SE->getSizeOfExpr(AllocTy);
const SCEV *OffsetInElements = SE->getUDivExpr(Offset, TypeOfSCEV);

if (const SCEVConstant *IntOffsetSCEV
	= dyn_cast<SCEVConstant>(OffsetInElements)) {
   ConstantInt *IntOffset = IntOffsetSCEV->getValue()
   return IntOffset;
} else {
   return "This seems to be a complicated offset";
}

const SCEV *OffsetInElements = SE->getUDivExpr(Offset, TypeOfSCEV);

Let me know if this or something similar worked.
Tobi











More information about the llvm-commits mailing list