OberonCore https://forum.oberoncore.ru/ |
|
Oberon/Ur https://forum.oberoncore.ru/viewtopic.php?f=61&t=6983 |
Страница 1 из 17 |
Автор: | arisu [ Суббота, 29 Июнь, 2024 15:11 ] |
Заголовок сообщения: | Oberon/Ur |
для тестирования приватного форка Nanojit понадобилось сделать к нему какой-то язык. и я подумал: а почему бы этому языку не быть обероном? на проект пока потрачено три дня, сейчас может скомпилировать и запустить примерно такое: Код: MODULE n0test_00; IMPORT Log; TYPE INT = INTEGER; MyRec = RECORD a: INT; b: REAL; END; VAR a0: INT; r0: MyRec; BEGIN r0.a := 666_69; r0.b := 666.999; Log.String("HI"+"!"); Log.Ln; Log.String("r0.a="); Log.Int(r0.a); Log.Ln; Log.String("r0.b="); Log.Real(r0.b); Log.Ln; a0 := 69; Log.String("a0="); Log.Int(a0); Log.Ln; Log.Real(66.9); Log.Ln; Log.String("a0(real)="); Log.Real(a0); Log.Ln; Log.Real(6.69); Log.Ln; Log.Int(660 + 9); (*Log.Int("BOO!");*) Log.Ln; Log.Int(29AH); Log.Ln; Log.Int(16%29A); Log.Ln(); Log.Int($29A); Log.Ln(); END n0test_00. на самом деле это сильно больше чем может показаться: почти полный компилятор. вся внутренняя механика типов, переменных, процедур (они есть, их только объявлять пока нельзя ;-), модулей — на месте. компилятор многопроходный: source → ast → ast-materialized → lir → native code. теоретически Nanojit поддерживает x86, x86_64 и arm (32), но практически мне весь этот зоопарк тупо нечем собирать. под шинду и 32-бит x86 пинус, однако, собирается. и даже работает. это так, early announce. доведение до полноценной реализации (с Kernel, написаном на самом NanoOberon) возможно, но не гарантируется. исходные тексты компилятора я, может, выложу в итоге. правда, они во-первых, на крестах, а во-вторых, совершенно бесполезны без моего форка Nanojit, который выложен не будет. но чисто посмотреть — почему бы и да. с Nanojit есть некоторые проблемы (он в целом не особо предназначен для подобного рода издевательств), но тем не менее держится вполне неплохо. дополнительное SSA-представление я не делал как раз затем, чтобы посмотреть, на что способен Nanojit при вот таком тупом использовании «в лоб». а. если вдруг из текста не очень ясно. NanoOberon не умеет делать бинарники, и уметь не будет. только взлетать с нуля из исходных текстов на обероне. ну, сам компилятор — бинарник, на крестах (потому что Nanojit на крестах), а остальное всё из обероновских исходников на лету. я бы и компилятор на обероне сделал, но тогда взлетать нечем. ;-) |
Автор: | arisu [ Суббота, 29 Июнь, 2024 22:06 ] |
Заголовок сообщения: | Re: NanoOberon/OberonJIT |
ещё скажу, что на «построение компиляторов» я забил большой и тяжёлый; внутри компилятор состоит из огромной кучи специализированых AST-нод. причём на первом этапе текст парзится в ноды типа `NodeId`, `NodeDot`, без уточнений. и только когда всё отпарзилось — по всему дереву запускается `Node.resolve()`. резолвер возвращает новую ноду (или самого себя, если так подходит). те же `NodeId` превращаются в `NodeGlobalVar` или `NodeLocalVar`, точечки — в `NodeField`, и так далее. и на третьем этапе у нас уже гарантировано валидное дерево, где у каждой ноды указан правильный тип, так что спокойно делаем `Node.emitLIR()`. конечно, это значительно медленней, чем простой однопроходный компилятор. зато независимые части чётко отделены друг от дружки, и в том же парзере не путается под ногами код для построения и проверки таблиц символов, например. равно как и `emitLIR()` никакими символами уже не интересуется: там все адреса и смещения уже решены. `emitLIR()` тут легко заменяется на что угодно другое, хоть на `emitSSA()` (SSA потом, правда, придётся канонизировать, но это мелочи). и некоторые оптимизации можно делать прямо по дереву (хоть и не очень удобно). собственно, и CP2 надо было бы переписать таким образом, но: «работает — не трогай!» одно из достоинств/недостатков подобного подхода — никакие forward declarations больше не нужны. я пока не решил, энфорсить правило «всё должно быть объявлено заранее» или нет. с одной стороны мне правило нравится, а с другой — это рудимент однопроходности же. |
Автор: | arisu [ Воскресенье, 30 Июнь, 2024 08:18 ] |
Заголовок сообщения: | Re: NanoOberon/OberonJIT |
я опять в тягостных раздумьях. по специфике компилятора получается забавное: вычислять константы и актуализировать типы можно лениво. но нужно ли? то есть: если у нас есть `CONST SomethingSomething = AnotherSomething * 69;`, а само `AnotherSomething` отсутствует — то компилятор вычислит константу только в момент её использования. а если нигде не используется — то и не станет, ему не надо. то же самое с `MyPtr = POINTER TO YetUnknownStruct`: если нигде переменная типа `MyPtr` не объявлена — то и `YetUnknownStruct` может не быть — кому не всё равно? чтобы этого избежать — надо предпринимать специальные меры. необходимость которых у меня под большим вопросом. с одной стороны — ну да: код типа должен быть корректным. а с другой — не всё ли равно, корректен ли код, который нигде никогда не используется? та же фигня, кстати, и с процедурами выходит: ежели процедура никем не вызывается и не экспортируется — то её и не резолвят. синтаксически она парзится, но вполне может не пройти проверку типов. если кто-то кроме роботов таки читает, то как думаете: делать лишние телодвижения, или ну его нафиг? в принципе, с учётом того, что язык вообще больше на скриптовый похож (ибо по сути напрямую выполняет обероновские исходники) — хрен бы с ним, с неисполняемым. а с другой стороны — попахивает. сделать опцию «проверяй всё» плохой вариант: это как раз проявление дурацкого «фичеризма» — когда автор не может сам решить, как надо делать, и сваливает решение на пользователя, отмазываясь «предоставлением выбора». это плохой, ненужный выбор. псевдовыбор. |
Автор: | Artyemov [ Воскресенье, 30 Июнь, 2024 20:48 ] |
Заголовок сообщения: | Re: NanoOberon/OberonJIT |
arisu писал(а): ... как думаете: делать лишние телодвижения, или ну его нафиг?... "Никаких поцелуев!!! Мочии-и-и!!!" (C) CelebrityDeathMatch, MTV |
Автор: | arisu [ Воскресенье, 30 Июнь, 2024 23:35 ] |
Заголовок сообщения: | Re: NanoOberon/OberonJIT |
ну, я в итоге да: сделал ленивое, потому что так проще. сайд-эффект: Код: CONST Love = Base + 69; Hell = Base + 666; Base = 10000; конечно, работает. и процедуры компилируются строго те, которые используются. и типы. да, уже можно объявить процедуру, и даже её вызвать. а теперь всё это надо переделывать, потому что Nanojit поддерживает максимум восемь аргументов. минус один на потенциальный `self`, минус один на непрямой вызов (потому что так там сделано: если надо непрямой вызов, то адрес передаётся последним аргументом). осталось шесть. маловато будет! один открытый массив два съедает. придётся делать логику заворачивания в скрытую структуру на стеке. собственно, avm+ и tamarin так и делали. в принципе — этот контекст всяко полезен, потому что он и для вложеных процедур нужен. вот сижу и думаю: если сделать полноценную поддержку Component Pascal — можно BBCB из исходников при старте поднимать. совершенно бесполезно, жутко неэффективно, но забавно. только LONGINT придётся даблом эмулить, с ограничением на 51 бит. делать такое, конечно, лень, но. на всякий случай напомню, что я всё ещё обкатываю Nanojit, а не просто пилю очередной бесполезный компилятор оберона. ;-) |
Автор: | arisu [ Вторник, 02 Июль, 2024 00:22 ] |
Заголовок сообщения: | Re: NanoOberon/OberonJIT |
запилил процедуры, локальные переменные, рекурсию, `IF` и `WHILE`. с рекурсией не всё так просто: у Nanojit нет инструкции: «вызови то, не знаю что, потом пропатчим». адрес вызова должен быть известен на момент компиляции инструкции. так что рекурсия сделана через косвенные вызовы по указателю, который суют в область констант. компилятор достаточно умён чтобы делать это только когда надо, вне зависимости от порядка объявления процедур. также у Nanojit есть ещё один квирк: аргументы функций изменять нельзя. вообще. никак. нет таких инструкций. можно только читать. оно, конечно, красиво и правильно, но в обероне-то можно! пришлось сделать в компилере хак: если он обнаруживает присваивание аргументу, то генерит пролог с копированием оного аргумента в стековый локал, и потом при генерации кода прозрачно работает с этим локалом. ну, кривовато. зато it works. заодно бампнул максимальное количество аргументов в Nanojit с восьми до шестидесяти трёх. на самом деле самая большая проблема с этим в том, что нано паковал типы аргументов и результата в `uint32_t` — отсюда и ограничение на восемь. эту часть пришлось переделать на битовый массив. в общем, теперь умеем в вот такое: Код: MODULE n0test_00;
IMPORT Log; TYPE INT = INTEGER; MyRec = RECORD a: INT; b: FLOAT; r: RECORD d: INT; END END; MyRec1 = RECORD ival: INT; END; MyRec3Ptr = POINTER TO MyRec3; MyRec4Ptr = POINTER TO MyRec4; MyRec2 = RECORD r: MyRec1; a: INT; (*pp: MyRec3Ptr;*) b: FLOAT; END; MyRec3 = RECORD x: DOUBLE; y: MyRec4Ptr; END; CONST Love = Base + 69; Hell = Base + 666; Base = 10000; VAR a0: INT; r0: MyRec; r2: MyRec2; PROCEDURE Proc (arg: INTEGER); BEGIN Log.String("IN `Proc`: arg="):Int(arg):Ln; Proc1(arg + 3); END Proc; PROCEDURE Proc1 (a: INTEGER); BEGIN Log.String("IN `Proc1`: arg="):Int(a):Ln; IF a = 666 THEN Log.String("***HELL**"):Ln ELSIF a = 669 THEN Log.String("***LOVE**"):Ln END IF; END Proc1; PROCEDURE Recurse (a: INTEGER); BEGIN Log.String("R-ENTER: a="):Int(a):Ln; IF a > 0 THEN Recurse(a - 1) END IF; Log.String("R-EXIT: a="):Int(a):Ln; END Recurse; PROCEDURE ProcWhile (a: INT); VAR cnt: INT; BEGIN Log.String("ProcWhile: start: a="):Int(a):Ln; cnt := a; WHILE cnt # 0 DO Log.String(" PWW: cnt="):Int(cnt):Ln; (*a := a - 1;*) DEC(cnt); END WHILE; Log.String("ProcWhile: end: a="):Int(a):Ln; END ProcWhile; PROCEDURE ProcWhile1 (a: INT); BEGIN Log.String("ProcWhile1: start: a="):Int(a):Ln; WHILE a # 0 DO Log.String(" PWW: a="):Int(a):Ln; (*a := a - 1;*) DEC(a); END WHILE; Log.String("ProcWhile1: end: a="):Int(a):Ln; END ProcWhile1; PROCEDURE ProcWhile2 (a: INT); BEGIN Log.String("ProcWhile2: start: a="):Int(a):Ln; WHILE a # 0 DO Log.String(" PWW: a="):Int(a):Ln; a := a - 1; END WHILE; Log.String("ProcWhile2: end: a="):Int(a):Ln; END ProcWhile2; BEGIN Log.String("HI"+"!"):Ln; r0.a := 666_69; r0.r.d := Love; r0.b := 666.999; Log.String("r0.a="):Int(r0.a):Ln; Log.String("r0.b="):Float(r0.b):Ln; Log.String("r0.r.d="):Int(r0.r.d):Ln; r2.a := 666_69; r2.b := 666.999; r2.r.ival := Hell; Log.String("r2.a="):Int(r2.a):Ln; Log.String("r2.b="):Float(r2.b):Ln; Log.String("r2.r.ival="):Int(r2.r.ival):Ln; a0 := 69; Log.String("a0="):Int(a0):Ln; Log.Float(66.9):Ln; Log.String("a0(real)="):Float(a0):Ln; Log.Float(6.69):Ln; Log.Int(660 + 9):Ln; Log.Int(29AH); Log.Ln; Log.Int(16%29A):Ln(); Log.Int($29A); Log.Ln(); Proc($290 + 10); Recurse(4); a0 := 3; WHILE a0 # 0 DO Log.String("W: a0="):Int(a0):Ln; (*a0 := a0 - 1;*) DEC(a0); END WHILE; ProcWhile(5); ProcWhile1(5); ProcWhile2(5); END n0test_00. |
Автор: | arisu [ Вторник, 02 Июль, 2024 01:08 ] |
Заголовок сообщения: | Re: NanoOberon/OberonJIT |
p.s.: компилятор, кстати, дубовый и адово рекурсивный. даже `IF/ELSIF` через рекурсию парзится. так проще, удобней, и меня вполне устраивает сегфолт, если стек закончился. алсо, тайпкасты будут. но через `CAST(typename)(expr)`. AO-шное `typename(expr)` мне не нравится: грепнуть все касты сложнее. ;-) и `LSH` не нравится. будет для легаси кода, но рядом будут и `SHL`, `SHR`, `SAR`. надо пилить массивы, открытые массивы, и аттачить ко всему type tag'и. тогда можно будет приступать к GC. p.p.s.: у Nanojit есть опкоды для арифметики с проверкой переполнения, кстати. использовать их, правда, не очень удобно. я пока не решил, нужна ли эта проверка вообще. пуристы мне скажут, что конечно нужна. это Правильно и Хорошо. на что я им отвечу, что оберон даже локалы не инитит, так что прен-цен-дент наплевательства есть. `INTEGER` — это прибитое гвоздями знаковое 32-битное целое, и на это можно полагаться в ручных проверках переполнения. и я вам скажу, что намного более чаще чем нет эти проверки не нужны. так что я склоняюсь к тому, чтобы их если и делать, то опциональными. не опцией компилятора, а встроеной функцией или новым оператором. как я уже где-то писал, надёжность оберона не в том, что он магически защищает программиста от алгоритмических ошибок программиста, а в том, что он не позволит сделать самые неприятные штуки — типа выхода за пределы массива и порубания хипа на лапшу. это всё ещё не освобождает от ручной проверки диапазонов, NIL и прочего. точно так же и переполнение интов надо проверять (если надо). в отличие от той же сишечки — переполнение индекса массива поймает range checker, например. ещё никак не могу решить, нужен ли мне дурацкий юникод по-умолчанию. склоняюсь к мысли, что нафиг не нужен, и CHAR следует делать восьмибитовым целым без знака. разбазаривать четыре байта на ерунду — это перебор. в два байта юникод давно не влазит. и все нормальные API всё равно заточены на utf-8. так что эксперимент с большими CHAR-ами я считаю провалившимся. надо — будет LONGCHAR. ах, да. FOR не будет. ну не нужно оно. и LOOP не будет: тоже не нужно. лучше попробую изобрести красивый синтаксис для итераторов Парнаса. WITH будет. и CASE будет как в CP, а не как в O7. и RETURN прибивать гвоздями не буду, скорее всего. это — опять таки — идеологически правильно, но я довольно часто пишу код типа: Код: PROCEDURE Smth; BEGIN IF wasDone THEN RETURN; END; <do-something> wasDone := TRUE; END Smth; нувыпонели. да, это криво с точки зрения Чистого Структурного. но лишний отступ, как по мне, читается намного хуже. также подумываю над тем, чтобы повысить точку с запятой до терминатора. она сейчас опциональна (как в CP), но камон. я считаю, что её «сепараторность» — тяжёлое наследие паскаля. там это имело смысл для `if smth then smth else smth;`. в оберонах это смысла не имеет, и навсегда закроет холивар «ставите ли вы точку с запятой после последнего statement-а?» а `TRUE` и `FALSE` повышены до ключевых слов. потому что тоже камон. |
Автор: | arisu [ Вторник, 02 Июль, 2024 02:22 ] |
Заголовок сообщения: | Re: NanoOberon/OberonJIT |
и чтобы тупо доказать, что Оно Живое: текущая рабочая версия, под шинду 32 бита. не стоит сильно стараться её поломать: у вас определённо получится. куча всего ещё не реализована. фактически, нормально работает только то, что в прилагаемом примере. ;-) |
Автор: | arisu [ Вторник, 02 Июль, 2024 06:41 ] |
Заголовок сообщения: | Re: NanoOberon/OberonJIT |
и о GC. я тут подумал, что можно обойтись без сканирования стека, запилив вместо этого полностью precise GC. на входе в процедуру с указателями создавать скрытый массивчик с указателями на все локалы, которые временные корни, и регистрировать этот массивчик. при выходе — дерегистрировать. тащемта, оверхэд — несколько mov да два быстрых call. ерунда. благо, у нас нет никаких дурацких исключений и `longjmp()`. а кто попробует — тот сам виноват. и ещё подумал, что имеет смысл добавить тип STRING — строка типа дельфийской: динамического размера, refcounted, cow. и удобно, и технику rc/cow с Nanojit обкатать можно. тем временем сделал short-circuit bools и функции (то есть, процедуры, которые что-то возвращают). |
Автор: | arisu [ Вторник, 02 Июль, 2024 06:47 ] |
Заголовок сообщения: | Re: NanoOberon/OberonJIT |
кстати, не очень понимаю, почему `&` и `OR` не имеют отдельного уровня приоритетов. это чисто чтобы заэнфорсить более читабельные условия, что ли? `IF (a # b) & (c # d)` vs `IF a # b & c # d`. ну… в принципе, да. ладно, пусть будет. а то знаю я этих погромистов: если по рукам не бить — то и будут писать портянки без скобочек. |
Автор: | arisu [ Вторник, 02 Июль, 2024 06:48 ] |
Заголовок сообщения: | Re: NanoOberon/OberonJIT |
а, блин! `SET` забыл впилить! |
Автор: | Alexander Shiryaev [ Вторник, 02 Июль, 2024 12:04 ] |
Заголовок сообщения: | Re: NanoOberon/OberonJIT |
arisu писал(а): также у Nanojit есть ещё один квирк: аргументы функций изменять нельзя. вообще. никак. нет таких инструкций. можно только читать. оно, конечно, красиво и правильно, но в обероне-то можно! пришлось сделать в компилере хак: если он обнаруживает присваивание аргументу, то генерит пролог с копированием оного аргумента в стековый локал, и потом при генерации кода прозрачно работает с этим локалом. ну, кривовато. зато it works. load/store? |
Автор: | Alexander Shiryaev [ Вторник, 02 Июль, 2024 13:10 ] |
Заголовок сообщения: | Re: NanoOberon/OberonJIT |
arisu писал(а): пуристы мне скажут, что конечно нужна. это Правильно и Хорошо. на что я им отвечу, что оберон даже локалы не инитит, так что прен-цен-дент наплевательства есть. `INTEGER` — это прибитое гвоздями знаковое 32-битное целое, и на это можно полагаться в ручных проверках переполнения. и я вам скажу, что намного более чаще чем нет эти проверки не нужны. так что я склоняюсь к тому, чтобы их если и делать, то опциональными. не опцией компилятора, а встроеной функцией или новым оператором. как я уже где-то писал, надёжность оберона не в том, что он магически защищает программиста от алгоритмических ошибок программиста, а в том, что он не позволит сделать самые неприятные штуки — типа выхода за пределы массива и порубания хипа на лапшу. это всё ещё не освобождает от ручной проверки диапазонов, NIL и прочего. точно так же и переполнение интов надо проверять (если надо). в отличие от той же сишечки — переполнение индекса массива поймает range checker, например. Хорошо то, что вот это компилируется: Код: MODULE M;
CONST C = 0E0000000H; VAR x: INTEGER; BEGIN x := C END M. |
Автор: | arisu [ Вторник, 02 Июль, 2024 18:44 ] |
Заголовок сообщения: | Re: NanoOberon/OberonJIT |
Alexander Shiryaev писал(а): load/store? э… не совсем понял вопрос. если про Nanojit — то там есть только инструкция «получить значение параметра», и всё. implicit load, то бишь. обратной отчего-то нет. а я пока не настолько хорошо понимаю код нано чтобы сказать: её нет потому что какая-то архитектурная закавыка, или просто автору не понадобилось.Alexander Shiryaev писал(а): Хорошо то, что вот это компилируется: я не очень понял, подколка ли это или нет. ;-) вообще, у меня переполнение не проверяется в том числе и парзером, и сворачивалкой констант (потому что это делается тем же `resolveExpr()` что и весь остальной код).Код: MODULE M; CONST C = 0E0000000H; VAR x: INTEGER; BEGIN x := C END M. впрочем, даже если я и добавлю эти проверки, то подобное всё равно будет разрешено. по той логике, что INTEGER — это 32-bit 2-complement signed. мы это знаем, компилятор это знает, CPU это знает — и нет смысла притворяться, что оно не так. соответственно, нет и смысла отвергать альтернативные формы записи этих битов. а в CP2 хексы вообще парзятся в LONGINT, без вариантов. диапазон проверяется только при присваивании, и — насколько помню — [MININT…MAXUINT]. как раз чтобы подобное работало. я б, может, тоже проверял, но в языке у меня лонгинтов нет в принципе, а в крестах нормально проверить переполнение нельзя. я, конечно, использую "-fwrapv", но городить проверки ручками мне лень. из свежих новостей: намедни впилил `&` и `OR`. и вспомнил, что забыл сделать VAR-аргументы. вот теперь сижу и думаю: то ли просто флагом обойтись, то ли завести полноценный тип `reference` (который как pointer, но не pointer). тип красивей, а флаг проще. |
Автор: | arisu [ Вторник, 02 Июль, 2024 18:53 ] |
Заголовок сообщения: | Re: NanoOberon/OberonJIT |
и если кому испугаться, то текущие исходники компилера. чисто для непрактического интересу. автор особо дизайном не утруждался: что выросло — то выросло. |
Автор: | Alexander Shiryaev [ Вторник, 02 Июль, 2024 19:09 ] |
Заголовок сообщения: | Re: NanoOberon/OberonJIT |
arisu писал(а): Alexander Shiryaev писал(а): load/store? э… не совсем понял вопрос. если про Nanojit — то там есть только инструкция «получить значение параметра», и всё. implicit load, то бишь. обратной отчего-то нет. а я пока не настолько хорошо понимаю код нано чтобы сказать: её нет потому что какая-то архитектурная закавыка, или просто автору не понадобилось.Ну в LLVM это было бы так: Код: void p (int *x) { *x = 5; } Код: clang -O3 -c -emit-llvm -S test.c Код: define void @p(ptr %0) { store i32 5, ptr %0 ret void } Код: clang -c test.ll objdump -d test.o Код: test.o: file format elf64-x86-64
Disassembly of section .text: 0000000000000000 <p>: 0: c7 07 05 00 00 00 movl $0x5,(%rdi) 6: c3 ret |
Автор: | Alexander Shiryaev [ Вторник, 02 Июль, 2024 19:26 ] |
Заголовок сообщения: | Re: NanoOberon/OberonJIT |
arisu писал(а): Alexander Shiryaev писал(а): Хорошо то, что вот это компилируется: я не очень понял, подколка ли это или нет. Код: MODULE M; CONST C = 0E0000000H; VAR x: INTEGER; BEGIN x := C END M. ![]() впрочем, даже если я и добавлю эти проверки, то подобное всё равно будет разрешено. по той логике, что INTEGER — это 32-bit 2-complement signed. мы это знаем, компилятор это знает, CPU это знает — и нет смысла притворяться, что оно не так. соответственно, нет и смысла отвергать альтернативные формы записи этих битов. а в CP2 хексы вообще парзятся в LONGINT, без вариантов. диапазон проверяется только при присваивании, и — насколько помню — [MININT…MAXUINT]. как раз чтобы подобное работало. я б, может, тоже проверял, но в языке у меня лонгинтов нет в принципе, а в крестах нормально проверить переполнение нельзя. я, конечно, использую "-fwrapv", но городить проверки ручками мне лень. В BlackBox и в Project Oberon это компилируется, но если заменить 0E0000000H на 3758096384, то уже нет. В voc/ofront — не компилируется. |
Автор: | arisu [ Вторник, 02 Июль, 2024 19:52 ] |
Заголовок сообщения: | Re: NanoOberon/OberonJIT |
Alexander Shiryaev писал(а): В BlackBox и в Project Oberon это компилируется, но если заменить 0E0000000H на 3758096384, то уже нет. а, понял. как минимум в CP2 это сделано вполне сознательно, да. в смысле, что с хексами так можно. унаследовано от OP2, я полагаю, а в OP2 из оригинального компилятора. то есть, это Вирт себе изначально сделал чтобы жизнь облегчить, видимо. ;-)
В voc/ofront — не компилируется. |
Автор: | Alexander Shiryaev [ Вторник, 02 Июль, 2024 21:17 ] |
Заголовок сообщения: | Re: NanoOberon/OberonJIT |
Alexander Shiryaev писал(а): arisu писал(а): также у Nanojit есть ещё один квирк: аргументы функций изменять нельзя. вообще. никак. нет таких инструкций. можно только читать. оно, конечно, красиво и правильно, но в обероне-то можно! пришлось сделать в компилере хак: если он обнаруживает присваивание аргументу, то генерит пролог с копированием оного аргумента в стековый локал, и потом при генерации кода прозрачно работает с этим локалом. ну, кривовато. зато it works. load/store? Я неправильно понял. В LLVM IR тоже нельзя, т. к. оно основано на SSA-форме. Но можно выделить память на стеке через alloca, скопировать его (аргумент) туда и потом уже менять. То есть так же, как в Nanojit. |
Автор: | arisu [ Вторник, 02 Июль, 2024 21:38 ] |
Заголовок сообщения: | Re: NanoOberon/OberonJIT |
это и там тоже нелогично: технически аргументы — это те же самые локалы. никакое SSA не запрещает менять локалы, иначе оно бесполезно же. просто у Nanojit изначально была заточка под житование javascript'а (или actionscript'а, что почти одно и то же). там в любом случае передают указатели на объекты, так что особого смысла в инструкции присваивания аргументу нет. вот и не сделали. там, например, и понятия «функция возвращает ничего» нет — в js так не бывает. можно, конечно, обойти, возвращая тупо нолик, но я добавил `retv` (void, в смысле). забавно, что Nanojit почти SSA… но почему-то этот последний шаг делать не стали. хотя там внутри даже попытки сэмулировать фита-ноды есть. к сожалению, консервативно, явно их создавать нельзя. я бы, конечно, и с нуля кодоген на SSA сделал, но у Nanojit есть бэкэнды к x86_64 и ARM. на них у меня ушло бы слишком много усилий — в связи с отсутствием такого же опыта, как с x86. а LLVM мне неинтересен в связи с монструозностью. Nanojit я могу просто кинуть в проект и всё, там даже STL не используется. есть ещё libJIT, она даже местами лучше (и SSA, и на чистом си), но её тоже не выйдет «просто кинуть и забыть». на самом деле (я, вроде бы, писал уже) весь этот проект — это я пытаюсь оценить, насколько имеет смысл плотно возиться с Nanojit. то бишь, насколько трудоёмко будет использовать нано для AOT-компиляции реального языка. я в курсе, что JIT-ы придуманы не для этого, но почему бы и да? ;-) меня устраивает посредственный код, но быстро и в рантайме. |
Страница 1 из 17 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |