5

所以我正在尝试优化一些代码。我有一个带有可变大小循环的函数。但是,为了提高效率,我想用 1、2 和 3 大小的循环制作完全展开的特殊情况。到目前为止,我的方法是将循环大小声明为 const 参数,然后定义调用 main 函数的包装函数,并将其传递给 const 值的文字。我已经包含了一个代码片段,它说明了我想到的那种事情。

inline void someFunction (const int a)
{
    for (int i=0; i<a; i++)
    {
        // do something with i.
    }
}

void specialCase()
{
    someFunction (3);
}

void generalCase(int a)
{
    someFunction (a);
}

所以我的问题是我期望我的编译器(GCC)在 specialCase 中展开 for 循环是否合理。我的意思是显然我可以复制 - 将 someFunction 的内容粘贴到 specialCase 中并用 3 替换 a 但为了清楚起见,我宁愿只在我的代码中处理 someFunction 的一个定义。

4

3 回答 3

2

但是,为了提高效率,我想用 1、2 和 3 大小的循环制作完全展开的特殊情况。

您是否测量过这实际上更快?我怀疑它会(或者编译器不会自动展开循环)。


到目前为止,我的方法是将循环大小声明为 const 参数,然后定义调用 main 函数的包装函数,并将其传递给 const 值的文字。

const在这里没有任何意义。它不会影响编译器展开循环的能力。这只是意味着它a不能在函数体内发生变异,但它仍然是一个运行时参数。


如果你想确保展开,那么强制它。使用 C++17 很容易。

template <typename F, std::size_t... Is>
void repeat_unrolled_impl(F&& f, std::index_sequence<Is...>)
{
    (f(std::integral_constant<std::size_t, Is>{}), ...);
}

template <std::size_t Iterations, typename F>
void repeat_unrolled(F&& f)
{
    repeat_unrolled_impl(std::forward<F>(f), 
                         std::make_index_sequence<Iterations>{});
}

Godbolt 上的实时示例

于 2017-09-18T10:37:49.140 回答
2

如果您不喜欢模板并且不信任您的编译器,那么总会有这种方法,它的灵感来自被称为“duff's device”的手动展开循环的过时方法:

void do_something(int i);

void do_something_n_times(int n)
{
    int i = 0;
    switch(n)
    {
        default:
            while(n > 3) {
                do_something(i++);
                --n;
            }
        case 3: do_something(i++);
        case 2: do_something(i++);
        case 1: do_something(i++);
    }
}

但我认为值得一提的是,如果你不相信你的编译器会为你做一些简单的事情,比如循环展开,那么可能是时候考虑一​​个新的编译器了。

请注意,Duff 的设备最初是作为一种微优化策略而发明的,用于使用不会自动应用循环展开优化的编译器编译的程序。

它是汤姆·达夫在 1983 年发明的。

https://en.wikipedia.org/wiki/Duff%27s_device

它与现代编译器的使用是值得怀疑的。

于 2017-09-18T11:08:51.130 回答
1

如果您愿意使用所有流行编译器的强制内联(非标准)功能,我宁愿这样做:

__attribute__((always_inline))
void bodyOfLoop(int i) {
  // put code here
}

void specialCase() {
    bodyOfLoop(0);
    bodyOfLoop(1);
    bodyOfLoop(2);
}

void generalCase(int a) {
    for (int i=0; i<a; i++) {
        bodyOfLoop(i);
    }
}

注意:这是 GCC/Clang 解决方案。用于__forceinlineMSVC。

于 2017-09-18T11:05:41.673 回答