如何强制GCC将常量放入内存而不是生成它们?

15 c c++ assembly gcc constants

我在几个函数中定义了很多常量数组.类似于以下内容:

const float values[4] = {-4312.435f,  -432.44333f,  4.798, 7898.89};
Run Code Online (Sandbox Code Playgroud)

在检查gcc汇编器输出后,我注意到这些常量是在每次运行函数时生成的.那是非常低效的.我怀疑这是因为C/C++规范说即使数据是const,编译器也不能假设它不会被修改(例如通过const_cast).是否有可能强制gcc不这么认为?

我想将这些常量定义在函数体内,因为它们非常复杂.将常量保持在他们使用的位置附近有助于可维护性.

编辑

不幸的是,即使定义了常量static,它们也会在每次运行时重新生成.如果有帮助我使用-O3.

EDIT2

好的,抱歉第一次编辑,我需要进一步调查.似乎特定的设置以前以某种方式不允许gcc初始化常量而不重新生成它们.

EDIT3

问题出在我的测试用例中,我在附近定义了两个数组,但其中一个数组是为了生成的.然后汇编程序误导了我.再次抱歉,谢谢!

rli*_*bby 12

static关键字声明它们.

编辑:回复您的评论,以便我可以向您展示一些代码:

这是预期的行为.你在做什么或看到不同的东西?

$ cat foo.c++
int main(void)
{
    static const float foos[] = {1.234f, 5.678f, 9.012f};
    return 0;
}
$ g++ -S foo.c++
$ cat foo.s
    .file   "foo.c++"
    .text
.globl main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    .cfi_personality 0x3,__gxx_personality_v0
    pushq   %rbp
    .cfi_def_cfa_offset 16
    movq    %rsp, %rbp
    .cfi_offset 6, -16
    .cfi_def_cfa_register 6
    movl    $0, %eax
    leave
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .section    .rodata
    .align 4
    .type   _ZZ4mainE4foos, @object
    .size   _ZZ4mainE4foos, 12
_ZZ4mainE4foos:
    .long   1067316150
    .long   1085649453
    .long   1091580199
    .ident  "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
    .section    .note.GNU-stack,"",@progbits
Run Code Online (Sandbox Code Playgroud)


asc*_*ler 11

编译器实际上可以假设定义为const永远不会改变的值.(通过const变量访问的东西是另一个故事;我只讨论定义可见且具有的情况const.)这里得到的问题是标准说如果你递归地调用你的函数,那么地址values将是每次都不一样.

因此,使用语言功能意味着每次调用函数时声明都引用相同的内容.也就是说,一个static函数变量:

static const float values[4] = {-4312.435f, -432.44333f, 4.798, 7898.89};
Run Code Online (Sandbox Code Playgroud)


osg*_*sgx 5

将定义更改为

static const float values[4] = {-4312.435f,  -432.44333f,  4.798, 7898.89};
Run Code Online (Sandbox Code Playgroud)

静态数组不会放在函数堆栈中,因此不会为每个函数调用重新生成它们.

您还可以尝试将此数组从函数移到外部(使其成为具有某些前缀的全局数组function1_values).

编辑:

如果你将这些"flds"或者的计数统计"movss"为再生 - 那就不是.常量将存储在.rodataelf文件的部分中,但要使用它们,编译器必须将它们加载到寄存器中.所以fld&movss只会从内存中加载常量,如果不加载它就不可能从内存中获取值.

示例代码:

int function4(float *a, int sz)
{
    int i;
const float values[4] = {-4312.435f,  -432.44333f,  4.798, 7898.89};
    for(i=4;i<sz;i++);
        a[i]+=a[i-1]*values[0]+a[i-2]*values[1]+a[i-3]*values[2]+a[i-4]*values[3];
    return i;
}
Run Code Online (Sandbox Code Playgroud)

gcc-4.5.2 -O3 ac -fverbose-asm -mfpmath = sse -march = native -S

Assembelr for loop body:

.L2:
    movl    -20(%ebp), %ecx # %sfp, D.2677
    leal    (%edx,%ecx), %ecx       #, D.2677  
    movss   .LC0, %xmm0     #, tmp192     << THIS is a constant loading
    mulss   (%edx,%edi), %xmm0      #* prephitmp.46, tmp192
    movss   .LC1, %xmm1     #, tmp179
    mulss   (%edx,%esi), %xmm1      #* prephitmp.46, tmp179
    addss   %xmm1, %xmm0    # tmp179, tmp192
    movss   .LC2, %xmm1     #, tmp183
    mulss   (%edx,%ebx), %xmm1      #* prephitmp.46, tmp183
    addss   %xmm1, %xmm0    # tmp183, tmp192
    movss   .LC3, %xmm1     #, tmp187
    movl    -16(%ebp), %ebx # %sfp,
Run Code Online (Sandbox Code Playgroud)

常量存储在.rodata:

    .section        .rodata.cst4,"aM",@progbits,4
    .align 4
.LC0:
    .long   -981023877
    .align 4
.LC1:
    .long   -1009239873
    .align 4
.LC2:
    .long   1083803959
    .align 4
.LC3:
    .long   1173804831
Run Code Online (Sandbox Code Playgroud)