C 硬件驱动的循环。胡说

C 硬件驱动的循环。胡说,c,performance,loops,embedded,verilog,C,Performance,Loops,Embedded,Verilog,前几天我在Verilog上学会了一个很酷的技巧。当你需要重复做某事时。您可以使用移位寄存器来计算递增的次数。只要将1从LSB移到MSB,当它到达MSB时,就完成了 在C中,它是这样的: for(j=0b1; !(j & (1<<16)); j=j<<1) { /*do a thing 16 times*/ } for(j=0b1;!(j&(1这是非常不值得的。它使代码更简洁、更难阅读,性能差异可以忽略不计 您的编译器可以比您更好地执行这些类型的优化。出于性能原因

前几天我在Verilog上学会了一个很酷的技巧。当你需要重复做某事时。您可以使用移位寄存器来计算递增的次数。只要将1从LSB移到MSB,当它到达MSB时,就完成了

在C中,它是这样的:

for(j=0b1; !(j & (1<<16)); j=j<<1)
{
/*do a thing 16 times*/
}

for(j=0b1;!(j&(1这是非常不值得的。它使代码更简洁、更难阅读,性能差异可以忽略不计

您的编译器可以比您更好地执行这些类型的优化。出于性能原因,类似这样的短循环甚至可能会展开。但是,如果您这样编写循环,编译器可能无法轻松地解决这一问题,因此您甚至可能会减慢程序的速度


这实际上是一个微优化的例子,几乎肯定不会对程序的运行时间产生明显的影响。

在真正的CPU中,加法是最快的事情之一;位移位不会更快。而且你会使编译器更难有效地优化。

更快?你确定吗?至少至少在MIPS体系结构上,一个位的移位所需的时间与一个加法所需的时间一样长。如果大多数面向消费者的处理器体系结构也不是这样,我会感到惊讶


此外,正如Oleksi所指出的,这很难理解。可能不值得一个不存在的速度增益。

一般来说,如果您希望始终循环特定次数>0并最小化循环开销,那么我认为这将是“最好的”:


在这一点上,你必须看一下汇编。

在我看来,大多数评论/回答的人并不真正理解asker在说什么。Verilog语言用于硬件设计,硬件设计与软件设计非常不同,没有CPU周期或类似的东西。然而,简短的回答是ill:没有,回答很长:

当然,移位比加法简单得多。对于移位,从FF(触发器)到FF的逻辑要少得多。对于加法,进位必须从LSB位传播到MSB位,这意味着逻辑的log2(N)级(N是计数器将达到的最高值)。 另一方面,移位寄存器将使用N个FFs,而加法器将只使用log2(N)个FFs。 因此,性能/面积权衡也严重依赖于N。关于加法器的一些“独立”信息: 找不到关于移位的类似文章,但一旦你们理解了加法器,移位器应该是显而易见的

当您在RTL中设计状态机时,这可能很重要。但您提供的代码实际上与上述内容无关。verilog中的“for”循环意味着所有的“工作”都将在一个周期内完成。因此实际上将有N个逻辑。此循环与实现无关。它甚至可能只会混淆verilog compi更容易说出一些奇怪的东西,影响模拟(CPU周期确实很重要,上面的答案是有效的)。有更多工具经验的人可以对此发表评论。

(根据Stefan的回答,我假设你问的是受Verilog版本启发的C版本,而不是在Verilog中这样做。)

在许多体系结构上,这实际上更糟糕,因为位移位需要额外的指令,而循环变量的加法是完全免费的

完全

是的。因为在许多体系结构中,如果计数器和分支不为零,则单个指令会减少计数器和分支的数量,而这些指令所花费的时间与任何其他比较和分支指令所花费的时间一样。然而,如果要进行移位,则需要额外的指令周期。如果您的平台没有“compare equal and branch”指令——并非所有指令都是这样;有些指令让您在两条指令中进行减法并将其与零进行比较

即使在没有减量比较分支指令的RISC平台上,倒计时循环也可能更快,因为您可以简单地减去(一条指令)并在非零指令时使用分支——而在循环中,您需要移位(一条指令)和按位and(一条指令)在分支为零之前,假设你甚至有一个分支为零


此外,对于(i=0;i
循环的简单
,编译器将其转换为“倒计时到0”是很简单的“如果循环速度更快,你几乎不需要自己做那一点聪明的事情。

增量是一种非常特殊的加法情况。在大多数处理器和大多数RISC处理器中,移位和增量在执行时间上是相同的。事实上,在大多数体系结构中,加法也不再需要时间

当你保持循环代码的习惯性时,乐观主义者很可能会简单地展开循环,并在任何情况下更快地渲染它。如果你使循环机制“不寻常”,乐观主义者可能无法对其进行优化

它不涉及任何添加,因此速度很快

对于哪种CPU体系结构,移位速度比加法快?还有,如果结果表明移位速度更快,那么您认为特定体系结构的编译器不会自动从加法到移位进行优化的原因是什么

这有什么用吗

出于优化目的,不,它没有任何用途

出于其他目的,是的,像这样的代码通常用于屏蔽字节中的单个位。我认为最常见的两种方法是:

uint8_t mask; 

for(mask = 0x01; mask != 0x00; mask<<=1)
{
  do_something (data & mask);
}
uint8\t掩码;

对于(mask=0x01;mask!=0x00;mask什么让你认为加法比移位慢?它肯定不在任何现代cpu上,甚至不在嵌入式内核上。位测试也不在。所以是的,胡说八道。有趣的是,我在这里看不到多少cpu周期增益。!如果你设计一个移位不仅比加法快,而且速度差的处理器ce实际上是公开的(即shift实际上比add占用更少的周期,而不是浪费一些时间),然后
uint8_t mask; 

for(mask = 0x01; mask != 0x00; mask<<=1)
{
  do_something (data & mask);
}
for(i=0; i<8; i++)
{
  do_something (data & (1<<i));
}