Вверх ↑
Этот топик читают: Гость
Ответов: 9906
Рейтинг: 351
#16: 2017-01-27 14:01:27 ЛС | профиль | цитата
Netspirit писал(а):

Зачем?

Смысл есть.
Ликвидировать функциональные вызовы как shr64, так и ror64.
Сделать для Sigma0, Sigma1, Gamma0 и Gamma1 только asm-реализации
По смыслу-то - это очень быстрые функции.
Дополнительные функциональные вызовы в них - совершенно не логичны.

Редактировалось 2 раз(а), последний 2017-02-02 20:17:28
карма: 9

0
Ответов: 4612
Рейтинг: 746
#17: 2017-01-27 14:43:03 ЛС | профиль | цитата
Не, ну это дополнительная задача, которую я лично не решу. Я имел в виду, что для решения обсуждаемой проблемы лезть в те функции необязательно.
карма: 26

0
Ответов: 2
Рейтинг: 0
#18: 2017-01-27 17:08:29 ЛС | профиль | цитата
извините, что пишу в чужую тему, подскажите как подключить другие компиляторы кроме встроенного FPC и какой лучше под веб подходит

Редактировалось 2 раз(а), последний 2017-01-27 17:10:01
карма: 0

0
Ответов: 9906
Рейтинг: 351
#19: 2017-01-28 19:46:50 ЛС | профиль | цитата
Netspirit писал(а):

Не, ну это дополнительная задача, которую я лично не решу.

Предубеждение, мне кажется.
Ничего военного, на самом деле:
function Sigma0(x: Int64): Int64; assembler;
asm
push ebx
mov eax,[ebp+08h]
mov edx,[ebp+0Ch]
shrd [ebp+08h],edx,28
shrd [ebp+0Ch],eax,28
mov ecx,eax
mov ebx,edx
shld eax,ebx,30
shld edx,ecx,30
mov ecx,eax
mov ebx,edx
shrd ebx,eax,5
shrd ecx,edx,5
xor eax,ecx
xor edx,ebx
xor eax,[ebp+08h]
xor edx,[ebp+0Ch]
pop ebx
// Result := (ror64(x, 28) xor ror64(x, 34) xor ror64(x, 39));
end;

function Sigma1(x: Int64): Int64; assembler;
asm
push ebx
mov eax,[ebp+08h]
mov edx,[ebp+0Ch]
shrd [ebp+08h],edx,14
shrd [ebp+0Ch],eax,14
mov ecx,eax
mov ebx,edx
shrd eax,ebx,18
shrd edx,ecx,18
mov ecx,eax
mov ebx,edx
shrd ebx,eax,23
shrd ecx,edx,23
xor eax,ecx
xor edx,ebx
xor eax,[ebp+08h]
xor edx,[ebp+0Ch]
pop ebx
// Result := (ror64(x, 14) xor ror64(x, 18) xor ror64(x, 41));
end;

function Gamma0(x: Int64): Int64; assembler;
asm
push ebx
mov eax,[ebp+08h]
mov edx,[ebp+0Ch]
shrd [ebp+08h],edx,1
shrd [ebp+0Ch],eax,1
mov ecx,eax
mov ebx,edx
shrd ebx,eax,8
shrd ecx,edx,8
shrd eax,edx,7
shr edx,7
xor eax,ecx
xor edx,ebx
xor eax,[ebp+08h]
xor edx,[ebp+0Ch]
pop ebx
// Result := (ror64(x, 1) xor ror64(x, 8) xor (x shr 7));
end;

function Gamma1(x: Int64): Int64; assembler;
asm
push ebx
mov eax,[ebp+08h]
mov edx,[ebp+0Ch]
shrd [ebp+08h],edx,19
shrd [ebp+0Ch],eax,19
mov ecx,eax
mov ebx,edx
shld ebx,eax,3
shld ecx,edx,3
shrd eax,edx,6
shr edx,6
xor eax,ecx
xor edx,ebx
xor eax,[ebp+08h]
xor edx,[ebp+0Ch]
pop ebx
// Result := (ror64(x, 19) xor ror64(x, 61) xor (x shr 6));
end;

--- Добавлено в 2017-01-28 19:49:56

Не моя тема...
Проверял только на примере от ТС

Редактировалось 3 раз(а), последний 2017-02-02 20:21:21
карма: 9

0
Разработчик
Ответов: 26061
Рейтинг: 2120
#20: 2017-01-29 04:07:00 ЛС | профиль | цитата
Galkov писал(а):
Ничего военного, на самом деле

Подождем окончательного тестирования и будем добавлять.
карма: 22

0
Ответов: 4612
Рейтинг: 746
#21: 2017-01-30 12:56:02 ЛС | профиль | цитата
Galkov писал(а):
Предубеждение, мне кажется
Не, я действительно такое не осилю.

Редактировалось 1 раз(а), последний 2017-01-30 12:56:32
карма: 26

0
Ответов: 9906
Рейтинг: 351
#22: 2017-02-02 10:24:00 ЛС | профиль | цитата
Netspirit писал(а):

В чем прикол - я так и не понял

Здорово смахивает на то, что он "реагирует" на то, что второй операнд константа, а не переменная.
В кодах ror64 тоже ведь есть shr ...
Вот так ведь - тоже "правильно" работает:
function Gamma0(x: Int64): Int64;
var b:byte;
begin
b := 7;
Result := (ror64(x, 1) xor ror64(x, 8) xor (x shr b));
end;

И еще одно интересное наблюдение ...
В кодах System.pas (которые я стащил когда-то из какой-то семерки)
Есть две процедуры для правых 64-битных сдвигов:
// ------------------------------------------------------------------------------
// 64-bit signed shift right
// ------------------------------------------------------------------------------
// target (EAX:EDX) count (ECX)

procedure __llshr;
asm
cmp cl, 32
jl @__llshr@below32
cmp cl, 64
jl @__llshr@below64
sar edx, 1fh
mov eax,edx
ret

@__llshr@below64:
mov eax, edx
cdq
sar eax,cl
ret

@__llshr@below32:
shrd eax, edx, cl
sar edx, cl
ret
end;

// ------------------------------------------------------------------------------
// 64-bit unsigned shift right
// ------------------------------------------------------------------------------

// target (EAX:EDX) count (ECX)
procedure __llushr;
asm
cmp cl, 32
jl @__llushr@below32
cmp cl, 64
jl @__llushr@below64
xor edx, edx
xor eax, eax
ret

@__llushr@below64:
mov eax, edx
xor edx, edx
shr eax, cl
ret

@__llushr@below32:
shrd eax, edx, cl
shr edx, cl
ret
end;
НО, в интерфейсной части определена лишь одна - вторая
Которую, компилятор, собственно, и использует. Когда второй операнд переменная.
А первую, получается - не сможет, даже если захочет.
Хотите верьте, хотите - нет ...

Редактировалось 5 раз(а), последний 2017-02-02 20:17:57
карма: 9

0
Ответов: 4612
Рейтинг: 746
#23: 2017-02-02 12:10:37 ЛС | профиль | цитата
Galkov писал(а):
он "реагирует" на то, что второй операнд константа, а не переменная
Да, я уже потом об этом подумал. Вроде таких заморочек с обычным Integer не наблюдается? Зачем тогда ему понадобилось два варианта сдвига?

Вообще, судя по тому, что я только сейчас узнал о существовании сдвига с сохранением последнего разряда, тому, что эта возможность нигде не светилась в документации и тому, что в новой версии Delphi её не существует - это было какое-то недоразумение в старых версиях Delphi...
карма: 26

0
Ответов: 9906
Рейтинг: 351
#24: 2017-02-02 14:55:12 ЛС | профиль | цитата
Netspirit писал(а):

... я только сейчас узнал о существовании сдвига с сохранением последнего разряда

Ну я-то знаю про это "с детства". Процесс познания происходил у меня "снизу вверх", а не как сейчас принято.
Практически все процессоры обладают стандартным набором битовых манипуляций: циклические вращения вправо/влево (плюс такие же вместе с битом переноса CF), один левый сдвиг, и два правых - т.н. логический и арифметический.
Собственно, и все. НО, всегда и везде.

Пытался найти семантическое описание правого сдвига хотя бы в C/C++. Фиг-вам, как говорится...
У Страуструпа - ничего не нашел.
Про C примерно так:
Брайан Керниган, Деннис Ритчи писал(а):

Сдвиг вправо беззнаковой величины всегда сопровождается заполнением освобождающихся разрядов нулями. Сдвиг вправо знаковой величины на одних машинах происходит с распространением знака ("арифметический сдвиг"), на других — с заполнением освобождающихся разрядов нулями ("логический сдвиг").

Т.е., стандартом языка это не определено. Даже такого стандартизированного языка.
Чего уж там про Дельфи говорить.


Netspirit писал(а):

это было какое-то недоразумение в старых версиях Delphi

Да, скорее всего.
Потом просто убрали строку из интерфейса, а "смарт-линкинг" не включает неиспользуемые коды.
А артефакты оптимизационной самогенерации - остались в 4-ке. В 7-ке - и их прикончили.
Странно, правда, что не появляется warning, типа такого: XXX declared, but never used

Это, если не обращать внимание на слово "недоразумение".
ЯВУ таки является посредником между программистом и процессором. Как говорится, если у проца есть возможности - соблаговолите предоставить их программисту. Действительно, смотреть, как программисты на ЯВУ пытаются изобразить циклический сдвиг, так волосы шевелиться начинают:
function ror64(x: Int64; y: Byte): Int64;
begin
Result := (x shr y) or (x shl (64 - y));
end;
Это при "нестандартизированности" правого сдвига. И без проверок y на превышение 64 (команды проца реагируют только на младшие 5 бит второго операнда)
Ну типа, когда в языке нет нужных слов, то РАКЕТУ начинают определять как "летающую огнедышащую колесницу"

Редактировалось 6 раз(а), последний 2017-02-03 15:23:14
карма: 9

0
Ответов: 9906
Рейтинг: 351
#25: 2017-02-02 20:07:06 ЛС | профиль | цитата
Заглянул как бы в официальный документ:
ISO/IEC 9899:201x писал(а):

The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 / 2^E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined.

Как после этого пользоваться правым сдвигом для знаковых чисел -- не понятно

--- Добавлено в 2017-02-02 20:32:45

Стандарт на C++ как бы платный... Говорят.
А вот в черновом варианте Working Draft, Standard for Programming Language C ++ (Document Number: N4527) про правый сдвиг написано все ровно то же самое. Буква в букву.

Редактировалось 6 раз(а), последний 2017-02-02 21:42:28
карма: 9

0
Ответов: 4612
Рейтинг: 746
#26: 2017-02-03 12:03:53 ЛС | профиль | цитата
Ну, все уже давно привыкли во всех языках, что "сдвиг - это сдвиг": освобожденное место заполняется 0-ми без вариантов. Собственно, сдвиг и используется как битовая операция, а не математическая, эквивалентная делению знакового числа на 2.
Это уже компиляторы, если захотят, могут реализовать целочисленное деление на 2 как правый арифметический сдвиг.

Редактировалось 2 раз(а), последний 2017-02-03 12:05:03
карма: 26

0
Ответов: 9906
Рейтинг: 351
#27: 2017-02-03 14:20:58 ЛС | профиль | цитата
Про ВСЕ - у меня отношение очень скептическое.
Если все привыкнут к тому, что Солнце вращается вокруг Земли - это не отменяет обратного факта.
И если "все привыкли" - это не отменяет выше-высказанного соображения: "если у проца есть возможности - соблаговолите предоставить их программисту"

Хорошо, случай из жизни ...
Работаю, например, с камнем Cortex-M3 (конкретно - STM32F105). Это означает, что машина 32-битная, и сопроцессора нет.
Задача - цифровая фильтрация звуковых сигналов.
Эффективность - важна, мягко говоря (частота проца - всего-то 72 МГц).

Какое решение мы выбрали (точнее, я лично настоял).
Сделали свой формат "с фиксированной точкой". Типа: старшие 16 бит - целая часть, а младшие 16 - дробная.
Примерно так сделали:
class __fix16 { //??? to ENITOOLs
int X;
public:
__fix16(int y){X = y;}
__fix16 operator+(__fix16 y){X += y.X;return *this;}
__fix16 operator*(__fix16 y){X = (X*__int64(y.X))>>16;return *this;}
__fix16 operator=(__fix16 y){X = y.X;return *this;}
operator int(){return X>>16;}
};
#define FIX16(y) __fix16(y*(1<<16))
Эффективности Keil-а хватило для inline-реализации умножения и без библиотечных функций для float/long-арифметики.
Все чисто и эффективно. Даже руками лучше не сделаешь, пожалуй (конечно же, я просматривал результаты в дизасме)...
Разве что, пришлось макрос FIX16 состряпать (просто float-конструктор - компилятор оптимизировать не хотел, почему-то).
Чтобы работали, например, такие конструкции:
  __fix16 F,G;
....
F = FIX16(0.95)*F + FIX16(0.05)*G; // БИХ-фильтр первого порядка
Работали, как уже говорил, без библиотечных функций для float/long-арифметики. Просто, в нужном месте используются 32-битные константы (рассчитанные на этапе компиляции).

А теперь, Netspirit, обратите внимание на правый сдвиг в операторе умножения.
Он там нужен именно знаковый. И он такой и есть, в данном конкретном (implementation-defined) исполнении.
Несмотря на то, что "все привыкли".

У меня не было таких привычек, и мне это даже казалось совершенно естественным (стандарты тогда я не просматривал)

Редактировалось 15 раз(а), последний 2017-02-03 15:36:12
карма: 9

0
Ответов: 4612
Рейтинг: 746
#28: 2017-02-03 14:56:11 ЛС | профиль | цитата
Ну, так привыкли от того, что ни в одной документации не описывают различий в поведении shr со знаковыми и беззнаковыми типами. А в Delphi (и возможно в других языках) этого различия и вообще нет. А мы - люди простые, мы изучаем программирование по книжках (не наша вина, если иногда книжка попадётся "неправильная"). Поэтому, пока по голове не прилетит - понятия о таких нюансах не имеем.
карма: 26

0
Ответов: 9906
Рейтинг: 351
#29: 2017-02-03 15:14:16 ЛС | профиль | цитата
Да, это правда. Суровая и горькая правда
карма: 9

0
Ответов: 4612
Рейтинг: 746
#30: 2018-04-16 14:38:03 ЛС | профиль | цитата
Вылез тот же баг в файле CryptoUtils.pas в функции Endian64()


function Endian64(X: Int64): Int64;
begin
Result := (X and $00000000000000FF) shl 56;
Result := Result + (X and $000000000000FF00) shl 40;
Result := Result + (X and $0000000000FF0000) shl 24;
Result := Result + (X and $00000000FF000000) shl 8;
Result := Result + (X and $000000FF00000000) shr 8;
Result := Result + (X and $0000FF0000000000) shr 24;
Result := Result + (X and $00FF000000000000) shr 40;
Result := Result + (X and $FF00000000000000) shr 56;
end;

Предлагается:


function Endian64(X: Int64): Int64;
type
Ti64 = packed record
Lo, Hi: LongWord;
end;
begin
Ti64(Result).Lo := Endian(Ti64(X).Hi);
Ti64(Result).Hi := Endian(Ti64(X).Lo);
end;
Монструозная функция на ассемблере превращается в компактную:

карма: 26

0
Сообщение
...
Прикрепленные файлы
(файлы не залиты)