优化编译器的不断组合

时间:2011-02-15 22:22:47

标签: c++ c gcc constants inline

我有一个包含许多小内联函数的头文件。他们中的大多数碰巧有不断的数据。由于这些函数对性能至关重要,因此它们处理常量的方式变得非常重要。 AFAIK有两种方法可以引用常量:

1)将它们定义在稍后与应用程序链接的单独源文件中。

2)就地定义常数。

我会选择后一种方式,因为它更易于维护。但是,如果编译器没有优化内联创建的数千个相等常量,那么它可能会更慢。

问题:

编译器会结合这些相等的常量吗?特别是,将使用以下哪种方法?

1)在编译单元中组合相等的常量 2)在链接模块(整个程序或库)中组合相等的常量
3)将常量与任何静态常量数据相结合,这些数据碰巧具有相同的位模式,并满足编译单元或整个程序的对齐要求。

我使用现代编译器(GCC4.5)。

我不是汇编程序方面的专家,因此我无法使用几个简单的测试来回答这个问题:)

修改

常量非常大(大多数至少为16个字节),因此编译器无法使它们成为立即值。

EDIT2:

代码示例

这个就地使用常数:

float_4 sign(float_4 a)
{
    const __attribute__((aligned(16))) float mask[4] = { //I use a macro for this line
        0x80000000, 0x80000000, 0x80000000, 0x80000000};
    const int128 mask = load(mask);
    return b_and(a, mask);
}

3 个答案:

答案 0 :(得分:8)

根据GCC,以下选项可以满足您的需求:

  

-fmerge常数

  尝试跨编译单元合并相同的常量(字符串常量和浮点常量)。   如果汇编器和链接器支持,则此选项是优化编译的缺省选项。使用-fno-merge-constants可以抑制此行为   在-O,-O2,-O3,-Os等级启用。

答案 1 :(得分:2)

如果您在头文件中定义常量,如下所示:

int const TEN = 10;
// or
enum { ELEVEN = 11 };

也就是说,编译转换单元(.cc源文件)时,编译器不仅可以看到常量声明,而且定义也是可见的,那么编译器当然会用生成的代码中的常量值替换它,即使是没有启用优化。

[max@truth test]$ cat test.cc
int const TEN = 10; // definition available
extern int const TWELVE; // only declaration

int foo(int x) { return x + TEN; }
int bar(int x) { return x + TWELVE; }

[max@truth test]$ g++ -S -o - test.cc | c++filt | egrep -v " *\."
foo(int):
    pushq   %rbp
    movq    %rsp, %rbp
    movl    %edi, -4(%rbp)
    movl    -4(%rbp), %eax
    addl    $10, %eax
    leave
    ret
bar(int):
    pushq   %rbp
    movq    %rsp, %rbp
    movl    %edi, -4(%rbp)
    movl    TWELVE(%rip), %eax
    addl    -4(%rbp), %eax
    leave
    ret
TEN:

注意foo(int)如何将addl $10, %eax加法,即TEN常数替换为其值。另一方面,在bar(int)中,它首先movl TWELVE(%rip), %eax将TWELVE的值从内存加载到eax寄存器(地址将由链接器解析)然后执行加法{{1} }。

优化版本如下所示:

addl -4(%rbp), %eax

答案 2 :(得分:0)

我认为你的问题没有一般性答案。我只给一个C,C ++的规则是不同的。

这很大程度上取决于常量的类型。一个重要的类是“整数常量表达式”。这些可以在编译时确定,特别是用作“整数枚举常量”的值。无论何时使用

enum { myFavoriteDimension = 55/2 };

对于这样的常数,通常应该发生最好的事情:它们被实现为汇编程序。它们甚至没有存储位置,直接写入汇编程序,你的问题甚至没有意义。

对于其他数据类型,问题更加微妙。尽量强制不要使用“const限定变量”的地址。这可以使用register关键字完成。

register double const something = 5.7;

可能与上述效果相同。

对于撰写类型(structunion,数组),没有一般的答案或方法。我已经看到gcc能够完全优化小数组(大约10个元素)。