Pointer aliasing issue

Hi,
I have a question regarding pointer aliasing.
I have following C code:

void factorial(float **a, float **b)
{
b[2][2] = a[0][2];
b[2][2] = a[0][1];
}

Which is converted to following LLVM IR:

define void @factorial(float** nocapture %a, float** nocapture %b) nounwind {
entry:
%0 = getelementptr inbounds float** %b, i64 2 ; <float**> [#uses=2]
%1 = load float** %0, align 8 ; <float*> [#uses=1]
%2 = load float** %a, align 8 ; <float*> [#uses=1]
%3 = getelementptr inbounds float* %2, i64 2 ; <float*> [#uses=1]
%4 = load float* %3, align 4 ; [#uses=1]
%5 = getelementptr inbounds float* %1, i64 2 ; <float*> [#uses=1]
store float %4, float* %5, align 4
%6 = load float** %0, align 8 ; <float*> [#uses=1]
%7 = load float** %a, align 8 ; <float*> [#uses=1]
%8 = getelementptr inbounds float* %7, i64 1 ; <float*> [#uses=1]
%9 = load float* %8, align 4 ; [#uses=1]
%10 = getelementptr inbounds float* %6, i64 2 ; <float*> [#uses=1]
store float %9, float* %10, align 4
ret void
}

Assuming that a and b arrays contains pointers that are not aliased,
is it possible to remove the first store by using some C or LLVM IR specific declarations?

Thanks.

Hi Artiom,

I have following C code:

    void factorial(float **a, float **b)
    {
       b[2][2] = a[0][2];
       b[2][2] = a[0][1];
    }

...

Assuming that a and b arrays contains pointers that are not aliased,
is it possible to remove the first store by using some C or LLVM IR specific
declarations?

try this:

void factorial(float ** __restrict a, float ** __restrict b)
{
   b[2][2] = a[0][2];
   b[2][2] = a[0][1];
}

Ciao,

Duncan.

PS: Did you mean to use b[2][2] in both lines?

Unfortunately since in this example function arguments are array of pointers, __restrict doesn’t help.
Yes, using 2 stores into same location is intentional.

Hi Artiom,

Unfortunately since in this example function arguments are array of pointers,
__restrict doesn't help.

it does help, though perhaps not in the way you had in mind. The IR changes
from (llvm-gcc at -O4)

define void @factorial(float** nocapture %a, float** nocapture %b) nounwind {
entry:
   %0 = getelementptr inbounds float** %b, i64 2
   %1 = load float** %0, align 8
   %2 = load float** %a, align 8
   %3 = getelementptr inbounds float* %2, i64 2
   %4 = load float* %3, align 4
   %5 = getelementptr inbounds float* %1, i64 2
   store float %4, float* %5, align 4
   %6 = load float** %0, align 8
   %7 = load float** %a, align 8
   %8 = getelementptr inbounds float* %7, i64 1
   %9 = load float* %8, align 4
   %10 = getelementptr inbounds float* %6, i64 2
   store float %9, float* %10, align 4
   ret void
}

to

define void @factorial(float** noalias nocapture %a, float** noalias nocapture %b) nounwind {
entry:
   %0 = getelementptr inbounds float** %b, i64 2
   %1 = load float** %0, align 8
   %2 = load float** %a, align 8
   %3 = getelementptr inbounds float* %2, i64 2
   %4 = load float* %3, align 4
   %5 = getelementptr inbounds float* %1, i64 2
   store float %4, float* %5, align 4
   %6 = getelementptr inbounds float* %2, i64 1
   %7 = load float* %6, align 4
   store float %7, float* %5, align 4
   ret void
}

Ciao,

Duncan.