C语⾔使⽤数组索引与指针索引在循环中对编译器优化的影响及耗时分析
C语⾔在访问数组时既可以使⽤如a[i]这样的下标⽅式,也可以使⽤*(a+i)这样的指针⽅式,理论上完全等价。但是在编译器对循环作优化时,对于指针⽅式的索引很有可能分析不彻底,因此相⽐数组索引耗时有所增加
数组索引耗时
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
unsigned long get_start_ms(){
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC,&ts);
return(ts.tv_sec *1000+ ts.tv_nsec /1000000);
}
int main(){
unsigned long t =get_start_ms();
uint64_t* mem =malloc(1024*1024*128*sizeof(uint64_t));
register uint64_t sum =0;
for(int i =0; i <1024*1024*128; i++) sum += mem[i];
printf("[%lums]0x%016llx\n",get_start_ms()-t, sum);
}
分别编译、运⾏后结果如下所⽰
可见随着优化等级提升,⽤时依次减少。
指针索引耗时
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
unsigned long get_start_ms(){
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC,&ts);
return(ts.tv_sec *1000+ ts.tv_nsec /1000000);
}
int main(){
unsigned long t =get_start_ms();
uint64_t* mem =malloc(1024*1024*128*sizeof(uint64_t));
uint64_t* end = mem +1024*1024*128;
register uint64_t sum =0;
while(mem<end) sum +=*mem++;
printf("[%lums]0x%016llx\n",get_start_ms()-t, sum);
c语言编译器怎么用?}
分别编译、运⾏后结果如下所⽰
同样,随着优化等级提升,⽤时依次减少。但是我们注意到,在-O1时指针与数组⽤时⼤体相同,但是之后两级都是数组⽐指针快约10ms,不是⼀个⼩数⽬。
编译器优化分析
对于出现这种现象的原因,我们需要从汇编代码作分析。
1. 优化等级-O1
在这⼀级,⼆者区别不明显。
数组索引
指针索引
2. 优化等级-O2
在这⼀级,引⼊了向量化,但是数组索引的向量化程度更⾼,指令条数也更少。
数组索引
指针索引
cmpq $4, %r9
jae LBB1_2
## %bb.1:
## implicit-def: $rbx jmp LBB1_11
LBB1_2:
movq %r9, %r8
andq $-4, %r8
leaq -4(%r8), %rdi
movq %rdi, %rsi
shrq $2, %rsi
incq %rsi
movl %esi, %ebx
andl $3, %ebx
cmpq $12, %rdi
jae LBB1_4
## %bb.3:
pxor %xmm0, %xmm0
xorl %edi, %edi
pxor %xmm1, %xmm1
testq %rbx, %rbx
jne LBB1_7
jne LBB1_7
jmp LBB1_9
LBB1_4:
movl $1, %edi
subq %rsi, %rdi
leaq -1(%rbx,%rdi), %rsi
pxor %xmm0, %xmm0
xorl %edi, %edi
pxor %xmm1, %xmm1
.p2align 4, 0x90
LBB1_5: ## =>This Inner Loop Header: Depth=1
movdqu 8(%rax,%rdi,8), %xmm2
paddq %xmm0, %xmm2
movdqu 24(%rax,%rdi,8), %xmm0
paddq %xmm1, %xmm0
movdqu 40(%rax,%rdi,8), %xmm1
movdqu 56(%rax,%rdi,8), %xmm3
movdqu 72(%rax,%rdi,8), %xmm4
paddq %xmm1, %xmm4
paddq %xmm2, %xmm4
movdqu 88(%rax,%rdi,8), %xmm2
paddq %xmm3, %xmm2
paddq %xmm0, %xmm2
movdqu 104(%rax,%rdi,8), %xmm0
paddq %xmm4, %xmm0
movdqu 120(%rax,%rdi,8), %xmm1
paddq %xmm2, %xmm1
addq $16, %rdi
addq $4, %rsi
jne LBB1_5
## %bb.6:
testq %rbx, %rbx
je LBB1_9
LBB1_7:
leaq 24(%rax,%rdi,8), %rax
negq %rbx
.p2align 4, 0x90
LBB1_8: ## =>This Inner Loop Header: Depth=1
movdqu -16(%rax), %xmm2
paddq %xmm2, %xmm0
movdqu (%rax), %xmm2
paddq %xmm2, %xmm1
addq $32, %rax
incq %rbx
jne LBB1_8
LBB1_9:
paddq %xmm1, %xmm0
pshufd $78, %xmm0, %xmm1 ## xmm1 = xmm0[2,3,0,1]
paddq %xmm0, %xmm1
movq %xmm1, %rbx
cmpq %r8, %r9
je LBB1_12
## %bb.10:
leaq (%rdx,%r8,8), %rdx
.p2align 4, 0x90
LBB1_11: ## =>This Inner Loop Header: Depth=1
addq (%rdx), %rbx
addq $8, %rdx
cmpq %rcx, %rdx
jb LBB1_11
LBB1_12:
3. 优化等级-O2 -march=native
在这⼀级引⼊了avx512,仍然是数组索引的向量化程度更⾼,指令条数更少。
数组索引
指针索引
cmpq $16, %r9
jae LBB1_2
## %bb.1:
## implicit-def: $rbx jmp LBB1_11
LBB1_2:
movq %r9, %r8
andq $-16, %r8
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论