Aqui está um exemplo motivador
void foo(int *A, int *B, int *N) {
for (int k = 0; k < *N; k++)
A[k] += B[k];
}
O compilador não pode vetorizar esse loop porque ele assume que A e N são alias. Adicionar a a restrict
N habilita a vetorização. por exemplo, 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];
}
gera
.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
O que é bom. Mas eu quero criar um restrict
ponteiro ed de N e não modificar a declaração da função. por exemplo, algo como
void foo(int *A, int *B, int *N) {
int *__restrict p = N;
for (int k = 0; k < *p; k++)
A[k] += B[k];
}
Mas isso não funciona. Existe alguma maneira de conseguir isso?
O motivo pelo qual eu gostaria de conseguir isso é porque então eu posso 'versionar' o código sem adicionar __restrict na declaração. Como:
// 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];
}
}
Outra opção é simplesmente se livrar dessa possibilidade atribuindo o valor a um intermediário.
Você deve usar os builtins
__builtin_assume
E talvez adicionar a opção de compilação
-fstrict-aliasing
( gcc, strict-aliasing e histórias de terror )Chame uma versão da função com o
restrict
qualificador.