gpt4 book ai didi

c++ - n 是负数、正数还是零?返回 1、2 或 4

转载 作者:IT老高 更新时间:2023-10-28 12:34:22 29 4
gpt4 key购买 nike

我正在构建一个 PowerPC 解释器,它运行良好。在 Power 架构中,条件寄存器 CR0(x86 上的 EFLAGS)几乎在任何指令上都会更新。它是这样设置的。 CR0的值为1,如果最后一个结果为负,如果最后一个结果为正,则为2,否则为4。

我的第一个天真的解释方法是:

if (n < 0)
cr0 = 1
else if (n > 0)
cr0 = 2;
else
cr0 = 4;

但是我知道所有这些分支都不会是最佳的,每秒运行数百万次。我已经看到一些关于 SO 的黑客攻击,但似乎没有一个是过激的。例如,我发现很多例子可以根据符号或 0 将数字转换为 -1、0 或 1。但是如何使 -1 = 1、1 = 2、0 = 4?我正在寻求 Bit Hackers 的帮助...

提前致谢

更新:首先:谢谢大家,你们太棒了。我会仔细测试你所有的代码的速度,你会第一个知道谁是赢家。

@jalf:关于你的第一个建议,我实际上并没有在每条指令上计算 CR0。我宁愿保留一个 lastResult 变量,当(如果)以下指令要求一个标志时,进行比较。三个主要动机让我回到了“每次”更新:

  1. 在 PPC 上,您不必像在 x86 上那样强制更新 CR0(其中 ADD 总是更改 EFLAGS,即使不需要),您有两种类型的 ADD,一种是更新。如果编译器选择使用更新的,这意味着它会在某个时候使用 CR0,所以延迟没有意义......
  2. 有一个特别痛苦的指令叫做 mtcrf,它可以让你任意更改 CR0。您甚至可以将其设置为 7,没有算术意义...这只会破坏保留“lastResult”变量的可能性。

最佳答案

首先,如果要在(几乎)每条指令之后更新此变量,显而易见的建议是:

不要

只有在后续指令需要它的值时才更新它。在其他任何时候,都没有必要更新它。

但是无论如何,当我们更新它时,我们想要的是这种行为:

R < 0  => CR0 == 0b001 
R > 0 => CR0 == 0b010
R == 0 => CR0 == 0b100

理想情况下,我们根本不需要分支。这是一种可能的方法:

  1. 将 CR0 设置为值 1。 (如果您真的想要速度,请调查是否可以在不从内存中获取常量的情况下完成此操作。即使您必须在上面花费一些指令,这也可能是值得的)
  2. 如果 R >= 0,则左移一位。
  3. 如果 R == 0,则左移一位

第 2 步和第 3 步可以转换以消除“如果”部分

CR0 <<= (R >= 0);
CR0 <<= (R == 0);

这样更快吗?我不知道。与往常一样,当您关心性能时,您需要衡量、衡量、衡量。

但是,我可以看到这种方法的几个优点:

  1. 我们完全避免使用分支
  2. 我们避免了内存加载/存储。
  3. 我们依赖的指令(位移和比较)应该具有低延迟,例如,乘法并非总是如此。

缺点是我们在所有三行之间都有一个依赖链:每一行都修改 CR0,然后在下一行中使用它。这在一定程度上限制了指令级并行性。

为了最小化这个依赖链,我们可以这样做:

CR0 <<= ((R >= 0) + (R == 0));

所以我们只需要在初始化之后修改 CR0 一次。

或者,在一行中完成所有操作:

CR0 = 1 << ((R >= 0) + (R == 0));

当然,这个主题有很多可能的变体,所以请继续尝试。

关于c++ - n 是负数、正数还是零?返回 1、2 或 4,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9558550/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com