Информация об изменениях

Сообщение Re: Кастомные прекомпиляторы от 24.11.2018 3:37

Изменено 24.11.2018 3:38 Evgeny.Panasyuk

Re: Кастомные прекомпиляторы
Здравствуйте, Khimik, Вы писали:

K>Интересно, не пробует ли кто-то из авторов ЯП делать кастомные прекомпиляторы, которые может написать программист-юзер?

K>Я имею в виду следующее (на примере Delphi). Предположим, я пишу библиотеку или exe-файл, которому на вход подаётся Delphi-юнит (паскалевский код), и моя программа его немного модифицирует. Среда разработки показывает в двух вкладках два кода: исходный юнит и юнит, модифицированный моим прекомпилятором. При запуске программы компилируется второй код, и естественно отладчик имеет дело с ним.
K>Вот пример. Есть простой приём оптимизации циклов – размножение. Пусть у меня есть код:

K>
K>qfor6 i:= 0 to count-1 do
K>  values[i] := values[i]* values[i];
K>


Если брать конкретно этот пример, то unroll'инг без проблем реализуется без макросов через функции высших порядков:
transform(values, begin(values), [](const auto &x)
{
    return x*x;
});

Причём под капотом transform может делать не только unroll, но и например разбивку на множество потоков.
На C++, такая абстракция в виде ФВП будет бесплатной (при включённой оптимизации) — то есть результат будет идентичен ручной раскрутке.

Если же в общем, то как упомянули выше — в некоторых языках есть встроенные синтаксические макросы.

Но ты, как я понимаю, спрашиваешь про внешние к языку преобразования. Тут могут быть разные варианты, в зависимости от степени интеграции с языком.
При слабой интеграции — будет примитивное манипулирование строчками кода — обычный внешний препроцессор.
Примером более сильной интеграции является Clang ASTMatchers + Rewriter: мы описываем паттерн синтаксического дерева кода который нас интересует, получаем callback при нахождении соответствующего паттерна, и переделываем синтаксическое дерево как нам необходимо:
https://www.youtube.com/watch?v=mVbDzTM21BQ
https://github.com/eliben/llvm-clang-samples/blob/master/src_clang/matchers_rewriter.cpp

K>(По ходу вопрос – насколько можно ещё оптимизировать этот код, или это уже предел?)


Зависит от того что у тебя за типы значений, и в целом что за программа.
Если это линейная алгебра, то имеет смысл использовать более высокие абстрации типа векторов и матриц, и оперировать непосредственно ими, а не педалить каждый цикл вручную.
Нормальные библиотеки (например Eigen) умеют оптимизировать линейную алгебру на уровне деревьев выражений. Например выражение вида:
vector_a = 5.0*vector_b + vector_c + vector_d + 3.0*vector_e;

будет вычислено одним циклом (плюс векторизованно и параллелизованно, или вовсе через gppgu).
Re: Кастомные прекомпиляторы
Здравствуйте, Khimik, Вы писали:

K>Интересно, не пробует ли кто-то из авторов ЯП делать кастомные прекомпиляторы, которые может написать программист-юзер?

K>Я имею в виду следующее (на примере Delphi). Предположим, я пишу библиотеку или exe-файл, которому на вход подаётся Delphi-юнит (паскалевский код), и моя программа его немного модифицирует. Среда разработки показывает в двух вкладках два кода: исходный юнит и юнит, модифицированный моим прекомпилятором. При запуске программы компилируется второй код, и естественно отладчик имеет дело с ним.
K>Вот пример. Есть простой приём оптимизации циклов – размножение. Пусть у меня есть код:

K>
K>qfor6 i:= 0 to count-1 do
K>  values[i] := values[i]* values[i];
K>


Если брать конкретно этот пример, то unroll'инг без проблем реализуется без макросов через функции высших порядков:
transform(values, begin(values), [](const auto &x)
{
    return x*x;
});

Причём под капотом transform может делать не только unroll, но и например разбивку на множество потоков.
На C++, такая абстракция в виде ФВП будет бесплатной (при включённой оптимизации) — то есть результат будет идентичен ручной раскрутке.

Если же в общем, то как упомянули выше — в некоторых языках есть встроенные синтаксические макросы.

Но ты, как я понимаю, спрашиваешь про внешние к коду преобразования. Тут могут быть разные варианты, в зависимости от степени интеграции с языком.
При слабой интеграции — будет примитивное манипулирование строчками кода — обычный внешний препроцессор.
Примером более сильной интеграции является Clang ASTMatchers + Rewriter: мы описываем паттерн синтаксического дерева кода который нас интересует, получаем callback при нахождении соответствующего паттерна, и переделываем синтаксическое дерево как нам необходимо:
https://www.youtube.com/watch?v=mVbDzTM21BQ
https://github.com/eliben/llvm-clang-samples/blob/master/src_clang/matchers_rewriter.cpp

K>(По ходу вопрос – насколько можно ещё оптимизировать этот код, или это уже предел?)


Зависит от того что у тебя за типы значений, и в целом что за программа.
Если это линейная алгебра, то имеет смысл использовать более высокие абстрации типа векторов и матриц, и оперировать непосредственно ими, а не педалить каждый цикл вручную.
Нормальные библиотеки (например Eigen) умеют оптимизировать линейную алгебру на уровне деревьев выражений. Например выражение вида:
vector_a = 5.0*vector_b + vector_c + vector_d + 3.0*vector_e;

будет вычислено одним циклом (плюс векторизованно и параллелизованно, или вовсе через gppgu).