gcc 为什么编译器不优化RAM查找?

g0czyy6m  于 2023-02-23  发布在  其他
关注(0)|答案(1)|浏览(139)

https://godbolt.org/z/dK9v7En5v
对于以下C++代码

#include <stdint.h>
#include <cstdlib>

void Send(uint32_t);

void SendBuffer(uint32_t* __restrict__ buff, size_t n)
{
    for (size_t i = 0; i < n; ++i)
    {
        Send(buff[0]);
        Send(buff[1]);  
        for (size_t j = 0; j < i; ++j) {
            Send(buff[j]);   
        }
    }
}

我们有以下汇编程序清单

SendBuffer(unsigned int*, unsigned long):
        test    rsi, rsi
        je      .L15
        push    r13
        mov     r13, rsi
        push    r12
        mov     r12, rdi
        push    rbp
        xor     ebp, ebp
        push    rbx
        sub     rsp, 8
.L5:
        mov     edi, DWORD PTR [r12]
        call    Send(unsigned int)
        mov     edi, DWORD PTR [r12+4]
        call    Send(unsigned int)
        test    rbp, rbp
        je      .L3
        xor     ebx, ebx
.L4:
        mov     edi, DWORD PTR [r12+rbx*4]
        add     rbx, 1
        call    Send(unsigned int)
        cmp     rbx, rbp
        jne     .L4
.L3:
        add     rbp, 1
        cmp     r13, rbp
        jne     .L5
        add     rsp, 8
        pop     rbx
        pop     rbp
        pop     r12
        pop     r13
        ret
.L15:
        ret

在每次循环迭代时,从存储器中读取,而值可以在寄存器中存储一次。
不管我们有没有内部循环,编译器不会优化它的构造,我添加循环是为了证明编译器不能依赖处理器缓存
编译器根据C++标准在循环之前从寄存器加载内存一次是否有效(如果我们有或没有__restrict__关键字)?如果有效,为什么编译器不做优化?如果现在没有,我怎么能告诉编译器没有人会改变内存,它是有效的?

c6ubokkw

c6ubokkw1#

您可以通过重新排列代码来帮助编译器,以便可以看到RAM优化的影响。

void SendBuffer(uint32_t* __restrict__ buff, size_t n)
{
    // Access RAM sequentially to take advantage of the data cache.
    const uint32_t a = buff[0];
    const uint32_t b = buff[1];

    for (uint32_t i = 0u; i < n; ++i)
    {
        Send(a);
        Send(b);

        // Start at the third buffer slot.
        for (size_t j = 2; j < n; ++j)
        {
            Send(buff[j]);   
        }
    }
}

在上面的代码中,瓶颈是对Send的调用。访问buff数组要快得多。而且,循环中的分支求值比访问数组花费更多的时间。
这里真正的优化应该是修改Send,使其传输块而不是字。大多数设备通信都有块传输功能。
否则,您可以尝试展开循环。(* 编译器可能会在更高的优化级别上展开循环 *)

size_t j;
for (j = 2u; (j + 4u) < n; j += 4)
{
     // Optimization:  load consecutively from data cache to reduce
     // the quantity of cache reloads.  
     const uint32_t a = buff[j + 0u];
     const uint32_t b = buff[j + 1u];
     const uint32_t c = buff[j + 2u];
     const uint32_t d = buff[j + 3u];

     // Send a "block" of data:
     Send(a);
     Send(b);
     Send(c);
     Send(d);
}
// Send the remaining words:
for (; j < n; ++j)
{
    Send(buff[j]);   
}

检查汇编语言应该显示更好的组织和优化的代码。

**编辑1:**包括外部循环,更正索引变量用法。

相关问题