【问题标题】:How to help the compiler eliminate loops and arrays?如何帮助编译器消除循环和数组?
【发布时间】:2010-07-14 10:20:09
【问题描述】:

假设您正在编写一个支持多纹理的 3d 渲染器,其中纹理单元的数量通过编译时间常数进行配置。与硬编码单个纹理单元相反,您的代码现在必须通过数组访问纹理相关参数,并通过循环处理它们。

假设一个现代 C++ 编译器,当纹理单元的数量设置为 1 时,为了让编译器生成与硬编码的单个纹理单元等效的代码,您是否需要遵循任何做法?

【问题讨论】:

  • 是的,有。你给我们一些代码,然后我们也可以给你看一些..

标签: c++ arrays loops


【解决方案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
    

    【讨论】:

      猜你喜欢
      • 2017-02-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-06
      • 2015-03-30
      • 2022-07-12
      • 1970-01-01
      相关资源
      最近更新 更多