簡體   English   中英

如何阻止 clang 通過模板過度擴展嵌套循環?

[英]How to stop clang from overexpanding nested loops via templates?

考慮這段代碼

#include <iostream>
typedef long xint;
template<int N>
struct foz {
    template<int i=0>
    static void foo(xint t) {
        for (int j=0; j<10; ++j) {
            foo<i+1> (t+j);
        }
    }
    template<>
    static void foo<N>(xint t) {
        std::cout << t;
    }
    
};

int main() {
    foz<8>::foo<0>(0);
}

clang++ -O0中編譯時,它會在幾秒鍾內編譯,然后運行 4 秒。

但是用clang++ -O2 ,編譯時間長,memory很多。 在godbolt上可以看到,把8改小一點,就充分展開了循環。

我不是讓它完全沒有優化,而是讓它不遞歸,就像嵌套循環應該表現的那樣。 有什么我應該做的嗎?

可以禁用循環展開優化,請參閱godbolt 生成的代碼是非遞歸的,並以嵌套循環的形式表示。

#pragma nounroll
for (int j=0; j<10; ++j) {
    foo<i+1> (t+j);
}

您也可以手動調整展開而不是禁用它,按 8 展開會生成與循環 8 次的代碼類似的代碼。 神螺栓

#pragma unroll 8
for (int j=0; j<10; ++j) {
    foo<i+1> (t+j);
}

要使其成為非遞歸的,您可以使用數組作為索引:

static bool increase(std::array<int, N>& a)
{
    for (auto rit = std::rbegin(a); rit != std::rend(a); ++rit) {
        if (++*rit == 10) {
            *rit = 0;
        } else {
            return true;
        }
    }
    return false;
}

static void foo(xint t) {
    std::array<int, N> indexes{};

    do {
        std::cout << std::accumulate(std::begin(indexes), std::end(indexes), 0);
    } while (increase(indexes));
}

演示

最簡單的解決方案是使用noinline function 屬性標記有問題的 function ,其他幾個 C++ 編譯器(例如GNU g++ )也支持該屬性:

    template<int i=0>
    static void foo(xint t)  __attribute__((__noinline__)) {

這指示編譯器的優化器從不內聯調用該 function。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM