[Assembler, Компиляторы, C] On commutativity of addition
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Does an assembly change, if we write (b + a) instead (a + b)?
Let's check out.
Let's write:
__int128 add1(__int128 a, __int128 b) {
return b + a;
}
and compile it with risc-v gcc 8.2.0:
add1(__int128, __int128):
.LFB0:
.cfi_startproc
add a0,a2,a0
sltu a2,a0,a2
add a1,a3,a1
add a1,a2,a1
ret
Now write the following:
__int128 add1(__int128 a, __int128 b) {
return a + b;
}
And get:
add1(__int128, __int128):
.LFB0:
.cfi_startproc
mv a5,a0
add a0,a0,a2
sltu a5,a0,a5
add a1,a1,a3
add a1,a5,a1
ret
The difference is obvious.
Now do the same using clang (rv64gc trunk). In both cases we get the same result:
add1(__int128, __int128): # @add1(__int128, __int128)
add a1, a1, a3
add a0, a0, a2
sltu a2, a0, a2
add a1, a1, a2
ret
The result is the same we got from gcc in the first case. Compilers are smart now, but not so smart yet.
Let's try to find out, what happened here and why. Arguments of a function __int128 add1(__int128 a, __int128 b) are passed through registers a0-a3 in the following order: a0 is a low word of «a» operand, a1 is a high word of «a», a2 is a low word of «b» and a1 is the high word of «b». The result is returned in the same order, with a low word in a0 and a high word in a1.
Then high words of two arguments are added and the result is located in a1, and for low words, the result is located in a0. Then the result is compared against a2, i.e. the low word of «b» operand. It is necessary to find out if an overflow has happened at an adding operation. If an overflow has happened, the result is less than any of the operands. Because the operand in a0 does not exist now, the a2 register is used for comparison. If a0 < a2, the overflow has happened, and a2 is set to «1», and to «0» otherwise. Then this bit is added to the hight word of the result. Now the result is located in (a1, a0).
Completely similar text is generated by Clang (rv32gc trunk) for the 32-bit core, if the function has 64-bit arguments and the result:
long long add1(long long a, long long b) {
return a + b;
}
The assembler:
add1(long long, long long): # @add1(long long, long long)
add a1, a1, a3
add a0, a0, a2
sltu a2, a0, a2
add a1, a1, a2
ret
There is absolutely the same code. Unfortunately, a type __int128 is not supported by compilers for 32-bit architecture.
Here there is a slight possibility for the core microarchitecture optimization. Considering the RISC-V architecture standard, a microarchitecture can (but not has to) detect instruction pairs (MULH[[S]U] rdh, rs1, rs2; MUL rdl, rs1, rs2) and (DIV[U] rdq, rs1, rs2; REM[U] rdr, rs1, rs2) to process them as one instruction. Similarly, it is possible to detect the pair (add rdl, rs1, rs2; sltu rdh, rdl, rs1/rs2) and immediately set the overflow bit in the rdh register.
===========
Источник:
habr.com
===========
Похожие новости:
- [CRM-системы, Визуализация данных, Повышение конверсии, Email-маркетинг] Визуализируем коммуникации с клиентами для застройщика на карте
- [Разработка веб-сайтов, JavaScript, VueJS] VueUse — обязательная библиотека для Vue 3
- [Разработка мобильных приложений, Разработка игр, Unity, Дизайн игр] Еще пять инструментов против читеров на мобильном проекте с DAU 1 млн пользователей
- [Законодательство в IT, IT-компании] На этой неделе Евросоюз предъявит Apple обвинение в недобросовестной конкуренции
- [Монетизация веб-сервисов, Бизнес-модели, Облачные сервисы, Социальные сети и сообщества, Звук] Spotify запускает платные подкасты с помощью Anchor
- [IT-компании] Все ли остается в интернете и можно ли это почистить (в контексте права на забвение в российской практике)
- [Open source, IT-инфраструктура] TangoRestServer обновление
- [Развитие стартапа, Управление продуктом] Как выбрать работающие KPI для (потенциально) миллиардного стартапа (перевод)
- [Информационная безопасность, Законодательство в IT, IT-компании] IT-cтруктура ФСБ объяснила случай с SolarWinds игнорированием уязвимостей
- [Исследования и прогнозы в IT] От перфокарты к ДНК: как менялся подход к хранению данных
Теги для поиска: #_assembler, #_kompiljatory (Компиляторы), #_c, #_llvm, #_riscv, #_optomization, #_assembler, #_kompiljatory (
Компиляторы
), #_c
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 02:55
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Does an assembly change, if we write (b + a) instead (a + b)? Let's check out. Let's write: __int128 add1(__int128 a, __int128 b) {
return b + a; } and compile it with risc-v gcc 8.2.0: add1(__int128, __int128): .LFB0: .cfi_startproc add a0,a2,a0 sltu a2,a0,a2 add a1,a3,a1 add a1,a2,a1 ret Now write the following: __int128 add1(__int128 a, __int128 b) {
return a + b; } And get: add1(__int128, __int128): .LFB0: .cfi_startproc mv a5,a0 add a0,a0,a2 sltu a5,a0,a5 add a1,a1,a3 add a1,a5,a1 ret The difference is obvious. Now do the same using clang (rv64gc trunk). In both cases we get the same result: add1(__int128, __int128): # @add1(__int128, __int128) add a1, a1, a3 add a0, a0, a2 sltu a2, a0, a2 add a1, a1, a2 ret The result is the same we got from gcc in the first case. Compilers are smart now, but not so smart yet. Let's try to find out, what happened here and why. Arguments of a function __int128 add1(__int128 a, __int128 b) are passed through registers a0-a3 in the following order: a0 is a low word of «a» operand, a1 is a high word of «a», a2 is a low word of «b» and a1 is the high word of «b». The result is returned in the same order, with a low word in a0 and a high word in a1. Then high words of two arguments are added and the result is located in a1, and for low words, the result is located in a0. Then the result is compared against a2, i.e. the low word of «b» operand. It is necessary to find out if an overflow has happened at an adding operation. If an overflow has happened, the result is less than any of the operands. Because the operand in a0 does not exist now, the a2 register is used for comparison. If a0 < a2, the overflow has happened, and a2 is set to «1», and to «0» otherwise. Then this bit is added to the hight word of the result. Now the result is located in (a1, a0). Completely similar text is generated by Clang (rv32gc trunk) for the 32-bit core, if the function has 64-bit arguments and the result: long long add1(long long a, long long b) {
return a + b; } The assembler: add1(long long, long long): # @add1(long long, long long) add a1, a1, a3 add a0, a0, a2 sltu a2, a0, a2 add a1, a1, a2 ret There is absolutely the same code. Unfortunately, a type __int128 is not supported by compilers for 32-bit architecture. Here there is a slight possibility for the core microarchitecture optimization. Considering the RISC-V architecture standard, a microarchitecture can (but not has to) detect instruction pairs (MULH[[S]U] rdh, rs1, rs2; MUL rdl, rs1, rs2) and (DIV[U] rdq, rs1, rs2; REM[U] rdr, rs1, rs2) to process them as one instruction. Similarly, it is possible to detect the pair (add rdl, rs1, rs2; sltu rdh, rdl, rs1/rs2) and immediately set the overflow bit in the rdh register. =========== Источник: habr.com =========== Похожие новости:
Компиляторы ), #_c |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 02:55
Часовой пояс: UTC + 5