如何在C中写入循环,以便编译器在减量后可以使用零上的分支
已知处理器具有特殊指令,用于在计数器为零且延迟非常低的情况下递减计数器和分支,因为分支指令不需要等待计数器递减通过整数单位 以下是ppc说明的链接: 我通常的做法是触发编译器生成适当的指令,如下所示:如何在C中写入循环,以便编译器在减量后可以使用零上的分支,c,loops,compiler-optimization,instruction-set,C,Loops,Compiler Optimization,Instruction Set,已知处理器具有特殊指令,用于在计数器为零且延迟非常低的情况下递减计数器和分支,因为分支指令不需要等待计数器递减通过整数单位 以下是ppc说明的链接: 我通常的做法是触发编译器生成适当的指令,如下所示: unsigned int ctr = n; while(ctr--) a[ctr] += b[ctr]; 可读性高,是一个在零上分支的递减循环。正如您所看到的,如果计数器在减量之前为零,则会发生分支。我希望编译器能发挥一些魔力,让它无论如何都能工作。问:编译器是否必须打破C语言的任何基本规则
unsigned int ctr = n;
while(ctr--)
a[ctr] += b[ctr];
可读性高,是一个在零上分支的递减循环。正如您所看到的,如果计数器在减量之前为零,则会发生分支。我希望编译器能发挥一些魔力,让它无论如何都能工作。问:编译器是否必须打破C语言的任何基本规则,才能将其转换为特殊的减量和分支条件指令(如果有的话)
另一种方法:
unsigned int ctr = n+1;
while(--ctr) {
a[ctr-1] += b[ctr-1];
}
分支现在发生在减量之后,但是有常数在生成丑陋的代码。我想,索引变量比计数器小1会使它看起来更漂亮一些。查看可用的ppc指令,查找a和b地址时的额外计算仍然适合单个指令,因为load也可能执行地址算术加法。对其他指令集不太确定。我的主要问题是,如果n+1大于一个最大值。Q:减量会像往常一样把它拉回到最大值并循环吗
问:在C语言中是否有一种更常用的模式来允许通用指令
编辑:ARM具有递减和分支操作,但仅当值不为零时才分支。似乎有一个额外的条件,就像ppc bc一样。在我看来,这是从C的角度来看的,这是非常相同的事情,所以我希望代码片段也可以编译成这种形式,而不会违反任何C标准
编辑:英特尔与ARM几乎有相同的分支指令:这是怎么回事:
do
{
a[ctr] += b[ctr];
}
while(--ctr);
但是,您需要额外检查:
if(n != 0)
{
/*...*/
}
如果你不能通过其他方式保证这一点
哦,请注意,ctr有不同的最终值,这取决于您在我的循环变量中选择了0,在您的第一个循环变量中选择了~0…这将取决于编译器的优化编写人员的努力 例如,可以在循环的底部使用bdz操作码跳过返回顶部的不同跳转。这将是一个坏主意,但它可能会发生
loop:
blah
blah
bdz ... out
b loop
out:
如果不是零,则更可能是递减和分支,PPC也支持这一点
loop:
blah
blah
bdnz ... loop
fallthru:
除非您有令人信服的理由尝试使用操作码,否则我建议您尝试编写干净、可读的代码,以尽量减少副作用。您自己从后减量到预减量的更改就是一个很好的例子——编译器可以少担心一个未使用的副作用
那样的话,你会得到最大的爆炸为您的优化雄鹿。如果有一个平台需要一个特殊版本的代码,您可以定义整个过程,包括内联汇编,或者在读取汇编输出和运行探查器的同时重写代码。当然取决于编译器,但这是一条对性能非常好的指令,因此,我希望编译器尝试最大限度地利用它 由于您正在链接一个AIX引用,所以我假设您正在运行xlc。我没有访问AIX机器的权限,但我可以访问Z机器上的xlc。 等效的Z对应项是支路计数BCTR指令 我尝试了5个例子并检查了列表
int len = strlen(argv[1]);
//Loop header
argv[1][counter] += argv[2][counter];
使用以下循环头:
for (int i = 0; i < len; i++)
for (int i = len-1; i >= 0; i--)
while(--len)
while(len--)
while(len){
len--;
所有5个示例都在-O1和更高的计数上使用分支,并且没有一个在opt 0上使用分支
我相信现代编译器能够在任何标准循环结构的零机会上找到分支。可读性高吗?可读性非常高,Swift3中已删除了前/后增量/减量。我会尝试memcpy或memmove。我个人对增量前/后没有问题。memcpy/memmove不是一个选项:他不是在复制,而是在添加值+=而不是=。所有示例是否生成相同的程序集?因为那真的很酷。顺便说一句,len必须注意从零开始。不,代码略有不同,但总体上非常相似。完全相同的代码将是令人印象深刻的lol。这些代码如何管理n=0?你的回答提供了更多的想法。在条件分支总是在循环开始之前,我就有了这个想法。现在我不太确定。。。根据是否存在分支预测器公共循环大小以及一次获取的指令数,在循环之前有条件地查找零以及have条件分支检查是否应该再次运行可能更有用。呃,我开始后悔当初问这个问题。在一天中,当DEC/BNZ是新的和酷的,数据总线是16位宽,max,有很多编译器生成的循环基本上是从JU开始的。 mp到底部,则循环的底部有一个减量分支,而不是从零到顶部的操作码。这是在缓存未命中成为代码生成的主要因素之前。基本上,do while循环是自然形式,while和for循环是do while循环,在顶部跳转到底部-