[LLVMdev] Pointer aliasing
Duncan Sands
baldrick at free.fr
Wed Jan 25 07:45:21 PST 2012
Hi Brent,
> Unless I can mark these extracted pointers as non-aliasing, performance
> suffers a lot. It's not just CSE that suffers -- LLVM does not do
> copy propagation either so we keep loading the same values from memory
> over and over again. See the example here:
>
> double f(double a, double * x, double *y, double * z)
> {
> *x = a;
> *y = a+1;
> *z = *x + 3;
>
> return *x + *y + *z;
> }
here you are obliged to reload the values since some of the pointers might
be equal. For example the store to *y will change the value of *x if x and
y are the same pointer.
Ciao, Duncan.
>
> define double @f(double %a, double* nocapture %x, double* nocapture
> %y, double* nocapture %z) nounwind uwtable {
> store double %a, double* %x, align 8, !tbaa !0
> %1 = fadd double %a, 1.000000e+00
> store double %1, double* %y, align 8, !tbaa !0
> %2 = load double* %x, align 8, !tbaa !0
> %3 = fadd double %2, 3.000000e+00
> store double %3, double* %z, align 8, !tbaa !0
> %4 = load double* %x, align 8, !tbaa !0
> %5 = load double* %y, align 8, !tbaa !0
> %6 = fadd double %4, %5
> %7 = fadd double %6, %3
> ret double %7
> }
>
> !0 = metadata !{metadata !"double", metadata !1}
> !1 = metadata !{metadata !"omnipotent char", metadata !2}
> !2 = metadata !{metadata !"Simple C/C++ TBAA", null}
>
> (I used arguments here without __restrict__ which has the same effect as
> loading my pointers from context as locals). As you can see we keep
> loading the value of x from memory, even though we just stored a local
> into it. Given that I am generating LLVM IR directly (via the C++
> interface) can you suggest someway I could pass the noalias attribute
> onto the locals?
>
> One work around is of course to generate two functions as follows:
>
> double f1( struct ctx* ctx )
> {
> return f2(ctx->a, ctx->x, ctx->y, ctx->z);
> }
>
> double f2( double a, double *__restrict__ x, double *__restrict__ y,
> double *__restrict__ z)
> {
> *x = a;
> *y = a+1;
> *z = *x + 3;
>
> return *x + *y + *z;
> }
>
> but if at all possible I would like to avoid such acrobatics.
>
> Thank you in advance for any help.
> Brent
>
>
> On Wed, Jan 25, 2012 at 4:52 AM, Dan Gohman<gohman at apple.com> wrote:
>> On Jan 24, 2012, at 7:45 AM, Brent Walker wrote:
>>
>>> Can you explain please why it works for this version of the function:
>>>
>>> double f(double *__restrict__ x, double *__restrict__ y, double
>>> *__restrict__ z);
>>>
>>> What is different here? There are stores here as well.
>>
>> LLVM ignores restrict everywhere except function parameters. This is a
>> compromise aimed at a sweet spot in the balance of compiler complexity
>> vs. optimization opportunity.
>>
>> - Many analysis and optimization techniques naturally apply to whole
>> functions. When restrict appears on a local variable inside a
>> function, its special aliasing property applies to only a subset of
>> the function. It's awkward to teach such code to understand and
>> respect local scope boundaries, in general.
>>
>> - Function boundaries are often the boundaries of analysis.
>> Interprocedural analysis can be expensive and complex, so many
>> optimization passes are limited to thinking about one function
>> at a time. And even interprocedural analysis passes are
>> bounded by shared library boundaries. While local variables can
>> often be analyzed automatically (as in your first example),
>> function paramters are often incoming mystery values, so they
>> are where restrict is most often interesting.
>>
>> This compromise does mean that some opportunities are lost (as in
>> your second example), but from clang's perspective these cases are
>> rare.
>>
>> Dan
>>
>
> _______________________________________________
> LLVM Developers mailing list
> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
More information about the llvm-dev
mailing list