c++cloopsoptimizationcompiler-optimization

How to create a restrict pointer out of a non-restrict pointer


Here is a motivating example

void foo(int *A, int *B, int *N) {
  for (int k = 0; k < *N; k++)
    A[k] += B[k];
}

Compiler can't vectorize this loop because it assumes that A and N alias. Adding a restrict to N enables vectorization. e.g., https://godbolt.org/z/joMrhEM8K

void foo(int *A, int *B, int *__restrict N) {
    for (int k = 0; k < *N; k++)
        A[k] += B[k];
}

generates

.LBB0_9:
        ldp     q0, q3, [x11, #-16]
        subs    x12, x12, #8
        ldp     q1, q2, [x10, #-16]
        add     x10, x10, #32
        add     v0.4s, v0.4s, v1.4s
        add     v1.4s, v3.4s, v2.4s
        stp     q0, q1, [x11, #-16]
        add     x11, x11, #32
        b.ne    .LBB0_9

Which is good. But I want to create a restricted pointer out of N and not modify the function declaration. e.g., something like

void foo(int *A, int *B, int *N) {
    int *__restrict p = N;
    for (int k = 0; k < *p; k++)
        A[k] += B[k];
}

But this doesn't work. Any way to achieve this?

The reason I'd like to achieve this is because then I can 'version' the code without adding __restrict in the declaration. like:

// Returns true if X, Y don't alias.
bool no_alias(int* X, int *Y);

void foo(int *A, int *B, int *N) {
    if (no_alias(A,N)) { // assuming I have a way to figure out that A and N don't alias at runtime.
      int *__restrict p = N;
      for (int k = 0; k < *p; k++)
        A[k] += B[k];
    } else {
      for (int k = 0; k < *p; k++)
          A[k] += B[k];
    }
}

Solution

  • Another option is to just get rid of the possibility by assigning the value to an intermediary.

    void foo(int *A, int *B, int *N) {
        if (no_alias(A, N)) {
            const int n = *N;
            for (int k = 0; k < n; k++)
                A[k] += B[k];
        }
        else {
            for (int k = 0; k < *N; k++)
                A[k] += B[k];
        }
    }