¿Por qué no hay ningún efecto de restringir el puntero?
-
12-12-2019 - |
Pregunta
No veo ninguna diferencia en el código de gcc para los punteros de restricción.
archivo1
void test (int *a, int *b, int *c)
{
while (*a)
{
*c++ = *a++ + *b++;
}
}
archivo2
void test (int *restrict a, int *restrict b, int *restrict c)
{
while (*a)
{
*c++ = *a++ + *b++;
}
}
compilar con
gcc -S -std=c99 -masm=intel file1.c
gcc -S -std=c99 -masm=intel file2.c
archivo1.s y archivo2.s ambos son iguales, excepto el .file
línea, que indica el nombre del archivo:
.file "file1.c"
.text
.globl test
.type test, @function
test:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq %rdi, -8(%rbp)
movq %rsi, -16(%rbp)
movq %rdx, -24(%rbp)
jmp .L2
.L3:
movq -8(%rbp), %rax
movl (%rax), %edx
movq -16(%rbp), %rax
movl (%rax), %eax
addl %eax, %edx
movq -24(%rbp), %rax
movl %edx, (%rax)
addq $4, -24(%rbp)
addq $4, -8(%rbp)
addq $4, -16(%rbp)
.L2:
movq -8(%rbp), %rax
movl (%rax), %eax
testl %eax, %eax
jne .L3
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size test, .-test
.ident "GCC: (GNU) 4.6.3 20120306 (Red Hat 4.6.3-2)"
.section .note.GNU-stack,"",@progbits
Ambos códigos se leen de la memoria y luego asignan la ubicación de la memoria señalada por a
a b
.donde esperaba el restrict
La versión no volverá a leer las direcciones de a
y b
, y las direcciones de a
y b
se incrementará en el registro y al final se escribirá en la memoria.
¿Hay algo malo que estoy haciendo?¿O está bien la selección del ejemplo?
Lo he probado con diferentes interruptores. -O0
, -O1
, -O2
, -O3
, -Ofast
, y -fstrict-aliasing
con los mismos resultados idénticos para ambos archivos.
Nota: gcc --version = gcc (GCC) 4.6.3 20120306 (Red Hat 4.6.3-2)
EDITAR Código cambiado.
Solución
El caso es que la siguiente expresión:
*c++ = *a++ + *b++;
De todos modos, prácticamente necesita eliminar la referencia a todos los punteros en cada iteración del bucle, ya que los punteros cambian en cada iteración.No hay ningún beneficio al usar restrict
.
Intente cambiar la línea dentro del bucle a:
*c++ = *a++ + *b;
(Es posible que también deba habilitar optimizaciones como -O2
).
Verás eso en el restrict
caso se carga *b
en un registro una vez, mientras que en el caso sin restricciones necesita cargarse a través del puntero en cada iteración del bucle porque no sabe si o no c
alguna vez alias b
.
Otros consejos
Sólo estás leyendo uno de los consejos, por lo que restrict
no importa.
Ver este ejemplo donde sí importa porque los punteros pueden alias los mismos datos, y los datos se escriben y leen a través de ambos punteros.