MSIL有ROL和ROR指令吗?

5

我写了一个Int128类型,它很好用。我认为可以通过一个简单的想法来提高其性能:改进有点笨拙的移位操作。

因为移位操作在乘法和除法中被广泛使用,所以一次改进会产生连锁反应。因此,我开始创建一个动态方法(用于低位移位和高位旋转),只发现没有OpCodes.Rol或OpCodes.Ror指令。

在IL中是否可能实现这一点?


即使没有CIL操作码可以用于位旋转,JIT编译器仍然可能聪明到将几个CIL操作码映射到底层机器指令集上的ROL和ROR指令。 (我实际上并不认为JIT编译器是 那么 聪明,但至少这是可能的)。我的意思是说:我不会太担心。与真正的汇编语言相比,CIL代码似乎非常低效,但JIT编译器很可能会在某种程度上缓解这种情况。 - stakx - no longer contributing
2个回答

5

不需要。

您需要使用位移运算符实现它。

UInt64 highBits = 0;
UInt64 lowBits = 1;
Int32 n = 63;
var altShift = (n - 63);

var lowShiftedOff = (n - 63) > 0 ? 0 : (lowBits << n);
var highShiftedOff = (n - 63) > 0 ? 0 : (highBits << n);

var highResult = (UInt64)(highShiftedOff | (altShift > 0 ? (lowBits << altShift - 1) : 0));
var lowResult= (UInt64)(lowShiftedOff | (altShift > 0 ? (highBits << altShift - 1) : 0));

1
谢谢。你确认了我所担心的事情。我在 .NET 4.0 的 BigInteger 中进行了挖掘,看看他们是如何做到的,现在我对自己的做法感觉不那么糟糕了。 - Tergiver
1
不仅是错误的,而且我忽略了SHL和SHR只查看移位操作数的最后5位(对于U/Int32)或6位(对于U/Int64),从而为完整的移位值创建模数。当尝试通过移位位时,这是一个很大的痛苦,我无法理解为什么会实现成这样。 - codekaizen
移位操作数仅适用于小于所涉及类型大小的移位,因为对于n位类型而言,移动超过n位并没有太多意义。 标准(ECMA 335:§3.59)指出:“如果'shiftAmount'大于或等于'value'的宽度,则返回值未指定。” - porges
@Porges - 当你试图像这样进行筛选时,这是有意义的。 - codekaizen

4
为了在7年后部分回答这个问题,以防有人需要。
你可以在.Net中使用ROR/ROL。
MSIL并不直接包含ROR或ROL操作,但是有一些模式会让JIT编译器生成ROR和ROL。RuyJIT(.Net和.Net core)支持此功能。
改进.Net Core以使用此模式的细节在这里讨论,一个月后,.Net Core代码更新了使用它
查看SHA512的实现,我们可以找到ROR的示例:
    public static UInt64 RotateRight(UInt64 x, int n) {
        return (((x) >> (n)) | ((x) << (64-(n))));
    }

并按相同模式扩展到ROL:

    public static UInt64 RotateLeft(UInt64 x, int n) {
        return (((x) << (n)) | ((x) >> (64-(n))));
    }

要在128位整数上执行此操作,可以将其处理为两个64位,然后使用AND提取“进位”,使用AND清除目标并使用OR应用。这必须在两个方向(低->高和高->低)中进行镜像。由于这个问题有点旧,我不会费心给出示例。

有没有想过如何将这段代码转换为通用的 ROL/ROR,适用于常见类型(byte、short、int、long 和它们的无符号版本)? (例如 public T RotateLeft<T>(T val, int n) { var bits = Marshal.SizeOf(val) * 8; n %= bits; return ((val << (n) | (val >> (bits - n))); /* ?? */ } - Ecnelis
1
我认为你最好重载它们,因为它们并不多。值类型的通用类型约束仅限于“结构体”。而且使用Marshal.SizeOf()(Windows API调用,如果我没记错的话)而不是sizeof()(编译时常量)将抵消任何潜在ROL/ROR的性能优势。因此,即使您编译了正确的代码,也不会有任何好处。 - Tedd Hansen
1
谢谢您的回复。您的见解非常有价值。 - Ecnelis
1
我最终写了一篇关于sizeof()和Marshal.SizeOf()之间区别的快速博客文章:https://blog.tedd.no/2018/03/18/sizeof-vs-marshal-sizeof/ :) - Tedd Hansen
我已经将它加入书签,如果我遇到任何问题,发现提到这个适用的话,我会把它们指向那个页面。 :) - Ecnelis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接