如何使GCC更好地优化传递和返回结构?

时间:2016-07-07 01:36:50

标签: c gcc optimization struct pass-by-value

我正在编写一个3d矢量数学库,用于具有约束内存的嵌入式系统。大多数C数学库使用“输出参数”习惯,我非常不喜欢。在听到像Chandler Carruth这样的人谈论编译器如何非常善于优化传递和价值回报之后,我变得忠实于它是使用3个浮点数结构的可行选择。 (在我的用例中,所有函数都在头文件中内联,因此保留调用约定无关紧要。)

但是,在编写我的库并将其用于预期的应用程序之后,我发现堆栈的使用率非常高。通过切换回旧的“输出参数”样式,甚至更糟糕的是就地修改,我可以节省许多字节的堆栈空间。

此示例代码演示了此问题:

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

typedef struct vec {
    float x; float y; float z;
} vec;

inline float vdot(vec a, vec b) {
    return a.x * b.x + a.y * b.y + a.z * b.z;
}

inline float vdotp(vec const *a, vec const *b) {
    return a->x * b->x + a->y * b->y + a->z * b->z;
}

inline vec vscale(float s, vec a) {
    vec v = { .x = s * a.x, .y = s * a.y, .z = s * a.z };
    return v;
}

inline void vscalep(float s, vec *a) {
    a->x = s * a->x;
    a->y = s * a->y;
    a->z = s * a->z;
}

inline vec vnormalize(vec a) {
    float s = 1.0f / sqrtf(vdot(a, a));
    return vscale(s, a);
}

inline void vnormalizep(vec *a) {
    float s = 1.0f / sqrtf(vdotp(a, a));
    vscalep(s, a);
}

inline vec vproject(vec a, vec b) {
    vec bnorm = vnormalize(b);
    float s = vdot(a, bnorm);
    return vscale(s, bnorm);
}

inline void vprojectp(vec *a, vec const *b) {
    vec bnorm = *b;
    vnormalizep(&bnorm);
    float s = vdotp(a, &bnorm);
    vscalep(s, &bnorm);
    *a = bnorm;
}

int main() {
    vec a = { .x = rand(), .y = rand(), .z = rand() };  
    vec b = { .x = rand(), .y = rand(), .z = rand() };  
#ifdef PTRS
    vprojectp(&a, &b);
#else
    a = vproject(a, b);
#endif
    printf("a: %f, %f, %f\n", a.x, a.y, a.z);
}

我希望,在同一个文件中标记为inline的所有函数的情况下,编译器将能够将我的按值传递代码“解构”为其核心标量数学运算,并大致生成两个版本的堆栈大小相同。但是,它不能:

> gcc -O3 -fconserve-stack -Wstack-usage=30 main.c -lm

main.c: In function ‘main’:
main.c:52:6: warning: stack usage is 64 bytes [-Wstack-usage=]

而使用就地版本:

> gcc -O3 -fconserve-stack -Wstack-usage=30 -DPTRS main.c -lm

main.c: In function ‘main’:
main.c:52:6: warning: stack usage is 48 bytes [-Wstack-usage=]

在我的实际应用中,我在更大范围内看到了同样的问题。通过值传递在堆栈空间中耗费了数百个字节。

在这种情况下,有没有办法获得更好的堆栈使用优化?我已经在使用fconserve-stack了。我愿意花费任何额外的优化时间来获得更好的结果。

(我在ARM上使用GCC 4.9,但在x86-64上也出现了同样的问题。我的示例代码中的堆栈大小是x86-64。)

0 个答案:

没有答案