[LLVMdev] Pointer aliasing

Brent Walker brenthwalker at gmail.com
Tue Jan 24 20:58:59 PST 2012


Thank you for your reply.  The compromise you describe below, is it a
compromise in the LLVM back end or in clang?  I run into this while
building a compiler for a small DSL language for which I generate
functions that receive a context from which they extract a bunch of
pointers to doubles from which inputs are passed to the function (I
just used C/clang in my examples to illustrate the problem).

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;
}

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
>




More information about the llvm-dev mailing list