如何帮助编译器消除循环和数组?
Posted
技术标签:
【中文标题】如何帮助编译器消除循环和数组?【英文标题】:How to help the compiler eliminate loops and arrays? 【发布时间】:2010-07-14 10:20:09 【问题描述】:假设您正在编写一个支持多纹理的 3d 渲染器,其中纹理单元的数量通过编译时间常数进行配置。与硬编码单个纹理单元相反,您的代码现在必须通过数组访问纹理相关参数,并通过循环处理它们。
假设一个现代 C++ 编译器,当纹理单元的数量设置为 1 时,为了让编译器生成与硬编码的单个纹理单元等效的代码,您是否需要遵循任何做法?
【问题讨论】:
是的,有。你给我们一些代码,然后我们也可以给你看一些.. 【参考方案1】:循环和数组有什么问题?
展开循环确实有一个缺点:它会使代码变得更大。更大的代码意味着更多的内存访问来获取代码,并且由于内存访问速度很慢,您的代码最终可能会变慢。此外,英特尔 cpu 对获取的代码进行预处理,并将它们转换为 uOps(微操作),然后调度和执行。 CPU 拥有这些 uOps 的缓存,因此它只解码尚未在缓存中的指令。因此,展开的循环将填满缓存并导致其他代码被撞出。较小的代码通常更好。
至于数组,我不知道你会如何摆脱它们。
所以,如果你有:
struct TextureUnit
// some texture unit data
TextureUnit units [number_of_units];
for (int i = 0 ; i < number_of_units ; ++i)
callfunction (units [i].someparams);
这样做可能会更好:
for (TextureUnit *i = unit ; i < &unit [number_of_units] ; ++i)
callfunction (i->someparams);
但您需要查看编译器在优化构建中生成了什么,以确保它确实提供了任何优势。
我认为这可能被归类为“微优化”,所以我不会真的担心它,除非你能证明它确实是一个瓶颈。记住 - 分析代码,不要只是猜测。
【讨论】:
【参考方案2】:我对计算机图形学了解不多,但这个简单的测试表明,对于 TEXTURE_COUNT=1 和 -O1,g++ 没有分支。我怀疑这甚至会延伸到许多现实生活中的程序,但你为什么不自己尝试一下。使用-S
查看生成的程序集。
#include <stdio.h>
typedef struct fake_texture
int r, g, b;
texture;
int main()
texture array[TEXTURE_COUNT] = ;
for(int i = 0; i < TEXTURE_COUNT; i++)
array[i].r += 1;
array[i].g += 2;
array[i].b += 3;
for(int i = 0; i < TEXTURE_COUNT; i++)
printf("%d\n", array[i].r);
x86 汇编摘录:
main:
.LFB31:
.cfi_startproc
.cfi_personality 0x0,__gxx_personality_v0
pushl %ebp
.cfi_def_cfa_offset 8
movl %esp, %ebp
.cfi_offset 5, -8
.cfi_def_cfa_register 5
andl $-16, %esp
subl $32, %esp
movl $1, 20(%esp)
movl $2, 24(%esp)
movl $3, 28(%esp)
movl $1, 8(%esp)
movl $.LC0, 4(%esp)
movl $1, (%esp)
call __printf_chk
movl $0, %eax
leave
ret
.cfi_endproc
【讨论】:
以上是关于如何帮助编译器消除循环和数组?的主要内容,如果未能解决你的问题,请参考以下文章