и кстати. fastcall помогает. не очень сильно, но помогает. во-первых, я разрешил моему внутреннему fastcall-у использовать три регистра для параметров. во-вторых, по возможности компилятор прозрачно процедуры до него апгрейдит. в итоге 200-250 мсек на «эксперименте» срезало. мелочь, но всё равно приятно. если сделать два регистра — будет 150-180, так что это действительно роялит.
также мой Nanojit умеет не только занулять стек на старте, но и не занулять, если ни одного обращения к локалам не было. и не выравнивать, если не было `LIR_call`. в итоге простенькие функции-ванлайнеры часто всё делают в регистрах. и просто просятся в инлайн, конечно.
я потихоньку конвертирую `ensureAddressable()` во вторичный резолвер. идея такая, что `resolveExpr()` проставляет типы и всё остальное, оптимайзит, всё вот это. и возвращает ноду типа `NodeVar`. которая на самом деле может быть `NodeLocVar`, `NodeArgVar`, и ещё кучка специальных. а потом `ensureAddressable()` в той же `NodeArgVar` может вернуть `NodeLocVar`, если у нас есть теневая копия.
хотя, наверное, копии можно было сделать и иначе: просто заменить в списке локалов ноды-аргументы на ноды-теневые-копии. `WITH`, например, именно такую (временную) замену и делает. это, кстати, решает проблему, когда внутри `WITH` тип аргумента процедуры (который мы в `WITH` использовали) меняется — и меняется вся сигнатура от этого. не меняется. никогда.
и это. EMPTY RECORD как замена енумов оказалась довольно удобной штукой. включая значение `NIL`, которое "default/don't care". в игре, например:
Код:
TYPE
(* game phases *)
Phase = EMPTY EXTENSIBLE RECORD;
PhaseIntro = EMPTY RECORD (Phase);
PhaseMainMenu = EMPTY RECORD (Phase);
PhaseBriefing = EMPTY RECORD (Phase);
PhaseShop = EMPTY RECORD (Phase);
PhaseInMission = EMPTY RECORD (Phase);
PhaseMissionFailed = EMPTY RECORD (PhaseInMission);
PhaseMissionCompleted = EMPTY RECORD (PhaseInMission);
PhasePostMission = EMPTY RECORD (Phase);
PhasePostMissionFail = EMPTY RECORD (PhasePostMission);
PhasePostMissionSuccess = EMPTY RECORD (PhasePostMission);
PhaseSaveLoad = EMPTY RECORD (Phase);
и я забыл сделать `EMPTY ABSTRACT RECORD`, да. и `Phase`, и `PhasePostMission` должны быть абстрактными.