bmstu-iu9 / bmstu-iu9/refal-5-lambda
Обобщающая функция gen__
- Dominant language
- C++
- Stars
- 97
- Forks
- 40
- PR merge metrics
- No merged PRs in 30d
Description
Мотивация
========
Компилятор выполняет лишние специализации по аккумуляторам. Достаточно много примеров описано в #319 (смотреть в свёрнутых комментариях). Там же (https://github.com/bmstu-iu9/refal-5-lambda/issues/319#issuecomment-727816888, комментарий свёрнут) предложено оборачивать выражения в вызов функции, который не должен оптимизироваться.
Предложено было два варианта: «костыльный» средствами самого языка и расширение компилятора. Костыльный вариант уже реализован и используется в компиляторе:
* 399a6a037cc062ccf3ea1fc6d1ce9aad469cca62
* b24582ea43931634c5f22db3f06c272095f31b3a
Код получен копипастом. Определять entry-функцию в одном из файлов и импортировать в другом некрасиво — возникает странная связь, а создавать новый файл для костыля ИМХО избыточно.
Надо сделать не костыльно. Хотя, сама идея функции `gen__` может рассматриваться как костыль…
Что сделать
========
Нужно реализовать поддержку в компиляторе функции `gen__`, вызов которой обобщается до ближайшей переменной (или пустоты, если аргумент пустой). Т.е. специализатор при анализе результатного выражения этот вызов может обобщить не до `e.Call`, а до `t.Call` или `s.Call`. Когда прогонщик будет корректно обрабатывать функции с активными аргументами (#230), он аналогично должен интерпретировать `gen__`. При этом, в идеале он должен считать этот вызов пассивным, если аргумент `gen__` пассивный, т.е. разрешать его переупорядочивать, дублировать или стирать.
Имя функции `gen__` выбрано по аналогии с именами особых функций для SCP4: `Const__`, `UnConst__` и др.
Функция `gen__` не встроенная, она должна быть определена пользователем как тождественная локальная функция вида
```Refal5
gen__ { e.X = e.X }
```
Если функция `gen__` определена как-то иначе (entry, drive, inline, spec или с другим телом), должно выдаваться предупреждение и такая функция не должна оптимизироваться. Впрочем, на директивы `$DRIVE gen__;`, `$INLINE gen__;`, `$SPEC gen__;` лучше выдавать ошибки — проще будет на последующих стадиях анализа. Обоснование: функция `gen__` может встречаться и в исходниках на классическом Рефале-5. Даже если она «неправильная», программа должна компилироваться и работать. Директивы `$DRIVE`, `$INLINE` и `$SPEC` есть только в Рефале-5λ, поэтому на них можно накладывать жёсткие семантические ограничения.
Детали реализации
----------------------
Можно эту функцию распознавать на стадии синтаксического анализа и заменять на
```Refal5
gen__ { e.X = <$gen e.X> }
```
Тогда при прогонке она заменится на некоторую встроенную функцию `$gen`, которая распознаётся оптимизатором и реализует требуемое поведение.
Но это плохая идея — функция `gen__` должна работать и при специализации без прогонки.
Просто распознавать имя `gen__` прогонщиком и специализатором нельзя — нет гарантии, что она определена тождественной. Можно искать её тело при подготовке дерева к специализации и каким-то образом факт её наличия запоминать в промежуточной структуре данных `(DriveInfo e._)` или `(SpecInfo e._)`. Но тоже некрасиво, усложняется внутренняя структура данных.
Поэтому есть предложение сделать отдельный проход, распознающий наличие правильной функции `gen__` (тождественная и локальная) и заменяющий её вызовы на `<$gen …>`, которую уже заведомо знают оптимизаторы. Проход может выполняться во время древесной оптимизации до неё или даже во время рассахаривания. Также нужен будет симметричный проход в конце, заменяющий `<$gen …>` на тождественную функцию.
Ситуация осложняется тем, что у нас есть режим глобальной оптимизации: функций `gen__` может быть много и они будут иметь суффиксы `gen__~N`. Такие имена тоже нужно будет распознавать.
Частичное решение
-----------------------
На данном этапе пока достаточно обобщать вызовы до e-переменных, с чем прекрасно справляется специализатор сам. И обобщать их достаточно только в специализаторе.
Поэтому достаточно для корректной работы просто не прогонять эту функцию. Явно назначить ей метку `$DRIVE` и `$INLINE` нельзя (должна быть синтаксическая ошибка, см. выше), а неявно ей не должна назначать метку авторазметка. Впрочем, компилятор может специализировать её в `gen__@N`, но это не страшно — всё равно произойдёт обобщение до e-переменной. А дополнительный проход прогонки экземпляров эти вызовы успешно уберёт с их накладными расходами.
Частичное решение предлагается в первую очередь взамен костылей (399a6a037cc062ccf3ea1fc6d1ce9aad469cca62, b24582ea43931634c5f22db3f06c272095f31b3a).
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.