我看不出gcc对限制指针的代码有什么不同。
文件1
void test (int *a, int *b, int *c)
{
while (*a)
{
*c++ = *a++ + *b++;
}
}
file2的
void test (int *restrict a, int *restrict b, int *restrict c)
{
while (*a)
{
*c++ = *a++ + *b++;
}
}
用
编译 gcc -S -std=c99 -masm=intel file1.c
gcc -S -std=c99 -masm=intel file2.c
file1.s 和 file2.s 两者都相同,但.file
行除外,它告诉文件名:
.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
这两个代码都从内存中读取,然后将a
指向的内存位置分配给b
。如果我预期restrict
版本不会重新读取a
和b
的地址,a
和b
的地址将会增加 - 注册并最后写入内存。
我在做什么事吗?或者是选择示例好吗?
我尝试使用相同结果的不同开关-O0
,-O1
,-O2
,-O3
,-Ofast
和-fstrict-aliasing
对于这两个文件。
注: gcc --version = gcc(GCC)4.6.3 20120306(Red Hat 4.6.3-2)
编辑代码已更改。
答案 0 :(得分:7)
您只是阅读其中一个指针,因此restrict
并不重要。
请参阅this example哪里有意义,因为指针可能会对相同的数据进行别名,并且数据会通过两个指针进行写入和读取。
答案 1 :(得分:3)
事情是以下表达式:
*c++ = *a++ + *b++;
无论如何都需要取消引用每个循环迭代中的所有指针,因为指针在每次迭代中都会发生变化。使用restrict
没有任何好处。
尝试将循环内的行更改为:
*c++ = *a++ + *b;
(您可能还需要启用-O2
等优化。
你会在restrict
的情况下看到它将*b
加载到寄存器中一次,而在没有限制的情况下,它需要在每次循环迭代中加载指针,因为它没有知道c
是否有别名b
。