Skip to content

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

@Mazdaywik

Description

@Mazdaywik

Мотивация

Компилятор выполняет лишние специализации по аккумуляторам. Достаточно много примеров описано в #319 (смотреть в свёрнутых комментариях). Там же (#319 (comment), комментарий свёрнут) предложено оборачивать выражения в вызов функции, который не должен оптимизироваться.

Предложено было два варианта: «костыльный» средствами самого языка и расширение компилятора. Костыльный вариант уже реализован и используется в компиляторе:

Код получен копипастом. Определять entry-функцию в одном из файлов и импортировать в другом некрасиво — возникает странная связь, а создавать новый файл для костыля ИМХО избыточно.

Надо сделать не костыльно. Хотя, сама идея функции gen__ может рассматриваться как костыль…

Что сделать

Нужно реализовать поддержку в компиляторе функции gen__, вызов которой обобщается до ближайшей переменной (или пустоты, если аргумент пустой). Т.е. специализатор при анализе результатного выражения этот вызов может обобщить не до e.Call, а до t.Call или s.Call. Когда прогонщик будет корректно обрабатывать функции с активными аргументами (#230), он аналогично должен интерпретировать gen__. При этом, в идеале он должен считать этот вызов пассивным, если аргумент gen__ пассивный, т.е. разрешать его переупорядочивать, дублировать или стирать.

Имя функции gen__ выбрано по аналогии с именами особых функций для SCP4: Const__, UnConst__ и др.

Функция gen__ не встроенная, она должна быть определена пользователем как тождественная локальная функция вида

gen__ { e.X = e.X }

Если функция gen__ определена как-то иначе (entry, drive, inline, spec или с другим телом), должно выдаваться предупреждение и такая функция не должна оптимизироваться. Впрочем, на директивы $DRIVE gen__;, $INLINE gen__;, $SPEC gen__; лучше выдавать ошибки — проще будет на последующих стадиях анализа. Обоснование: функция gen__ может встречаться и в исходниках на классическом Рефале-5. Даже если она «неправильная», программа должна компилироваться и работать. Директивы $DRIVE, $INLINE и $SPEC есть только в Рефале-5λ, поэтому на них можно накладывать жёсткие семантические ограничения.

Детали реализации

Можно эту функцию распознавать на стадии синтаксического анализа и заменять на

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-переменной. А дополнительный проход прогонки экземпляров эти вызовы успешно уберёт с их накладными расходами.

Частичное решение предлагается в первую очередь взамен костылей (399a6a0, b24582e).

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions