bmstu-iu9 / bmstu-iu9/refal-5-lambda

Обобщающая функция gen__

Open
#331 2 comments 0 reactions 1 assignee Claimed by @Mazdaywik View on GitHub
task
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.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.