编译后的汇编代码中有哪些方法/技术可以用来减少分支数量?

3
我试图在一个特定的架构中尽量减少编译后汇编代码中分支指令的数量,因为处理器流水线的实现方式导致分支指令非常昂贵。
我可以尝试使用自修改代码来减少条件分支中测试条件的次数,但还有其他方法可以考虑吗?

听起来像是一道作业题。你为什么不去找一下原始的ARM芯片是如何处理这个问题的呢? - Alex Brown
1
这是一个很大的主题,也是一个不太具体的问题。 - harold
如果你在计算一个表达式,你可以尝试通过使用一些位运算技巧(如AND、OR、XOR、-、*、算术右移等)来重写计算它的代码,从而减少或消除条件分支。你正在做什么? - Alexey Frunze
我没有看到它说这是一个 ARM,如果它是一个 ARM,那么根据代码避免分支有简单的解决方案。 - old_timer
@Froskoy 我仍然不同意 - 有许多不同的技术可以避免分支,适用哪些取决于你试图减少分支数量的具体代码片段。 - harold
显示剩余2条评论
1个回答

3

在编译代码中,你不应该过于关注分支指令的数量,而应该关注程序运行时分支指令被执行的次数。

有两种简单的方法可以减少执行分支指令的次数:

  1. 如果你的架构支持谓词指令,那么可以使用谓词指令生成小的if块来替代分支。你可以要求编译器为你完成此操作。例如,如果你使用的是GCC编译器,则使用-O1,-O2,-O3或-Os编译选项,或使用-fif-conversion2标志即可实现。
    请记住:大的if块无法进行转换,因为谓词指令会通过CPU流水线传递,而不管条件是否为真。这会浪费时间。

  2. 展开循环。循环意味着分支。如果你展开循环,就可以减少执行分支的次数(尽管在编译代码中,你仍然会“看到”相同数量的分支指令,对吧?)。
    但请记住:这会增加代码大小,可能导致指令缓存的缺失率增加。

例如:

for (i = 0; i < N; i++)
  {
     LOOP_BODY;
  }

如果已知N是偶数,则手动展开两次的方法非常简单:

for (i = 0; i < N; i++)
  {
     LOOP_BODY;
     i++;
     LOOP_BODY;
  }

执行此代码时,执行的分支数几乎减半。
同样的,你的编译器可能也可以自动执行此操作。例如,GCC会使用"-funroll-loops"展开一些循环。
编译器还有其他一些技巧可供使用。例如,如果使用的是GCC,则应该在此页面中搜索“branch”

谢谢!这真的很有帮助。感谢您还提供了GCC提示,因为这是我编译过程中的第一阶段。 - Froskoy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接