Есть ли в MSIL инструкции ROL и ROR?

Я написал тип Int128, и он отлично работает. Я думал, что смогу улучшить его производительность с помощью простой идеи: улучшить операции переключения, которые немного неуклюжи.

Поскольку они активно используются при умножении и делении, их усовершенствование будет иметь волновой эффект. Поэтому я начал создавать динамический метод (для смещения вниз и поворота вверх), только чтобы обнаружить, что нет инструкций OpCodes.Rol или OpCodes.Ror.

Возможно ли это в ИЛ?


person Tergiver    schedule 10.07.2010    source источник
comment
Даже если выяснится, что нет кода операции CIL для чередования битов, JIT-компилятор все еще может быть достаточно умным, чтобы сопоставить несколько кодов операций CIL с инструкциями ROL и ROR в наборе инструкций базовой машины. (На самом деле я не думаю, что JIT-компилятор настолько умен, но, по крайней мере, это возможно). Я хочу сказать: я бы не стал слишком волноваться. По сравнению с реальным языком ассемблера код CIL в любом случае кажется очень неэффективным, но JIT-компилятор, скорее всего, несколько облегчит ситуацию.   -  person stakx - no longer contributing    schedule 14.07.2010


Ответы (2)


No.

Вам нужно реализовать это с битовыми сдвигами

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));
person codekaizen    schedule 10.07.2010
comment
Спасибо. Вы подтвердили то, чего я опасался. Я копался в BigInteger .NET 4.0, чтобы посмотреть, как они это сделали, и теперь я не так уж плохо себя чувствую. - person Tergiver; 11.07.2010
comment
Это не только плохо, но я игнорировал тот факт, что SHL и SHR смотрят только на последние 5 (для U/Int32) или 6 (для U/Int64) бит операнда сдвига, эффективно создавая модуль для полного значения сдвига. Это большая боль при попытке сдвинуть биты, и я не могу понять, почему это было реализовано именно так. - person codekaizen; 11.07.2010
comment
Операнды сдвига определены только для сдвигов, меньших размера используемого типа, поскольку сдвиг более чем на n битов для n-битного типа не имеет особого смысла. Стандарт (ECMA 335: §3.59) говорит: The return value is unspecified if 'shiftAmount' is greater than or equal to the width of 'value'. - person porges; 18.07.2010
comment
@Porges - это имеет смысл, когда вы пытаетесь переключиться таким образом. - person codekaizen; 19.07.2010

Частично ответить на этот вопрос спустя 7 лет, вдруг кому понадобится.

Вы можете использовать ROR/ROL в .Net.

MSIL не содержит непосредственно операций ROR или ROL, но есть шаблоны, которые заставят JIT-компилятор генерировать ROR и ROL. RuyJIT (ядро .Net и .Net) поддерживает это.

Детали улучшения .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-битных, затем И для извлечения «переноса», И для очистки назначения и ИЛИ для применения. Это должно быть отражено в обоих направлениях (низкий-> высокий и высокий-> низкий). Я не буду возиться с примером, так как этот вопрос немного устарел.

person Tedd Hansen    schedule 21.12.2017
comment
Любая идея, как вы могли бы преобразовать это в общий 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))); /* ?? */ }) - person Ecnelis; 14.03.2018
comment
Я думаю, вам лучше их перегрузить, их не так много. Ограничение универсального типа для типа значения ограничивается структурой. И использование Marshal.SizeOf() (вызов Windows API iirc) вместо sizeof() (постоянная времени компиляции) сведет на нет любые преимущества производительности от потенциального ROL/ROR. Таким образом, даже если у вас есть дженерик для компиляции правильного кода, пользы не будет. - person Tedd Hansen; 19.03.2018
comment
Спасибо за ответ. Ваше понимание было ценным. - person Ecnelis; 20.03.2018
comment
В итоге я написал короткую запись в блоге о разнице между sizeof() и Marshal.SizeOf(): blog.tedd.no/2018/03/18/sizeof-vs-marshal-sizeof :) - person Tedd Hansen; 20.03.2018
comment
Я добавил это в закладки, если у меня когда-нибудь возникнут вопросы, где я считаю упоминание об этом применимым, я укажу их на эту страницу. :) - person Ecnelis; 21.03.2018