Не подскажите как компиляторы фиксят проблему неудобного распределения регистров?
я просто не распределяю регистр eax и когда получается к примеру mov m32,m32 то добавляю
mov eax,m32
mov m32,eax
кстати довольно много приходится писать ...
а есть ли способ получше?
VVV>Не подскажите как компиляторы фиксят проблему неудобного распределения регистров?
Что значит — неудобное распределение?
Алгоритм сделал еще Андрей Петрович Ершов в начале 60-х.
С помощью алгоритма раскраски графа.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
VVV>>Не подскажите как компиляторы фиксят проблему неудобного распределения регистров? LVV>Что значит — неудобное распределение? LVV>Алгоритм сделал еще Андрей Петрович Ершов в начале 60-х. LVV>С помощью алгоритма раскраски графа.
теперь понятно почему он такой неюзабельный...
когда регистров мало то сможешь генерировать команду например add [edi-4],[edi-12] и не cассимилировать её
неужели Ершов как-то это учёл?
как?
Здравствуйте, VVVa, Вы писали:
VVV>Не подскажите как компиляторы фиксят проблему неудобного распределения регистров? VVV>я просто не распределяю регистр eax и когда получается к примеру mov m32,m32 то добавляю VVV>mov eax,m32 VVV>mov m32,eax VVV>кстати довольно много приходится писать ... VVV>а есть ли способ получше?
Ну ты спросил... (c)
Вообще непонятно, о чём конкретно вопрос, поэтому отвечу вширь (и интересно, что ещё скажут).
1. Если про оптимизацию использования — чем больше регистров применено и чем меньше перегонки через память, то это одна из сложнейших проблем, и в полном виде она NP-полная.
На практике используется целая толпа алгоритмов, которые дают более-менее внятный локальный оптимум.
Компиляторы с SSA определяют наиболее часто используемые значения в пределах блоков и циклов и держат их в регистрах, пытаясь забить доступный регистровый пул по максимуму. Без SSA используются более хитрые костыли, которые по сути сводятся к тому же. https://en.wikipedia.org/wiki/Register_allocation https://www.geeksforgeeks.org/register-allocation-algorithms-in-compiler-design/
и так далее.
Но для ручного ассемблирования можно применить похожие методы просто вручную, насколько хватит сил — найти самые ходовые значения и их держать в регистрах.
2. Если про специфику конкретных архитектур, то тут сплошные эмпирики, которые нарабатываются годами под конкретные железяки.
Вон писали, что MSVC (до SSA?) старался использовать CX (ECX, RCX...) только как временный или для его специфичных команд (сдвиги).
Наоборот, максимально используя AX можно применять более простые или короткие команды.
Но как правило это сводится к ограничениям (constraintʼам) в обобщённом алгоритме аллокации регистров (ну типа "вот тут обязательно нужен RDI или RSI, выгибайтесь, ребята, как хотите"), а уже он максимально старается применить доступную свободу.
3. Можно скрыть проблему используя макры для 90-95% кода пойдёт, а там, где самые горячие места, открыть их и рассчитать всё вручную...
Здравствуйте, LaptevVV, Вы писали:
VVV>>Не подскажите как компиляторы фиксят проблему неудобного распределения регистров? LVV>Что значит — неудобное распределение? LVV>Алгоритм сделал еще Андрей Петрович Ершов в начале 60-х. LVV>С помощью алгоритма раскраски графа.
Здравствуйте, VVVa, Вы писали:
LVV>>Алгоритм сделал еще Андрей Петрович Ершов в начале 60-х. LVV>>С помощью алгоритма раскраски графа. VVV>теперь понятно почему он такой неюзабельный...
Интересно, сколько преподавателей exUSSR читают хотя бы журналы ACM?
VVV>когда регистров мало то сможешь генерировать команду например add [edi-4],[edi-12] и не cассимилировать её
Эээ
Я не понял, что значит "сассимилировать", но на x86 нет команд с поддержкой операций память-память в этой группе.
Или `add регистр,[edi-12]` или `add [edi-4],регистр`...
VVV>неужели Ершов как-то это учёл? VVV> как?
Проблема тут в том, что ты подымаешь тему, которой занимаются ну навскидку до 100 человек на весь мир, из которых больше половины сидят в командах GCC, LLVM, Java JIT и тому подобного, а для вхождения в тему посерьёзнее чем на уровне Ершова нужно пару лет плотного раздумья. Все остальные скажут в духе "вызывай LLVM и не морочь голову".
Так что не думаю, что тебе тут что-то ещё расскажут так чтобы сразу понять.
Здравствуйте, VVVa, Вы писали:
VVV>кстати довольно много приходится писать ...
Ну вручную заниматься распределением регистров довольно неблагодарное занятие. Как тут уже писалось, задача Register Allocation это NP-полная задача.
Есть два популярных алгоритма регалока: Linear Scan и Graph Coloring. Первый прост в реализации и быстрее в работе, но второй более эффективен.
Для копирования из памяти в память в любом случае нужен регистр. В твоем случае ты под это выделил отдельный scratch регистр,
но тогда он изымается из свободных регистров, соответственно давление на регистры увеличивается, становится больше спиллов(освобождение регистров через их сохранение в память).
Я бы посоветовал генерировать сначала LLVM IR файл и потом скармливать его LLVM llc тулзе для генерации машинного кода.
Здравствуйте, LaptevVV, Вы писали:
LVV>Алгоритм сделал еще Андрей Петрович Ершов в начале 60-х. LVV>С помощью алгоритма раскраски графа.
И как в этом алгоритме решается проблема функциональной не равноценности регистров (в x86)
Вопрос риторический, объяснения разумеется не нужно, просто примечание на тему расстояния теории от практики.
LVV>>Алгоритм сделал еще Андрей Петрович Ершов в начале 60-х. LVV>>С помощью алгоритма раскраски графа. _>И как в этом алгоритме решается проблема функциональной не равноценности регистров (в x86) _>Вопрос риторический, объяснения разумеется не нужно, просто примечание на тему расстояния теории от практики.
Тогда все регистры были равноправные...
И мысли не было о том, что какие-то регистры ОБЩЕГО назначения могут быть не общего назначения...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
LVV>>>Алгоритм сделал еще Андрей Петрович Ершов в начале 60-х. LVV>>>С помощью алгоритма раскраски графа. _>>И как в этом алгоритме решается проблема функциональной не равноценности регистров (в x86) _>>Вопрос риторический, объяснения разумеется не нужно, просто примечание на тему расстояния теории от практики. LVV>Тогда все регистры были равноправные... LVV>И мысли не было о том, что какие-то регистры ОБЩЕГО назначения могут быть не общего назначения...
Назовите хотя бы две архитектуры (начала 60-х, да?), пожалуйста, в которых действительно _все_ регистры (даже у уточнением "общего назначения") были равноправные. (И регистров должно быть минимум 3. Нет, я верю про БЭСМ-6 с 15 индексными регистрами, на них можно было играться (и одним аккумулятором).)
Только проверьте свои утверждения, наверняка много интересного узнаете
А то я таких не помню в принципе. Можно вспомнить PDP-11 с R0..R5, но это уже 1970 и позже.
LVV>>Тогда все регистры были равноправные... LVV>>И мысли не было о том, что какие-то регистры ОБЩЕГО назначения могут быть не общего назначения... N>Назовите хотя бы две архитектуры (начала 60-х, да?), пожалуйста, в которых действительно _все_ регистры (даже у уточнением "общего назначения") были равноправные. (И регистров должно быть минимум 3. Нет, я верю про БЭСМ-6 с 15 индексными регистрами, на них можно было играться (и одним аккумулятором).)
Про БЭСМ-6 ты сам сказал. Там не было регистров ОБЩЕГО назначения — только сумматор
Архитектуру БЭСМ-6 я изучал достаточно глубоко, так как писал диплом на автокоде БЭМШ...
М-220 и Минск-22, на которых я тоже работал, не имели регистров ОБЩЕГО назначения...
На Уралах я не работал, поэтому ничего сказать не могу.
Это в гражданке.
Скорее всего военка имела более продвинутые архитектуры и там регистры общего назначения были N>Только проверьте свои утверждения, наверняка много интересного узнаете N>А то я таких не помню в принципе. Можно вспомнить PDP-11 с R0..R5, но это уже 1970 и позже.
А, ты зацепился за слово в равноправные...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
LVV>А, ты зацепился за слово в равноправные...
Именно. Как раз с этим проблема в то время была считай везде.
ARM (обе разрядности, но не thumb), MIPS (базовый как минимум), RISC-V (без сжатых команд), POWER, Alpha — где-то приближение к этому, если исключить пустые регистры, адрес возврата и всё такое. Вот на этих RISCʼах ещё и простые алгоритмы работали хорошо.
И то — не на всех RISC. SPARC, например, сюда не относится, со своей схемой окон.
Неожиданно, CISC как PDP-11 или VAX. Но не родственный им M68000 со своим делением A/D.
X86 аж никак. Он как тот верблюд — "а что у меня прямое?"
Потому и получалось, что эффективные для нынешней обстановки алгоритмы стали пригодными только когда их более-менее научили поддержке ограничений архитектур.
А это уже ближе к 90-м (а учитывая инерцию реализации — и до 2000-х).
Но это вошло в "пакет" тех достижений, после которых новые CISCи не проектируют.
Здравствуйте, ути-пути, Вы писали:
N>>А то я таких не помню в принципе. Можно вспомнить PDP-11 с R0..R5, но это уже 1970 и позже.
УП>ЕМНИП, с R6 и R7 можно было все те же операции делать, что и с этими, учитывая, конечно, их побочки.
R7 = PC
как бы побочки заслоняют собой всё остальное
У SP даже если не использовать его как стек были особенности — например, (R6)+ шагало по 2 байта, а не 1, даже в байтовых командах.