Форум программистов, компьютерный форум, киберфорум
Низкоуровневое программирование
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.60/15: Рейтинг темы: голосов - 15, средняя оценка - 4.60
199 / 86 / 9
Регистрация: 15.11.2010
Сообщений: 472
1

Арифметические операции над небольшими целыми числами в процессоре SPARC

11.09.2016, 14:11. Просмотров 2995. Ответов 57
Метки нет (Все метки)

Здравствуйте, форумчане!

Есть ли среди вас знатоки архитектуры SPARC? Если да, то просветите меня, пожалуйста, по такому вопросу.

Как в процессоре SPARC выполняются простые арифметические действия над целыми числами размера меньшего, чем стандартное машинное слово этого процессора (32 или 64 бит)? Допустим, нам надо выполнить какую-то простую операцию над байтом или 16-битным полусловом. Мне хотелось бы понять, каким набором машинных инструкций эта операция над байтом или полусловом длиной в 16 бит будет воплощена? Особенно мне интересно, как осуществляется контроль за переполнением разрядной сетки в этом случае.

В случае архитектуры x86 особых вопросов не возникает - как и в любой другой CISC-архитектуре код операции (поле КОП) в команде один и тот же независимо от размера данных, а собственно размер операндов задаётся специальными битами признаков внутри самой команды. Проблемы контроля переполнения данных в x86 (как, впрочем, и в других CISC-архитектурах) тоже нет. Фиксируется переполнение той разрядной сетки, которая указана в поле длины операндов. Т. е. если длина данных равняется одному байту - в регистре флагов фиксируется выход значения за границы одного байта, если операнды представляют собой 16-битные полуслова - фиксируется выход за пределы 16-битного представления целых чисел, если длина операндов равна 32-битному слову, результат должен помещаться в 32 бита (в противном случае будут установлены соответствующие флаги в регистре флагов). То же самое относится к 64-разрядным целым числам.

Хотелось бы понять, как те же самые проблемы (хранения небольших целых чисел размера меньшего длины машинного слова, манипулирования этими маленькими числами, контроля над переполнением данных при арифметических операциях с их участием) решаются в архитектуре SPARC. Для примера можно было бы рассмотреть какое-то простое арифметическое действие (например, сложение или вычитание) над двумя числами размером с байт или 16-битное полуслово и привести элементарную программку, которая его выполняет.

Был бы очень благодарен тем, кто мне ответит.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
11.09.2016, 14:11
Ответы с готовыми решениями:

Арифметические опреции над целыми числами
Привет ))) Народ, оч нужно решить задачку((( не как не могу сделать эту лабу... суть такова......

Арифметические операции над числами
Доброго вечера.Помогите-помогите,завтра нужно сдать,иначе не видать зачета( нужно написать...

Арифметические операции над числами
Пользователь вводит с клавиатуры два целочисленных значения: X и Y. Рассчитать сумму X+Y и...

Арифметические операции над числами
Пытаюсь написать программу, производящую арифметические операции над числами, которые не входят в...

57
1576 / 809 / 146
Регистрация: 13.06.2015
Сообщений: 2,939
11.09.2016, 17:27 2
Это делается путём "вырезания" операндов из машинного слова операцией and со сдвигом в младшие разряды, затем проведение нужного действия, контроль битов переполнения (он будут левее "вырезанных" операндов) с их последующим занулением (опять and) и "врезание" результата обратно в машинное слово сдвигом и операцией or.
P.S. С архитектурой SPARC не работал, это просто общие принципы по которым всегда это делают.
1
1321 / 483 / 67
Регистрация: 21.07.2015
Сообщений: 1,248
12.09.2016, 17:01 3
Ну так работай с любым машинным словом, только младшие старшие биты занули.
1
199 / 86 / 9
Регистрация: 15.11.2010
Сообщений: 472
05.10.2016, 05:06  [ТС] 4
Прошу прощение за задержку с ответом, просто был долго в отъезде.

Цитата Сообщение от Kukuxumushu Посмотреть сообщение
Это делается путём "вырезания" операндов из машинного слова операцией and со сдвигом в младшие разряды, затем проведение нужного действия, контроль битов переполнения (он будут левее "вырезанных" операндов) с их последующим занулением (опять and) и "врезание" результата обратно в машинное слово сдвигом и операцией or.
P.S. С архитектурой SPARC не работал, это просто общие принципы по которым всегда это делают.
Kukuxumushu, это всё верно и я это понимаю. Это способ работы с машинными словами произвольной длины при условии, что процессор поддерживает работу только со словами одного единственного размера (допустим, 64 бит) и не имеет команд (или режимов) для работы со словами меньшей длины (допустим, 32, 16 или 8 бит). По сути ведь это не что иное, как программная эмуляция работы команд, выполняющих действия над операндами меньшей длины, при отсутствии таких команд в процессоре. Смысл этой эмуляции сводится к тому, что мы обнуляем старшие "лишние" биты в регистрах, хранящих операнды, выполняем арифметическое действие (сложение, вычитание или умножение), а потом проверяем, не появились ли в этих старших, обнулённых ранее битах единицы (выполнить эту проверку можно операцией or). Если единицы появились, значит, произошло переполнение.

Но ведь в процессоре Intel, единственном процессоре, ассемблер которого я немного знаю, никакой необходимости в такой имитации нет. Там ведь для каждой арифметической команды или команды побитовой логики предусмотрены различные режимы, позволяющие работать со словами произвольного размера - от байта до 64-битного слова.

Допустим, для того чтобы сложить два байта, размещённых в регистрах, нам достаточно выполнить такую инструкцию
Assembler
1
add ah, bh
или
Assembler
1
add al, bl
Аналогично, для слов длиной в 16 бит выполняем
Assembler
1
add ax, bx
Чтобы сложить два 32-битных слова, делаем так
Assembler
1
add eax, ebx
То же самое для слов 64-битного размера выглядит как
Assembler
1
add rax, rbx
Результат переполнения фиксируется в регистре флагов - в бите CF (carry flag), который интерпретирует операцию как действие над беззнаковыми числами, и в бите OF (overflow flag), который воспринимает операцию как действие над числами со знаком. При этом каждый вариант команды (над байтами, словами 16, 32 и 64 бит) фиксирует в CF и OF переполнение именно для операндов своего типа, своей длины. Т. е. команда, работающая с байтами, будет в этих двух битах фиксировать случай, когда результат не помещается в байт, команда, работающая со словами длиной в 16 бит, фиксирует в CF или OF случай, когда результат не уместился в слово длиной 16 бит. Для случая 32 и 64 двоичных разрядов всё аналогично - соответствующие команды фиксируют во флагах именно переполнение 32-ух и 64-ёх-разрядной арифметики. Далее состояние этих флагов можно проанализировать командами условного перехода (например, JO или JC).

Никакой необходимости во всей этой химии с предварительным обнулением старших битов в регистре, хранящем машинное слово избыточной длины, а потом с проверкой, не появились ли единички в этих старших битах после выполнения операции (что позволяет выполнить контроль переполнения), в x86 нет, так как x86 позволяет работать со словами разной длины напрямую. Я и хотел спросить, а как всё это делается в процессоре SPARC.
0
199 / 86 / 9
Регистрация: 15.11.2010
Сообщений: 472
07.10.2016, 00:50  [ТС] 5
И всё же очень хотелось бы получить ответ на вопрос, заданный мною в исходном сообщении. Если есть здесь знатоки низкоуровневого программирования процессора SPARC или RISC-процессоров вообще — отзовитесь, пожалуйста.
0
1321 / 483 / 67
Регистрация: 21.07.2015
Сообщений: 1,248
07.10.2016, 02:39 6
JohnyWalker, именно так и делается.
0
199 / 86 / 9
Регистрация: 15.11.2010
Сообщений: 472
07.10.2016, 04:13  [ТС] 7
Цитата Сообщение от shmkv Посмотреть сообщение
JohnyWalker, именно так и делается.
Т. е. никаких команд, позволяющих работать напрямую с байтами и полусловами в 16 бит, процессор SPARC не имеет и контроль переполнения целочисленных арифметических операций на уровне байт, полуслов и т. п. в нём напрочь отсутствует? Невозможно, допустим, сложить 2 беззнаковых целых числа размером в байт и проверить на аппаратном уровне через флаги переполнения (или что-то другое в этом роде), уместился ли результат в байт или превзошёл его?

Всё это можно сделать только над словами в 32 бит для архитектуры sparc v8 или над словами 32 и 64 бит в случае архитектуры sparc v9? Работу над байтами и 16-битовыми полусловами приходится эмулировать программно через 32 или 64-битные регистры, а потом таким же программным путём (с помощью операций побитовой логики) определять, произошло переполнение байта или полуслова в 16 бит или нет?

Это всё действительно так?
0
Ушел с форума
Автор FAQ
13991 / 7003 / 815
Регистрация: 11.11.2010
Сообщений: 12,598
07.10.2016, 08:53 8
JohnyWalker,
а кто мешает поместить данные размером в байт в 32-разрядный регистр и сдвинуть содержимое влево на 24 разряда или данные размером в слово помещенные в 32-разрядный регистр сдвигаются на 16 разрядов. При сложении/вычитании будут взведены/сброшены флаги переноса/переполнения
1
1321 / 483 / 67
Регистрация: 21.07.2015
Сообщений: 1,248
07.10.2016, 11:43 9
Цитата Сообщение от JohnyWalker Посмотреть сообщение
Невозможно, допустим, сложить 2 беззнаковых целых числа размером в байт и проверить на аппаратном уровне через флаги переполнения (или что-то другое в этом роде), уместился ли результат в байт или превзошёл его?
Складываешь, если 9й бит результата = 1, значит произошло переполнение.
1
199 / 86 / 9
Регистрация: 15.11.2010
Сообщений: 472
07.10.2016, 22:16  [ТС] 10
Цитата Сообщение от Mikl___ Посмотреть сообщение
JohnyWalker,
а кто мешает поместить данные размером в байт в 32-разрядный регистр и сдвинуть содержимое влево на 24 разряда или данные размером в слово помещенные в 32-разрядный регистр сдвигаются на 16 разрядов. При сложении/вычитании будут взведены/сброшены флаги переноса/переполнения
Mikl___, разумно. Не пришёл в голову сразу этот вариант. А казалось бы, он сойдёт и для случая сложения, и для случая вычитания, как знаковых, так и беззнаковых чисел. Не проверял, но похоже, что это так. И действительно, будут сброшены/взведены флаги, которые можно будет после этого проанализировать каким-нибудь jump'ом. Просто меня в данном случае интересовал несколько иной вопрос — действительно ли в RISC-процессорах отсутствует хоть какая-то возможность выполнения арифметических операций на уровне байт и полуслов в 16 бит и невозможно контролировать на этом уровне переполнение и перенос (то, что программная имитация всего этого возможна, я понимаю, но речь сейчас не о том). Хотел разобраться с этим вопросом на примере SPARC'ов. Вроде это действительно так, но хотелось бы получить чёткий и исчерпывающий ответ.
0
Ушел с форума
Автор FAQ
13991 / 7003 / 815
Регистрация: 11.11.2010
Сообщений: 12,598
08.10.2016, 03:47 11
shmkv,
Цитата Сообщение от shmkv Посмотреть сообщение
если 9й бит результата = 1, значит произошло переполнение
если 9-ый бит результата = 1, значит произошел перенос, а переполнение это
OF = CF xor SOP1 xor SOP2 xor SRESULT
где CF - значение флага переноса, SOP1 - знак 1-ого операнда, SOP2 - знак второго операнда, SRESULT - знак результата. Подробности есть в https://www.cyberforum.ru/asse... 05284.html https://www.cyberforum.ru/cgi-bin/latex.cgi?\rightarrow"ГЛАВА 10. АРИФМЕТИЧЕСКИЕ КОМАНДЫ"https://www.cyberforum.ru/cgi-bin/latex.cgi?\rightarrow "Флаги переполнения и переноса"
2
1321 / 483 / 67
Регистрация: 21.07.2015
Сообщений: 1,248
08.10.2016, 16:48 12
Mikl___, я имел ввиду для для беззнаковых чисел. Точнее не 9й,а 8й бит.
0
Evg
Эксперт CАвтор FAQ
21139 / 8155 / 628
Регистрация: 30.03.2009
Сообщений: 22,465
Записей в блоге: 30
21.11.2016, 19:34 13
Цитата Сообщение от JohnyWalker Посмотреть сообщение
Как в процессоре SPARC выполняются простые арифметические действия над целыми числами размера меньшего, чем стандартное машинное слово этого процессора (32 или 64 бит)? Допустим, нам надо выполнить какую-то простую операцию над байтом или 16-битным полусловом. Мне хотелось бы понять, каким набором машинных инструкций эта операция над байтом или полусловом длиной в 16 бит будет воплощена? Особенно мне интересно, как осуществляется контроль за переполнением разрядной сетки в этом случае
Общий принцип я расписывал в Int vs int fast - как проверить производительность?

На sparc начиная с v9 имеется, грубо говоря, единственная операция сложения - add. Она работает на 64-битными операндами (коими являются регистр либо 13-битный литерал). Поэтому ответ на вопрос кроется не столько в операции сложения, сколько в том месте, кто формирует операнды для операции сложения. Если нужен какой-то контроль за битами переполнения, то нужно следит за тем, чтобы в старших битах было сформировано нужное значение. Если этот контроль не нужен, то значения в старших битах безразличны (поскольку они не влияю на младшие биты результата)

Добавлено через 2 минуты
Цитата Сообщение от JohnyWalker Посмотреть сообщение
Для примера можно было бы рассмотреть какое-то простое арифметическое действие (например, сложение или вычитание) над двумя числами размером с байт или 16-битное полуслово и привести элементарную программку, которая его выполняет
В простейшем случае аргументы сложения лежат в памяти. Для их чтения используется операция ldh. Она читает 16 бит из памяти и кладёт их в младшие 16 бит регистра. А оставшиеся 48 бит заполняет нулями. Если я ничего не путаю, то ест ещё операция ldsh вроде бы, которая старшие 48 бит заполняет знаком (значением 15-го бита, если считать с нуля)

Добавлено через 4 минуты
Цитата Сообщение от JohnyWalker Посмотреть сообщение
Особенно мне интересно, как осуществляется контроль за переполнением разрядной сетки в этом случае
Что-то я немного протупил. тут ведь вопрос касался о переполнении в 8-м и 16-м бите, а не в старшем. Я с ходу не могу сказать, завтра систему команд почитаю, если доберусь до неё
1
199 / 86 / 9
Регистрация: 15.11.2010
Сообщений: 472
21.11.2016, 20:28  [ТС] 14
Цитата Сообщение от Evg Посмотреть сообщение
Что-то я немного протупил. тут ведь вопрос касался о переполнении в 8-м и 16-м бите, а не в старшем. Я с ходу не могу сказать, завтра систему команд почитаю, если доберусь до неё
Давайте, было бы очень интересно! Посмотрите, что об этом пишут в учебниках и справочниках по SPARC.

А заодно, если Вы не против, можно было бы поступить так. Вы бы написали маленькую программу на ассемблере SPARC, проводящую подобную манипуляцию над числами и анализирующую случай переполнения, а я бы написал какую-нибудь идиотскую программу на C, выполняющую простейшие операции над целыми числами различного размера, со знаком и без. Что-то в духе

C
1
c = a + b;
Вы бы, если имеете сейчас доступ к компьютеру с процессором SPARC, скомпилировали бы её при помощи gcc и компилятора Sun/Oracle Studio, задав и в том, и в другом случае для компилятора флаг , заставляющий его производить не объектный файл, а ассемблерный листинг. В случае gcc, это, если не ошибаюсь, флаг -S. Какой флаг используется для этого в компиляторе от Sun/Oracle Studio, я не знаю. И оба листинга (один, полученный gcc, другой cc от Sun/Oracle Studio) можно было бы выложить прямо здесь. Ну, и конечно, очень хотелось бы увидеть такую демонстрационную программу, написанную на ассемблере вручную. Но это всё, конечно, при условии, что оно Вас не затруднит.
0
Evg
Эксперт CАвтор FAQ
21139 / 8155 / 628
Регистрация: 30.03.2009
Сообщений: 22,465
Записей в блоге: 30
21.11.2016, 20:40 15
Какой будет ассемблерный код из-под программы на Си я в общем-то и так знаю. Но там не будет ничего, что связано с переполнениями. Я просто не совсем понимаю конечную цель эксперимента
1
199 / 86 / 9
Регистрация: 15.11.2010
Сообщений: 472
22.11.2016, 05:59  [ТС] 16
Evg, а цель этого эксперимента очень проста. Просто мне хочется посмотреть на код, который породит компилятор для всех этих манипуляций над целыми числами разного размера. Понятно, что код компилятора над числами будет достаточно рационален — никакой глупости заставлять делать процессор он не будет, всё же компиляторы пишут не идиоты, а люди, хорошо разбирающиеся в машине)) Т. е. этот код будет учитывать все возможности данного процессора: он не будет заставлять его выполнять ненужные, бесполезные, лишние операции - лишние пересылки данных, преобразования типов, бесполезные сравнения, когда всё это можно сделать более простым и коротким путём с меньшим числом команд, но компилятор и не сможет заставить процессор сделать невозможное. Если не умеет данный процессор работать с байтами и шестнадцатиразрядными целыми, то компилятор никак его не заставит это делать — все вычисления всё равно будут производиться над 64-битными операндами, операции над байтами и 16-битными целыми будут проводиться через 64-разрядные целые. Т. е. компилятор сделает максимум того, что можно сделать (его код будет не сильно хуже того, что сможет написать в данном случае на ассемблере человек), но не более того. Мне и хочется своими глазами взглянуть на этот код, на этот ассемблерный листинг, он мне очень многое даст для понимания. Вот и вся цель данного эксперимента. А заодно я скомпилирую свою тестовую программу под платформу x86 (с помощью gcc или Visual Studio) и сравню код для платформы Intel с кодом для SPARC. Очень наглядное сравнение возможностей и организации системы команд двух процессоров.

Ну и конечно очень хотелось бы увидеть вручную составленную на ассемблере для SPARC'а демонстрационную программу, иллюстрирующую все эти вещи. Может, в справочниках и учебниках по SPARC'у такие программы и есть — можно было бы просто скопипастить их сюда.

Добавлено через 18 минут
Цитата Сообщение от Evg Посмотреть сообщение
Какой будет ассемблерный код из-под программы на Си я в общем-то и так знаю. Но там не будет ничего, что связано с переполнениями.
Да, чистый C в том виде, в каком он описан в стандартах и изложен в учебниках не предполагает ничего, что позволяло бы контролировать переполнение — таких операций там просто нет. Но вот, возможно, есть какие-то нестандартные расширения языка, которые всё же позволяют это делать (в виде ли библиотечных функций, макросов или даже базовых средств самой реализации языка). Хорошо, если такие проверки реализованы через нижний аппаратный уровень машины (допустим, в случае x86 задействуют флаги OF и CF, а в случае SPARC те возможности данного процессора, какие у него для этого есть), а не чисто алгоритмическим путём (в духе, c = a + b; все три числа беззнаковые; раз c < a || c < b , значит, произошло переполнение целого при сложении).

Не уверен точно, но вроде я такую возможность некоторых реализаций языка C где-то видел, что-то мне такое вроде бы попадалось.

Добавлено через 7 часов 55 минут
Вот что удалось разыскать по поводу встроенных в сишный компилятор арифметических действий, выполняющих проверку переполнения
https://gcc.gnu.org/onlinedocs... ltins.html.

Так и не понял, правда, что представляют собой эти функции. Это обычные библиотечные функции, входящие в glibc, это какие-то сложные макросы, разворачиваемые препроцессором, или же это встроенные в сам компилятор (не в библиотеки и не в .h-файлы!) операции, распознаваемые им и приводящие к генерации кода? Т. е. это не библиотечные функции и не макросы, а именно базовые синтаксические конструкции самого компилятора? Как вы думаете?

Интересно, в компиляторе Oracle Developer Studio есть что-то подобное или нет? Или в компиляторе MS Visual Studio? Любопытно, как всё это работает — опирается на инструкции процессора, позволяющие проверить переполнение арифметических операций, например, путём проверки соответствующих флагов (OF и СF в x86), или же всё это воплощено платформо-независимым способом, не опираясь на железо (допустим, путём сравнения между собой операндов и результата)?
0
Evg
Эксперт CАвтор FAQ
21139 / 8155 / 628
Регистрация: 30.03.2009
Сообщений: 22,465
Записей в блоге: 30
22.11.2016, 14:35 17
Цитата Сообщение от JohnyWalker Посмотреть сообщение
Просто мне хочется посмотреть на код, который породит компилятор для всех этих манипуляций над целыми числами разного размера
В посте #13 я написал, что будет сделано. Но если тебе это так важно, то позже покажу код из-под компилятора

Цитата Сообщение от JohnyWalker Посмотреть сообщение
Ну и конечно очень хотелось бы увидеть вручную составленную на ассемблере для SPARC'а демонстрационную программу, иллюстрирующую все эти вещи
Этого я тоже не понимаю. Чем вручную написанная программа принципиально отличается от ассемблерного кода, рождённого компилятором?

Цитата Сообщение от JohnyWalker Посмотреть сообщение
Да, чистый C в том виде, в каком он описан в стандартах и изложен в учебниках не предполагает ничего, что позволяло бы контролировать переполнение — таких операций там просто нет. Но вот, возможно, есть какие-то нестандартные расширения языка, которые всё же позволяют это делать
Из того, что я видел в жизни - такие вещи всегда реализуются на ассемблерных вставках. Возможно, они накрыты каким-то библиотечным интерфейсом. Я в общем-то не знаком с библиотеками, специализированными для математичеких рассчётов, но если найдёшь какую-нибудь подобную, то на уровне интерфейсов они почти наверняка будут выглядеть одинаково для всех архитектур, но внутри будут иметь собственные кишки

Цитата Сообщение от JohnyWalker Посмотреть сообщение
Так и не понял, правда, что представляют собой эти функции
Это не функции. По синтаксису они выглядят как функции, но по сути это встроенные в язык операции. Они могли бы вместо синтаксиса функции ввести какую-нибудь закорючку (типа +, -, *, /), но беда в том, что все закорючки уже давно задействованы

Цитата Сообщение от JohnyWalker Посмотреть сообщение
Т. е. это не библиотечные функции и не макросы, а именно базовые синтаксические конструкции самого компилятора? Как вы думаете?
Я не то чтоб думаю, я точно знаю, что это именно так.

Цитата Сообщение от JohnyWalker Посмотреть сообщение
Интересно, в компиляторе Oracle Developer Studio есть что-то подобное или нет? Или в компиляторе MS Visual Studio?
Наверняка есть, но выглядят по другому. В природе такого понятия как "чистый Си" не существует. У каждого компилятора есть собственные расширения

Цитата Сообщение от JohnyWalker Посмотреть сообщение
Любопытно, как всё это работает — опирается на инструкции процессора, позволяющие проверить переполнение арифметических операций, например, путём проверки соответствующих флагов (OF и СF в x86), или же всё это воплощено платформо-независимым способом, не опираясь на железо (допустим, путём сравнения между собой операндов и результата)?
Для тех архитектур, где есть аппаратная поддержка, там должны использоваться встроенные операции. Для тех, у кого в процессоре таких инструкций нет и для тех архитектур, для которых разработчики компилятора пока это не поддержали - там будет использоваться эмуляция. Собственно, все builtin'ы в gcc построены по такому принципу

Я, честно говоря, не совсем понял, в какой версии gcc появились эти builtin'ы. В официальной документации от gcc-6.2 я что-то не нашёл этих описаний. Видимо, это ссылка из самой свежей версии, которая пока ещё в процессе разработки. Т.е. много лет они жили без этого, но по каким-то причинам решили наконец встроить в язык

Добавлено через 2 часа 57 минут
Исходник:

C
short a, b, c;
void foo (void) { a = b - c; }
Код на gcc без оптимизаций:

Код
foo:
        save    %sp, -96, %sp
        sethi   %hi(b), %g1
        or      %g1, %lo(b), %g1
        lduh    [%g1], %g1
        mov     %g1, %g2
        sethi   %hi(c), %g1
        or      %g1, %lo(c), %g1
        lduh    [%g1], %g1
        sub     %g2, %g1, %g1
        mov     %g1, %g2
        sethi   %hi(a), %g1
        or      %g1, %lo(a), %g1
        sth     %g2, [%g1]
        restore
        jmp     %o7+8
         nop
Код на gcc с оптимизациями:

Код
foo:
        sethi   %hi(b), %g1
        lduh    [%g1+%lo(b)], %g2
        sethi   %hi(c), %g1
        lduh    [%g1+%lo(c)], %g1
        sub     %g2, %g1, %g2
        sethi   %hi(a), %g1
        jmp     %o7+8
         sth    %g2, [%g1+%lo(a)]
Код на Sun CC без оптимизаций:

Код
foo:
        save    %sp,-96,%sp

        ! block 1
.L17:

! File t.c:
!    1  short a, b, c;
!    2  void foo (void) { a = b - c; }

        sethi   %hi(b),%o0
        ldsh    [%o0+%lo(b)],%o1
        sethi   %hi(c),%o0
        ldsh    [%o0+%lo(c)],%o0
        sub     %o1,%o0,%o1
        sethi   %hi(a),%o0
        sth     %o1,[%o0+%lo(a)]
        jmp     %i7+8
        restore

        ! block 2
.L16:
        jmp     %i7+8
        restore
Код на Sun CC с оптимизациями:

Код
                       foo:
/* 000000          2 */         sethi   %hi(b),%o5
/* 0x0004            */         sethi   %hi(c),%o4
/* 0x0008            */         ldsh    [%o5+%lo(b)],%o3
/* 0x000c            */         sethi   %hi(a),%o2
/* 0x0010            */         ldsh    [%o4+%lo(c)],%o5
/* 0x0014            */         sub     %o3,%o5,%o1
/* 0x0018            */         retl    ! Result = 
/* 0x001c            */         sth     %o1,[%o2+%lo(a)]
Отличие между gcc'шным и suncc'шным кодом в том, что один использует операции lduh (чтение 16 бит с заполнением старшей части нулями), другой ldsh (чтение 16 бит с заполнением старшей части знаками). Эта разница непринципаильная и только подчёркивает тот факт, что пофиг, чем заполнена старшая часть

Добавлено через 2 часа 0 минут
На sparc'е есть флаги для 32-го и 64-го битов, но нету для 8-го и 16-го. Каких-то специальных операций для эмуляции нет. Т.е. для 8-го и 16-го бита все флаги переноса нужно считать вручную

Добавлено через 1 минуту
Точнее так: для v8 есть только флаги для 32-го бита (поскольку машина была ещё 32-разрядная). А для v9 есть 32 и 64 (причём 32 сделано для поддержки совместимости с v8)
1
199 / 86 / 9
Регистрация: 15.11.2010
Сообщений: 472
22.11.2016, 19:40  [ТС] 18
Evg, большое спасибо за такой полный и исчерпывающий ответ! По поводу этих builtin'ов — вот что сходу удалось нагуглить:
https://news.ycombinator.com/item?id=8766210
https://gcc.gnu.org/gcc-5/changes.html

Т. е. они, похоже, появились только в пятой версии gcc.
MinGW, основанный на gcc 4.9.3, эти функции не опознаёт и отказывается программу с их участием напрочь компилировать.

Я правильно понимаю, что для использования встроенных функций компилятора gcc (builtins), не нужно в исходник программы добавлять никаких заголовочников (файлов *.h)?

Добавлено через 31 минуту
Посмотрел у себя в Debian'е и с удивлением обнаружил, что там тоже стоит четвёртая версия gcc — gcc 4.9.2, т. е. даже ещё более старый gcc, чем в MinGW под Windows (MinGW использует версию 4.9.3), хотя инсталляция Debian'а свеженькая — 8.6, Jessie, буквально на днях устанавливал.

Даже не знаю, как и где эти builtin'ы скомпилировать и посмотреть, как они работают.

Добавлено через 20 минут
Любопытно, почему разработчики дистрибутивов, будь то MinGW для Windows или даже последние дистрибутивы Linux, так упорно не хотят переходить на новые версии gcc. Или они их считают недостаточно зрелыми и надёжными из-за того, что в них много ошибок, или эти новые версии плохо совместимы с прежними старыми версиями того же компилятора, что порождает трудности при работе с ним, или же этот новый компилятор вводит всякие строгости и ограничения в синтаксисе C и C++, а программисты Linux привыкли к более свободному синтаксису более старых версий gcc, допускающему больше вольностей в объявлениях и преобразованиях типов, и не хотят поэтому переходить на новый gcc. В общем, я даже не знаю, что там на самом деле. У тебя, Evg, какие-то мысли есть по этому поводу?

Добавлено через 3 часа 52 минуты
Да, по поводу этих встроенных функций с проверкой переполнения... Посмотрел сейчас, есть они в документации на gcc 6.2.0.
Вот они:
http://gcc.gnu.org/onlinedocs/... eddest=538 .

Добавлено через 4 минуты
Ну и собственно ответ на мой вопрос, используют ли они возможности аппаратуры процессора для фиксации переполнения или всё делают чисто программным путём.

The compiler will attempt to use hardware instructions to implement these built-in functions where possible, like conditional jump on overflow after addition, conditional jump on carry etc.

Т. е. всё, как ты мне и написал.
0
Evg
Эксперт CАвтор FAQ
21139 / 8155 / 628
Регистрация: 30.03.2009
Сообщений: 22,465
Записей в блоге: 30
22.11.2016, 19:47 19

Не по теме:

Цитата Сообщение от JohnyWalker Посмотреть сообщение
Т. е. они, похоже, появились только в пятой версии gcc
Странно, утром смотрел в документацию от 6-го и ничего не нашёл, а сейчас вижу, что есть. Видимо, при поиске ошибся



Цитата Сообщение от JohnyWalker Посмотреть сообщение
Я правильно понимаю, что для использования встроенных функций компилятора gcc (builtins), не нужно в исходник программы добавлять никаких заголовочников (файлов *.h)?
Да

Цитата Сообщение от JohnyWalker Посмотреть сообщение
Любопытно, почему разработчики дистрибутивов, будь то MinGW для Windows или даже последние дистрибутивы Linux, так упорно не хотят переходить на новые версии gcc
Ну вот собрали люди дистрибутив при помощи gcc-4.9.2, потратили кучу времени на его отладку. А теперь выходит gcc-4.9.3, в котором может быть ничего полезного-то и не было (например, исправили ошибки для какой-нибудь левой архитектуры или поправили документацию). А оно нужно ради этого весь этот процесс начинать по новой?

Если речь идёт о переходе с gcc-4 на gcc-5, то такой переход зачастую нетривиален. И не каждая софтина его переживёт. Очень часто при обновлении версии компилятора синтаксис делается более строгим. Т.е. в старых компиляторах допускалось то, что по стандарту должно вызывать ошибку (и при этом в реальности не было критичным), а на новой версии это запрещается. А в софт уже успело проникнуть. Новые версии выдают гораздо больше предупреждений, в результате чего не соберётся софт, в котором предупреждения рассматриваются как ошибки (опция -Werror). Да и зачем людям переходить на новую gcc, если им ни одной из новых свойств не нужно? В итоге при переходе кроме геморроя ничего не получат
1
199 / 86 / 9
Регистрация: 15.11.2010
Сообщений: 472
22.11.2016, 20:37  [ТС] 20
Цитата Сообщение от Evg Посмотреть сообщение
Ну вот собрали люди дистрибутив при помощи gcc-4.9.2, потратили кучу времени на его отладку. А теперь выходит gcc-4.9.3, в котором может быть ничего полезного-то и не было (например, исправили ошибки для какой-нибудь левой архитектуры или поправили документацию). А оно нужно ради этого весь этот процесс начинать по новой?

Если речь идёт о переходе с gcc-4 на gcc-5, то такой переход зачастую нетривиален. И не каждая софтина его переживёт. Очень часто при обновлении версии компилятора синтаксис делается более строгим. Т.е. в старых компиляторах допускалось то, что по стандарту должно вызывать ошибку (и при этом в реальности не было критичным), а на новой версии это запрещается. А в софт уже успело проникнуть. Новые версии выдают гораздо больше предупреждений, в результате чего не соберётся софт, в котором предупреждения рассматриваются как ошибки (опция -Werror). Да и зачем людям переходить на новую gcc, если им ни одной из новых свойств не нужно? В итоге при переходе кроме геморроя ничего не получат
Ну, в общем я что-то такое и предполагал. Я вот думаю, может, разработчики всех этих компиляторов, и gcc здесь не исключение, со строгостью синтаксиса перегибают палку. Ведь C изначально создавался как язык с не очень строгим синтаксисом. Простой удобный язык с уклоном в сторону машины с кучей вольностей в вопросе приведения типов (и немножко в вопросе объявлений). В этом смысле он прямая противоположность Паскалю. Зачем его уродовать всеми этими строгостями, сообщениями об ошибках со стороны компилятора, warning'ами и пр.? Какой смысл запрещать людям делать то, к чему они привыкли и что им нравится? Раз уж стандарт развивается в такую сторону (хотя какая от этого польза для C?), сделали бы дополнительную опцию компилятора, что-то вроде -strict или -strictstd, и компилятор с включённой этой опцией всё бы запрещал. А без неё бы всё разрешалось, как и прежде. В результате огромное сообщество не самых худших и не самых глупых программистов работает над этим gcc, делает огромную работу, а люди этим пользоваться не хотят. И не пользуются... Уже вышла шестая версия gcc, а основная масса программистов из мира свободного софта сидит на последних версиях четвёртого. Я догадывался, что эти ограничивающие нововведения стандарта вызывают больше проблем. Но это так, мысли вслух...

Добавлено через 16 минут
У меня такой ещё вопрос по сути.

Можно ли в gcc сделать кросскомпиляцию? Допустим, у меня рабочая платформа x86 или x86_64. Могу ли я при этом получить на выходе компилятора код под SPARC, который на моей машине, естественно, не запустится, но будет вполне работоспособен и будучи скопирован на компьютер с процессором SPARC прекрасно на нём заработает? При этом хотелось бы иметь возможность получать и ассемблерный листинг (с помощью ключа -S), и объектный файл (т. е. файл с расширением .o), и окончательный загрузочный исполняемый модуль. Можно ли это сделать с помощью gcc, идущем в обычном дистрибутиве Linux, не устанавливая никаких дополнительных пакетов, просто указав компилятору в командной строке какую-то опцию? Или всё это несложно сделать, но нужно устанавливать дополнительные специальные пакеты из дистрибутива, позволяющие такую кросскомпиляцию выполнять? Или это всё, если и возможно, то очень сложно, — нужно каким-то нетривиальным образом скачивать и устанавливать дополнительное ПО, а потом его хитрым и сложным образом настраивать? В общем, могу я на своём Intel'е, имея дистрибутив Debian, легко и просто компилировать программы под SPARC? Или это всё, если и возможно, то очень сложно?
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
22.11.2016, 20:37

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

Написать программу калькулятор, выполняющую арифметические действия над целыми и вещественными числами
Напишите программу «Калькулятор», выполняющую арифметические действия над целыми и вещественными...

Арифметические операции над двумя числами
Требуется вывести на экран два произвольных числа, и произвести с их помощью все возможные...

Арифметические операции над числами с плавающей запятой
Помогите, пожалуйста, нужно сделать на Паскале Заранее Спасибо!!!

Длинная арифметика: арифметические операции над числами
Срочно нужны исходники (функции): 1. Перевод обычного числа в длинное (массив, строка , вектор кто...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.