是否有可以从c#访问的shift和copy cpu指令?

时间:2011-09-21 14:19:12

标签: c# assembly

我需要在64位cpu上取8位数字并将其向右移动8次。每次我移动数字我需要在它后面移动相同的8位数,这样我最终会重复8次相同的8位数。这最终会转移,添加8,转移添加8 ...等等,结果是40多个周期(如果我错了,请纠正我)。

有没有办法在1个循环中执行此操作(移位和复制),以便最终得到相同的值?

long _value = 0;
byte _number = 7;
for (int i = 0; i < 8; i++) {
    _value = (_value << 8) + _number;
}
编辑:我正在尝试比较一组字符来检测关键字。我不能使用string.contains,因为字符串值可能跨越缓冲区的边界。此外,该应用程序必须在嵌入式ARM cpu以及桌面和服务器CPU上运行。内存使用和CPU周期非常重要。

3 个答案:

答案 0 :(得分:6)

如今,执行指令的数量与执行它们所需的 cpu周期数之间没有直接联系。 您似乎也假设C#中的语句对应于单个程序集/ cpu指令,这也是错误的。

您的代码似乎正确执行了算法描述所说的内容(请注意,long已签名,使用 ulong 表示无符号行为)。

如果要使用专门的 cpu扩展(如mmx,sse等)可以在一条指令中执行add-shift-assignment,则需要使用汇编代码。但我不确定是否存在这样的具体指令。这可能取决于您拥有的CPU类型。

您不能将汇编代码与c#一起直接使用,但您可以将汇编与 c 一起使用(作为链接对象文件使用,使其成为内联汇编)。编译后的c代码可以在c#/ .net中使用 interop

但对你而言,第一个也是最重要的问题应该是:你想要完成什么?

我怀疑性能对您的应用程序至关重要,即使您应该诚实地问自己c#是否是达到目标的最佳语言。

答案 1 :(得分:4)

另一个想法是预先计算所有字节值的查找表。

var lu = new long[256];
// init
var n = 7;
var v = lu[n];

<强>更新

一些基准测试结果(以每100000000次迭代的毫秒数为单位):

  • 循环:272
  • 展开:207
  • 不安全:351
  • 查询:250
  • HenkH:216

展开的版本是:

long _value = 0;
byte _number = 7;

_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;

不安全的版本是:

long _value = 0;
byte _number = 7;

byte* p = (byte*)&_value;

*p++ = _number;
*p++ = _number;
*p++ = _number;
*p++ = _number;
*p++ = _number;
*p++ = _number;
*p++ = _number;
*p++ = _number;

遗憾地没有表演:(

查找只是对数组的读取。

全部为x64 / release编译。

答案 2 :(得分:3)

如果你希望它快,你至少可以展开你的循环:

ulong _value = 0;
byte _number = 7;

_value = _number;
_value = (_value <<  8) + _value;
_value = (_value << 16) + _value;
_value = (_value << 32) + _value;

这也会减少分支。