自修改代码vs编译器优化vs重复代码

Self modifying code vs compiler optimizations vs duplicate code

本文关键字:代码 vs 优化 编译器 修改      更新时间:2023-10-16

我变得有点紧张,因为我无法在不妥协的情况下提高C++代码的效率。我开始写一些代码,就像下面的

int foo(int a, int b, int c)
{
    int result;
    bool cond1 = bar1(a, b, c);
    bool cond2 = bar2(a, b, c);
    bool cond3 = bar3(a, b, c);
    for (int i = 0; i < 10000; i++)
    {
        int start = 0;
        int end = 10000;
        if (cond1)
            start = max(start, baz1(i));
        else
            start = max(start, baz2(i));
        if (cond2)
            end = min(end, baz1(i));
        else
            end = min(end, baz2(i));
        for (int j = start; j < end; j++)
        {
            if (cond3)
                result += baz3(i, j);
            else
                result -= baz3(i, j);
        }
    }
    return result;
}   

问题是,如何优化它,使其在每次循环迭代中不检查条件"cond1、cond2、cond3"。我可以把内部循环写成

...
        if (cond3)
        for (int j = start; j < end; j++)
            result += baz3(i, j);
        else
        for (int j = start; j < end; j++)
            result -= baz3(i, j);
...

这将"cond3"的检查次数从10000次减少到只有10000次。然而,仍然有29997个冗余检查,为了优化它,我只看到复制循环2^3=8次的选项。由于#loops与#conditions的指数增长,我有一些问题:

  1. 我可以依靠编译器优化器来展开循环吗
  2. 反对自修改代码的理由是什么,因为在这种情况下,不仅程序大小会减少,而且代码也更易于管理。我很难相信,自从C++发明以来,还没有遇到过这样的问题

函数指针。使用函数指针
使用3个函数指针,每个条件一个。

例如:

  Function_Pointer_Type_Cond1 p_cond_1_function;
  Function_Pointer_Type_Cond2 p_cond_2_function;
  if (bar1(a, b, c))
  {
    p_cond_1_function = baz1;
  }
  else
  {
    p_cond_1_function = baz2;
  }
  if (bar2(a, b, c))
  {
    p_cond_2_function = baz1;
  }
  else
  {
    p_cond_2_function = baz2;
  }
  for (int i = 0; i < 10000; i++)
  {
    int start = 0;
    int end = 10000;
    start = max(start, (*p_cond_1_function)(i));
    end   = min(end,   (*p_cond_2_function)(i));
    // ...
  }

使用函数指针可以删除"if"语句。您可以在循环之前分配函数指针,因为函数在for循环中不会更改。

有关函数指针的更多信息,请在web上搜索"C++常见问题函数指针"或在StackOverflow中搜索"C++函数指针"。

目标压力。

做一些基准测试,但我的预测是,你的代码很好,因为它即使是最简单的分支预测形式也是最优的,这将使所有这些测试几乎免费,而且肯定比函数调用便宜,更不用说间接函数调用了。

如果baz1和baz2是琐碎的,请确保它们可以内联。如果它们不是微不足道的,那么一个几乎总是成功预测的分支就是无关紧要的。

您可以轻松删除第三个if

只要始终在循环内进行加法运算,并在循环后求反结果,然后再返回(如果cond3指示的话)。