Главное меню
Мы солидарны с Украиной. Узнайте здесь, как можно поддержать Украину.

Ответ

Обратите внимание: данное сообщение не будет отображаться, пока модератор не одобрит его.
Ограничения: максимум вложений в сообщении — 3 (3 осталось), максимальный размер всех файлов — 300 КБ, максимальный размер одного файла — 100 КБ
Снимите пометку с вложений, которые необходимо удалить
Перетащите файлы сюда или используйте кнопку для добавления файлов
Вложения и другие параметры
Проверка:
Оставьте это поле пустым:
Наберите символы, которые изображены на картинке
Прослушать / Запросить другое изображение

Наберите символы, которые изображены на картинке:

√36:
ALT+S — отправить
ALT+P — предварительный просмотр

Сообщения в этой теме

Автор Drundia
 - октября 16, 2011, 20:45
Продолжаю баловаться. Похоже что     if ((x+rhs.x) < rhs.x) x=x-n+rhs.x;
    else x+=rhs.x;
компилируется лучше (догадался, что (a+b)<a для беззнаковых — это тест кэрри-флэга, и даже догадался, что последующие операции сложения используют уже посчитанное x+rhs.x), чем
  if ((x+=rhs.x) < rhs.x) x-=n; Забавно.

Для уважаемых модераторов: думаю, не помешало бы кусок темы, посвящённый компиляции сишного (сиплюсплюсного) кода в x86-ассембли вынести в отдельную тему.
Автор Drundia
 - октября 16, 2011, 19:27
Цитата: mnashe от октября 16, 2011, 18:02
В моей программе есть специальная функция от трёх параметров — muldiv. Она такую цепочку как раз и задействует.
Со всеми оптимизациями код
x = ((unsigned long long)x*rhs.x) % n;
даёт вполне пригодное умножение, но для остатка всё равно использует встроенную функцию для деления слишком длинных целых ___umoddi3 :( Надо будет посмотреть когда-нибудь, как она устроена.

В сложении явно использует при подобном коде больше регистров, чем надо.

Если преобразовывать уже результат умножения, то код для определения остатка вполне пригодный; но старшее слово теряется, что соответствует стандарту. Нехорошо.
Автор mnashe
 - октября 16, 2011, 18:02
Цитата: Drundia от октября 16, 2011, 17:36С умножением ещё веселее. Надо получить int64 из int32*int32, а потом найти остаток от деления этого int64 на int32. Нормальный код получить не выходит, а вот добрый дядя Интел всё необходимое предусмотрел.
В моей программе есть специальная функция от трёх параметров — muldiv. Она такую цепочку как раз и задействует.
Остаток от деления, правда, отбрасывается, но пока в такой цепочке он мне не был нужен.
Посчитал, сколько раз эта функция используется у меня в макрях: 46.
Автор Drundia
 - октября 16, 2011, 17:36
Вот-вот, и никакие оптимизации не спасают.

Ещё есть забавная задача с арифметикой по модулю. Без ассемблера никуда.

    if ((x+=rhs.x) < rhs.x) x-=n;
даёт
        mov     eax, DWORD PTR [edx+4]
        add     eax, DWORD PTR [ecx+4]
        mov     DWORD PTR [ecx+4], eax
        cmp     eax, DWORD PTR [edx+4]  ;ересь
        jae     L2
LVL1:
        sub     eax, DWORD PTR [ecx]
        mov     DWORD PTR [ecx+4], eax
L2:

Учитывая беззнаковость операндов, условие в if'е — это просто установка CF при сложении. Стало быть ересь не нужна. К счастью, jnc===jae. Впрочем, ассемблером можно и красивее, учитывая что нам потом нужен остаток от деления.

С умножением ещё веселее. Надо получить int64 из int32*int32, а потом найти остаток от деления этого int64 на int32. Нормальный код получить не выходит, а вот добрый дядя Интел всё необходимое предусмотрел.

Впрочем, GCC всё же неплохо умеет интегрировать сишный и ассемблийный код, что избавляет от ненужной мороки.
    asm (
        "mul %[b0]\n\t"
        "div %[d0]\n\t"
        :[a] "=d" (x)        // лучше "=&d"?
        :[a0] "a" (x), [b0] "g" (rhs.x), [d0] "g" (n)
    );



Вывод: языки высокого уровня для низкоуровневых задач не годятся.
Автор mnashe
 - октября 15, 2011, 22:43
Цитата: Drundia от октября 14, 2011, 21:32
Цитата: Python от октября 14, 2011, 15:22
Не факт.
Ой-ой-ой, таки не факт, обнаружил жуткую ересь!

c = a/b; d = a%b;
даёт
mov     eax, DWORD PTR [esp+20]
mov     edx, DWORD PTR [esp+16]
mov     ecx, edx
cdq
idiv    ecx
mov     DWORD PTR [esp+24], eax
mov     eax, DWORD PTR [esp+20]
mov     edx, DWORD PTR [esp+16]
mov     ecx, edx
cdq
idiv    ecx
mov     DWORD PTR [esp+28], edx

Вот-вот.
Задача, кстати, весьма практическая: например, при переводе числа в строку.
И это не единственный случай. Если такое делается в многократно повторяющемся цикле, разница будет ощутимой.
Хотя, конечно, на шкале между древними компиляторами высоких языков и ассемблером современные компиляторы ближе к ассемблеру.
Автор Drundia
 - октября 14, 2011, 21:32
Цитата: Python от октября 14, 2011, 15:22
Не факт.
Ой-ой-ой, таки не факт, обнаружил жуткую ересь!

c = a/b; d = a%b;
даёт
mov     eax, DWORD PTR [esp+20]
mov     edx, DWORD PTR [esp+16]
mov     ecx, edx
cdq
idiv    ecx
mov     DWORD PTR [esp+24], eax
mov     eax, DWORD PTR [esp+20]
mov     edx, DWORD PTR [esp+16]
mov     ecx, edx
cdq
idiv    ecx
mov     DWORD PTR [esp+28], edx
Автор Drundia
 - октября 14, 2011, 16:16
Ну то что для базовых типов (a=a+b) === (a+=b) — знают.
Автор Python
 - октября 14, 2011, 15:22
ЦитироватьА нынче компиляторы умные пошли. Оптимизируют.
Не факт.
Автор Drundia
 - октября 14, 2011, 15:20
Цитата: jvarg от октября 14, 2011, 11:47
Угу, только это лишние байты, что при тогдашних объемах памяти и быстродействии имело огромное значение.
Тогда лучше было не функции использовать, а goto.

Цитата: jvarg от октября 14, 2011, 11:47
Для тогдашних маленьких машин были и компиляторы высокоуровневых языков, однако именно потому для создания практических программ и использовался, в основном, ассемблер, что он позволял сократить объем программы даже на таких мелочах, как передача параметров через стек.
Ну да, передавайте через регистры... Только кто полезные значения из регистров и где сохранять будет? Правильно, в стэке.

Цитата: mnashe от октября 14, 2011, 14:06
И не только объём программы, но и быстродействие.
А нынче компиляторы умные пошли. Оптимизируют.
Автор mnashe
 - октября 14, 2011, 14:06
Цитата: jvarg от октября 14, 2011, 11:47
Для тогдашних маленьких машин были и компиляторы высокоуровневых языков, однако именно потому для создания практических программ и использовался, в основном, ассемблер, что он позволял сократить объем программы даже на таких мелочах, как передача параметров через стек.
И не только объём программы, но и быстродействие.