Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在C中写入循环,以便编译器在减量后可以使用零上的分支_C_Loops_Compiler Optimization_Instruction Set - Fatal编程技术网

如何在C中写入循环,以便编译器在减量后可以使用零上的分支

如何在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语言的任何基本规则

已知处理器具有特殊指令,用于在计数器为零且延迟非常低的情况下递减计数器和分支,因为分支指令不需要等待计数器递减通过整数单位

以下是ppc说明的链接:

我通常的做法是触发编译器生成适当的指令,如下所示:

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循环,在顶部跳转到底部-