请查看以下代码段
#define HF_ND_SZ sizeof(struct huffman_node)
#define TSIZE_MAX 256
struct huffman_node * build_decomp_huffman_tree(uint64_t *table, int size) {
static struct huffman_node huffman_node_list2[TSIZE_MAX * 3];
int i = 0, j = 0;
int k = TSIZE_MAX * 2; // this is the case point 1
//...//
for (i = 0; i < size - 1; i++) {
huffman_node_list2[k + i] = huffman_node_list2[i + 1]; // point 2
huffman_node_list2[TSIZE_MAX + i].right = &huffman_node_list2[k+ i];
// ... //
}
return &huffman_node_list2[size - 1];
}
为简单起见,我减少了代码并指出了我想要突出显示的位置,也不认为算法和结构太深。
我想要的是,如果我们将第1点定义为const int k = TSIZE_MAX * 2;
,那么是否有任何优化发生在第2点或第3点,其中分配发生在连续数据(数组)huffman_node_list2[k + i] = huffman_node_list2[i + 1];
?
(请注意并纠正我的假设,如果它是错误的,我认为当我们在本地或全球范围内声明const
它被创建为不可变的内存分配时,如果我们使用不可变内存并在循环结构中执行数学运算,如第2点或第3点([k + i]
),在运行时程序中必须< strong>加载不可变内存循环的每次迭代并将结果存储在临时内存位置,如果不可变内存有大块,如果发生,希望你能抓住我的想法,我是否正确?)
答案 0 :(得分:1)
使用Visual C,我编译了代码的两个版本:使用const int k
而不使用const
。标志/FA
在(某些)人可读的.asm
文件中生成代码机。没有使用优化标志。
结果是:没有优化,没有区别。生成的机器代码严格相同:
; Listing generated by Microsoft (R) Optimizing Compiler Version 19.00.24231.0
TITLE opt_const.c
.686P
.XMM
include listing.inc
.model flat
INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES
PUBLIC _main
_BSS SEGMENT
?huffman_node_list2@?1??main@@9@9 DB 01fd4H DUP (?) ; `main'::`2'::huffman_node_list2
_BSS ENDS
; Function compile flags: /Odtp
; File c:\joël\tests\opt_const.c
_TEXT SEGMENT
_j$ = -16 ; size = 4
_size$ = -12 ; size = 4
_k$ = -8 ; size = 4
_i$ = -4 ; size = 4
_argc$ = 8 ; size = 4
_argv$ = 12 ; size = 4
_main PROC
; 10 : {
push ebp
mov ebp, esp
sub esp, 16 ; 00000010H
push esi
push edi
; 11 : static struct huffman_node huffman_node_list2[TSIZE_MAX * 3];
; 12 : int i = 0, j = 0, size = 17;
mov DWORD PTR _i$[ebp], 0
mov DWORD PTR _j$[ebp], 0
mov DWORD PTR _size$[ebp], 17 ; 00000011H
; 13 : int k = TSIZE_MAX * 2; // this is the case point 1
mov DWORD PTR _k$[ebp], 194 ; 000000c2H
; 14 : //...//
; 15 : for (i = 0; i < size - 1; i++) {
mov DWORD PTR _i$[ebp], 0
jmp SHORT $LN4@main
$LN2@main:
mov eax, DWORD PTR _i$[ebp]
add eax, 1
mov DWORD PTR _i$[ebp], eax
$LN4@main:
mov ecx, DWORD PTR _size$[ebp]
sub ecx, 1
cmp DWORD PTR _i$[ebp], ecx
jge SHORT $LN3@main
; 16 : huffman_node_list2[k + i] = huffman_node_list2[i + 1]; // point 2
mov edx, DWORD PTR _i$[ebp]
add edx, 1
imul esi, edx, 28
add esi, OFFSET ?huffman_node_list2@?1??main@@9@9
mov eax, DWORD PTR _k$[ebp]
add eax, DWORD PTR _i$[ebp]
imul edi, eax, 28
add edi, OFFSET ?huffman_node_list2@?1??main@@9@9
mov ecx, 7
rep movsd
; 17 : huffman_node_list2[TSIZE_MAX + i].right = &huffman_node_list2[k+ i];
mov ecx, DWORD PTR _k$[ebp]
add ecx, DWORD PTR _i$[ebp]
imul edx, ecx, 28
add edx, OFFSET ?huffman_node_list2@?1??main@@9@9
mov eax, DWORD PTR _i$[ebp]
add eax, 97 ; 00000061H
imul ecx, eax, 28
mov DWORD PTR ?huffman_node_list2@?1??main@@9@9[ecx], edx
; 18 : // ... //
; 19 : }
jmp SHORT $LN2@main
$LN3@main:
; 20 : return 0;
xor eax, eax
; 21 : }
pop edi
pop esi
mov esp, ebp
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END
编辑:我使用gcc,-O3优化标志进行了相同的测试。
并且......相同的结果:生成的汇编代码在有const
关键字的情况下再次严格相同。
.file "opt_const.c"
.section .text.unlikely,"ax",@progbits
.LCOLDB0:
.section .text.startup,"ax",@progbits
.LHOTB0:
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB23:
.cfi_startproc
movl $huffman_node_list2.2488+16384, %eax
.p2align 4,,10
.p2align 3
.L2:
movq -16352(%rax), %rdx
movq %rax, -8192(%rax)
addq $32, %rax
movq %rdx, -32(%rax)
movq -16376(%rax), %rdx
movq %rdx, -24(%rax)
movq -16368(%rax), %rdx
movq %rdx, -16(%rax)
movq -16360(%rax), %rdx
movq %rdx, -8(%rax)
cmpq $huffman_node_list2.2488+17088, %rax
jne .L2
xorl %eax, %eax
ret
.cfi_endproc
.LFE23:
.size main, .-main
.section .text.unlikely
.LCOLDE0:
.section .text.startup
.LHOTE0:
.local huffman_node_list2.2488
.comm huffman_node_list2.2488,24576,32
.ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609"
.section .note.GNU-stack,"",@progbits
答案 1 :(得分:1)
const
如果编译器将它放在只读的.text段中足够远,导致高速缓存未命中,则会慢一些。
这可能发生在全局const
或者编译器将其从函数中提升而不是必须使用指令构建它(结构或数组的相当常见的优化)这可以减少代码大小,如果多个函数使用相同的常量,但也会增加与代码的距离,从而增加导致错过的可能性。
由于您没有使用任何聚合类型,因此与优秀的编译器应该没有区别。
有一篇很好的文章介绍了如何布置不同的数据here
答案 2 :(得分:0)
const
根本不会创建内存位置,除非您获取其地址。它们可以作为立即模式常量消失在指令流中,或者在编译或链接时添加到地址中。
例如,huffman_node_list2[k + i] = huffman_node_list2[i + 1]
几乎肯定被编译为huffman_node_list2[TSIZE_MAX * 2 + i] = huffman_node_list2[i + 1]
,其中不仅在编译时评估TSIZE_MAX * 2
,而且在链接时评估huffman_node_list2+TSIZE_MAX*2
。