LINUX.ORG.RU

Homoiconic C

 homoiconicity,


3

2

Я тут упоролся и подумал, а что если бы у нас был ЯП уровня Си с гомоиконным синтаксисом в стиле Io или Julia. То есть — у нас есть интерпретатор гомоиконного языка, который работает как макропроцессор, и результат трансформаций исходного кода скармливается затем компилятору языка с Си-подобной семантикой. И у нас будет нормальный тьюринг-полный макроязык, который позволит бескостыльно расширять возможности ЯП неограниченно. Компилирующаяя же часть будет по сути обычным компилятором Си (просто читающим входные данные в неСишном синтаксисе).

Это ж кайф. Выражения типа regexp(«^[a-z][a-z0-9]») или format(«%s - %s (%d)», bla1, bla2, i) можно будет автоматически обрабатывать макропроцессором и отправлять компилятору оптимизированный вариант. Это значит, регулярка, например, будет скопилирована в конечный автомат при компиляции программы, а не при выполнении.

Вот эта вот странная задачка, на которой dr_jumba проверял лаконичность языков, записывалась бы как-то вот так:

sample_function := fn(a(iterable(T))) to(T) {
    a select(match(regexp(/^J[a-z]+/))) each_chunk(3) map(format_with("~1 and ~2 follow ~3")) join("\n")
}

Дискас.

Ответ на: комментарий от anonymous

Пользователю хуже, потому как он получает менее качественный код.

Не понял в каком смысле менее качественный? Как код может быть менее качественным, если он совпадает?

С макросами невозможны высокоуровневые оптимизации.

Кто это тебе сказал? Точно так же возможны как и без макросов, макросы тут ни на что не влияют. Оптимизации-то производятся после экспанда, а там уже макросов нет.

anonymous
()
Ответ на: комментарий от anonymous

Как это «нет макросов»?

Ну так, нет.

Там вообще нет ничего, кроме макросов.

Там нету ничего кроме примитивного препроцессора (уровня сишки). Даже с общелиспом это сравнивать смешно, ну а чтобы уж полноценной макросистемой называть - надо реально упороться.

anonymous
()
Ответ на: комментарий от anonymous

Там нету ничего кроме примитивного препроцессора (уровня сишки).

По определению, макросы - это и есть примитивный препроцессор, работающий на уровне AST. Именно это в MPS и делается. Причем, код пишется на Java, полноценном языке, в отличие от всяких там лиспов.

А уж сравнивать это с сишным препроцессором просто нелепо, сишный препроцессор работает на уровне текста, а в MPS текстового представления кода вообще нет в принципе, там есть только AST.

anonymous
()
Ответ на: комментарий от anonymous

Не понял в каком смысле менее качественный? Как код может быть менее качественным, если он совпадает?

Совпадает с чем?!?

Допустим, есть компилятор А, где конструкция for реализована как макрос, раскрывающийся в кучку меток и goto. И есть компилятор Б, где эта конструкция является встроенным примитивом. Спрашивается, какой из компиляторов сможет сделать больше оптимизаций для этого цикла?

Кто это тебе сказал?

Здравый смысл и огромный практический опыт в компиляторостроении.

Точно так же возможны как и без макросов, макросы тут ни на что не влияют.

Именно что влияют. Если фичи языка делаются на уровне макросов, раскрывающихся в более убогие примитивы, то теряется возможность проделать над этими фичами оптимизации высокого уровня.

Оптимизации-то производятся после экспанда, а там уже макросов нет.

Именно. А если без макросов, то можно проделать оптимизации и до экспанда в более низкий уровень.

anonymous
()
Ответ на: комментарий от anonymous

По определению, макросы - это и есть примитивный препроцессор, работающий на уровне AST.

Да нет, коненчо. Препроцессор - это препроцессор, а макросистема - это макросистема. Не надо их путать.

Если у тебя есть некоторая поебень, которая может взять кусок АСТ и нагенерить из него некоторый другой кусок АСТ - это препроцессор.

А уж сравнивать это с сишным препроцессором просто нелепо, сишный препроцессор работает на уровне текста, а в MPS текстового представления кода вообще нет в принципе, там есть только AST.

А это вобщем-то несущественно. В том плане, что разница между MPS и препроцессором сишки хоть и есть, но она пренебрежимо мала по сравнению с разницей между MPS и макросистемой.

Причем, код пишется на Java

Потому и препроцессор. Макросы - это то, что исполняется внутри инстанса рантайма, который затем будет исполнять преобразованный код. По-этому макросы, которые пишутся на джаве, умеют генерировать только джаву и работать только внутри жабарантайма. Но вобщем-то все проще можно сделать - покажи мне как выглядит в MPS макрос aif.

anonymous
()
Ответ на: комментарий от anonymous

Макросы - это то, что исполняется внутри инстанса рантайма, который затем будет исполнять преобразованный код.

Именно так в MPS и сделано. Следующий!

anonymous
()
Ответ на: комментарий от anonymous

Допустим, есть компилятор А, где конструкция for реализована как макрос, раскрывающийся в кучку меток и goto. И есть компилятор Б, где эта конструкция является встроенным примитивом. Спрашивается, какой из компиляторов сможет сделать больше оптимизаций для этого цикла?

Естественно, что первый. Он имеет значительно больше информации о коде.

Здравый смысл и огромный практический опыт в компиляторостроении.

Зуевый у тебя смысл и опыт, раз реальности не соответствует.

Именно что влияют. Если фичи языка делаются на уровне макросов, раскрывающихся в более убогие примитивы, то теряется возможность проделать над этими фичами оптимизации высокого уровня.

Как раз наоборот.

Именно. А если без макросов, то можно проделать оптимизации и до экспанда в более низкий уровень.

Их же можно проделать после экспанда. Или во время экспанда.

anonymous
()
Ответ на: комментарий от anonymous

ЗЫ: одна из причин, почему Фортран долгое время в хвост и в гриву уделывал по производительности всякие там сишечки для числодробильни была в том, что у него есть встроенная в язык поддержка комплексных чисел.

anonymous
()
Ответ на: комментарий от anonymous

Именно так в MPS и сделано.

Нет не сделано, дурашка. Сперва происходит трансформация кода и только потом он уже исполняется в совершенно другом рантайме. На это какбе намекает тот факт, что можно в MPS кодогенерировать разные ЯП с разными рантаймами.

anonymous
()
Ответ на: комментарий от anonymous

что у него есть встроенная в язык поддержка комплексных чисел.

И? ЯП или умеет делать луп-анролинг или нет, и это никак не зависит от того, является for примитивной формой или раскрывается в гото.

anonymous
()
Ответ на: комментарий от anonymous

Допустим, есть компилятор А, где конструкция for реализована как макрос, раскрывающийся в кучку меток и goto. И есть компилятор Б, где эта конструкция является встроенным примитивом. Спрашивается, какой из компиляторов сможет сделать больше оптимизаций для этого цикла?

Правильный ответ: компилятор А.

Любой оптимизирующий компилятор, если это действительно оптимизирующий компилятор, а не говно, производит оптимизации на графе потока управления. И ему абсолютно по барабану, что оптизизировать: for или лапшу из goto. Потому что для него это одно и то же.

geekless ★★
() автор топика
Ответ на: комментарий от anonymous

Рантайм там один - JVM.

И код на сишке тоже внутри jvm исполняется? кул стори, бро.

anonymous
()
Ответ на: комментарий от geekless

И ему абсолютно по барабану, что оптизизировать: for или лапшу из goto. Потому что для него это одно и то же.

В том-то и дело, что не по барабану. В for у тебя уже явно прописано, кто является induction variable, какой шаг, и т.п. А если делать анализ на SSA, то, во первых, получается дороже и дольше, а во вторых есть случаи, когда induction variable можно и не найти. И это еще самый примитивный случай, а если мы захотим к этому самому for добавить прагмы (как в OpenMP, например), то с макросом жить станет еще сложнее.

А уж в случае с алгебраическими оптимизациями (те же комплексные числа в Фортране) и вовсе ничего нельзя сделать на низком уровне - там уже семантика потерялась.

anonymous
()
Ответ на: комментарий от anonymous

Ты помоему не понимаешь главного - компилятор прекрасно знает, что лапша из goto и label'ов раньше была фором. То есть он знает все то, что знает компилятор, в котором for - примитвная форма + еще немного больше (результат экспанда).

Аналогично с комплексными числами.

anonymous
()
Ответ на: комментарий от anonymous

Естественно, что первый. Он имеет значительно больше информации о коде.

Чего? Что за чушь? У второго более богатая семантика.

Зуевый у тебя смысл и опыт, раз реальности не соответствует.

Найди реальные, промышленные компиляторы, которые сделаны на макросах.

Их же можно проделать после экспанда. Или во время экспанда.

Как ты после экспанда проделаешь оптимизации высокого уровня? Семантика уже потерялась. Ты уже не знаешь, что это операции над комплексными числами, к которым можно применить такие-то и такие-то алгебраические преобразования - для низкого уровня это будет уже кучка непонятных операций над float-ами.

anonymous
()
Ответ на: комментарий от anonymous

Чего? Что за чушь? У второго более богатая семантика.

С чего вдруг?

Как ты после экспанда проделаешь оптимизации высокого уровня?

Так же как и до.

Ты уже не знаешь, что это операции над комплексными числами

Прекрасно знаю. С чего бы я не знал?

И вообще все эти оптимизации еще внутри экспанда самого фора можно применить спокойно.

anonymous
()
Ответ на: комментарий от anonymous

Ты помоему не понимаешь главного - компилятор прекрасно знает, что лапша из goto и label'ов раньше была фором.

Это если после всех оптимизаций control flow остался reducible. Тогда да, знает. Точнее, может восстановить из control flow - найти back edge (и то, после оптимизаций их может стать несколько для одного for, что усложняет ситуацию).

А вот найти induction variable для этого цикла - задача уже заметно более сложная, и такой информации при раскрытии for не сохраняется.

Аналогично с комплексными числами.

Ты некомпетентен.

anonymous
()
Ответ на: комментарий от anonymous

С чего вдруг?

С того, что больше сущностей в семантике. Кроме просто label и goto есть еще и конкретная сущность - цикл с такой-то induction variable, таким-то конкретным условием выхода и таким-то шагом. И все это уже дано, готовенькое, его не надо восстанавливать из SSA.

Так же как и до.

Ты ни хера не понимаешь, что такое оптимизации высокого уровня. Примитивно мыслишь.

Прекрасно знаю. С чего бы я не знал?

Откуда ты это знаешь? При раскрытии макросов (ну или темплейтов в C++) информации о семантике не сохранилось. Теперь это просто операции над обычными плавучими. И ты уже не сможешь применить конкретно знания об особенностях комплексных чисел.

Ладно еще, когда используются интринсики для того, чтобы дать подсказку компилятору, но тогда пропадает смысл в макросах - все равно поддержка фичи требует и изменений в backend, и одного только макроса недостаточно.

И вообще все эти оптимизации еще внутри экспанда самого фора можно применить спокойно.

Да, ты действительно абсолютно некомпетентен.

У тебя внутри экспанда еще и все другие макросы не раскрылись. У тебя нет информации о контексте. Ты не можешь внутри макроса изменить код, который вне этого макроса. О каких тут оптимизациях можно говорить?

anonymous
()
Ответ на: комментарий от anonymous

И? ЯП или умеет делать луп-анролинг или нет,

Это единственная оптимизация, которую ты можешь для циклов придумать? Свободен, следующий!

anonymous
()
Ответ на: комментарий от anonymous

Это если после всех оптимизаций control flow остался reducible.

после каких оптимизаций, олух? Не было никаких оптимизаций, только экспанд закончился.

Точнее, может восстановить из control flow - найти back edge (и то, после оптимизаций их может стать несколько для одного for, что усложняет ситуацию).

Ему ничего не надо восстанавливать.

А вот найти induction variable для этого цикла - задача уже заметно более сложная, и такой информации при раскрытии for не сохраняется.

Не надо ничего искать. В property раскрытого терма просто хранится исходный терм. И induction variable явным текстом прописана. Там вообще все прописано, что в исходном терме есть. По-этому никакой информации не теряется.

anonymous
()
Ответ на: комментарий от anonymous

после каких оптимизаций, олух? Не было никаких оптимизаций, только экспанд закончился.

Ты абсолютно некомпетентен. С какой такой радости backend будет сразу после раскрытия макросов, наплевав на все остальное, сверкая пятками бежать делать конкретно loop optimizations?

Ему ничего не надо восстанавливать.

Ты вообще ни хера про компиляторы не знаешь.

Итак, лох, рассказывай, каким образом backend узнает, кто является induction variable для цикла, выделяет условие выхода и выражение для вычисления шага. Необходимо это для polyhedral-анализа (то есть, для автоматического распараллеливания), для проверки на конечность цикла, и тому подобного.

Да, современные SSA компиляторы всю эту информацию могут извлечь. Очень дорого и не всегда корректно. Тогда как если for остается известной компилятору конструкцией, все становится намного проще.

В property раскрытого терма просто хранится исходный терм. И induction variable явным текстом прописана. Там вообще все прописано, что в исходном терме есть. По-этому никакой информации не теряется.

Ты совсем тупой?

Или мы реализуем for как макрос, а наш backend ни черта не знает про циклы, у него есть только basic block-и и условные переходы между ними, или backend знает, что такое for, и тогда ни о каких макросах не может быть и речи.

anonymous
()
Ответ на: комментарий от anonymous

А больше никаких оптимизаций для _цикла_ науке не известно, бедный мой друг.

У тебя нет мозга. Ты безграмотен и бесполезен. За каким хером ты с такой убежденностью рассуждаешь на тему, в которой абсолютно не разбираешься?

Во первых, есть loop fusion. Одна из самых полезных оптимизаций вообще. Во вторых, целая куча разных оптимизаций и преобразований, основанных на polyhedral-анализе. Например, loop coarsening, с заменой внутренней части цикла на SIMD-операции (или распараллеливание на несколько потоков).

anonymous
()
Ответ на: комментарий от anonymous

Да, и главное забыл - loop invariant lifting. А это тоже далеко не однозначная оптимизация, которую при анализе только одного цикла делать сразу нельзя, можно только в контексте всей функции в целом (потому как может измениться register pressure).

anonymous
()
Ответ на: комментарий от anonymous

С того, что больше сущностей в семантике. Кроме просто label и goto есть еще и конкретная сущность - цикл с такой-то induction variable, таким-то конкретным условием выхода и таким-то шагом. И все это уже дано, готовенькое, его не надо восстанавливать из SSA.

Все то же самое у тебя есть после экспанда - цикл с такой-то там induction variable, да. И восстанавливать ничего ниоткуда не нужно - тоже верно.

Откуда ты это знаешь? При раскрытии макросов (ну или темплейтов в C++) информации о семантике не сохранилось.

Ну при раскрытие темплейтов с++ действительно ничего не сохраняется - ведь это препроцессор. При раскрытии макросов все прекрасно сохраняется.

Теперь это просто операции над обычными плавучими.

О которых компилятор знает, что они получились из операций над комплексными. Более того - компилятор прекрасно знает исчодный код. Более того - он даже знает точное расположение и связи между подттермами/идентификатоарми на всех шагах экспанда. В том числе на первом и на последнем (то есть до экспанда и когда он полностью закончился).

У тебя внутри экспанда еще и все другие макросы не раскрылись.

А это в общем случае не нужно.

У тебя нет информации о контексте.

Хватит уже о препроцессорах говорить. Препроцессоры типа MPS - это говно, да, ненужное говно. Но они никакого отнлшения не имеют к макросам.

Ты не можешь внутри макроса изменить код, который вне этого макроса.

Ну, вообще говоря - могу. Но так делать не стоит, т.к. это силньо нарушает семантику экспанда. В случае _высокоуровневых_ оптимизаций, однако, это и не требуется - раскрытие внешнего макроса может быть как угодно завязано на раскрытие внутренних макросов (и собранной во время этого раскрытия информации).

О каких тут оптимизациях можно говорить?

А о каких нельзя? О любых можно.

anonymous
()
Ответ на: комментарий от anonymous

Все то же самое у тебя есть после экспанда - цикл с такой-то там induction variable, да. И восстанавливать ничего ниоткуда не нужно - тоже верно.

То есть, у тебя в IR есть такая конструкция, как «цикл с такой-то induction variable, шагом и условием»? Ну на кой хер тогда тебе макрос еще понадобился, если это у тебя уже примитив.

А если это не примитив, и backend про него ничего не знает, тогда как он будет пользоваться этой информацией для оптимизации?

При раскрытии макросов все прекрасно сохраняется.

Идиот. Ничего не сохраняется. Если исходная семантика известна низкому уровню, то макрос не нужен. Если не известна, то сохранять ее бесполезно.

О которых компилятор знает, что они получились из операций над комплексными.

Ты редкостный идиот. Если компилятор и так знает про комплексные чила, то макросы не нужны. Если не знает, то он не сможет их корректно оптимизировать.

Хватит уже о препроцессорах говорить. Препроцессоры типа MPS - это говно, да, ненужное говно. Но они никакого отнлшения не имеют к макросам.

Повторяю для недоумков - у тебя нет информации о контексте при раскрытии макроса. Ни в говнолиспеге, ни в говнорэкете, ни в говнонемерлеге.

Ну, вообще говоря - могу. Но так делать не стоит, т.к. это силньо нарушает семантику экспанда.

И о каких ты тогда оптимизациях тут смеешь вякать?

В случае _высокоуровневых_ оптимизаций, однако, это и не требуется

Ты, похоже, вообще не понимаешь, что такое оптимизации, и зачем они нужны.

Расскажи за хотя бы constant folding на этапе макроэкспанда, так, чиста поржать. Особенно смешно будет услышать про constant folding после inlining.

anonymous
()
Ответ на: комментарий от anonymous

В динамических ЯП оно происходит безо всяких типов.

«только типы тут не при чем» — а я скажу «только динамические ЯП тут ни при чём». В хаскеле оно так работает, то есть _не только_ и _не столько_ за счёт модулей, например:

pass :: (m -> m) -> TChan m -> TChan m -> STM ()
pass fn chan1 chan2 = do
  msg <- readTChan chan1
  let msg' = fn msg
  -- ... STM, но не IO
  writeTChan chan2 msg'

-- или

pass fn chan1 chan2 = writeTChan chan2 . fn =<< readTChan chan1

я захватываю два канала, читаю из одного, обрабатываю сообщение и пишу во второй, потом это переводится в IO как одно атомарное действие с помощью

foo :: IO ()
foo = do
  chan1 <- ...
  chan2 <- ...
  ...
  atomically $ pass someFn chan1 chan2
  ...

то что STM не проваливается в IO и IO действия не попадают в STM это именно проверка типов — в интерфейсе есть много функций возвращающих и то и другое, я сам выбираю какая композиция STM действий будет атомарной и явно перевожу STM в IO с помощью atomically. Обратно — ещё более явно с помощью unsafeIOToSTM.

То есть даже _без_ модулей и сокрытия _вообще_ — уровни всё равно окажутся разделены (будут использоваться data или newtype, но не type), а всё смешивание будет явным, — так с монадическими трансформерами бывает, или с ST — то есть со всем у чего есть и lift и run одновременно.

Кстати, а как в динамических ЯП делать подобие монадических регионов / эффектов с подобными же гарантиями про разделение уровней и захваты ресурсов с освобождениями? Мне приходит на ум только full-blown eDSL с макросами и code walker-ом. То есть (with-io ... (with-stm ... (with-io <- поймаем при раскрытии макросов))).

тот же хаскель, в котором монады никому не были бы нужны, если бы не наличие сахарка в виде do-нотации

Это ты так думаешь.

Если наша система типов столь выразительна, что никакая другая система типов не может быть более выразительна, чем наша, то эта система типов называется макросистемой.

Это не «система типов», это «любая compile-time хрень вообще». То есть, например, ты не можешь поймать в более-менее изученных системах типов такое свойство программ как «терминируемость» (хотя некоторым системам это свойство нужно как воздух), но можешь взять в макросе программу, воспользоваться API компилятора / образа, узнать про сигнатуры и определения функций, сигнатуры и определения данных и провести анализ примитивной и структурной рекурсии, выделив класс заведомо завершимых программ, отбросив как зависающие, так и прочие завершимые (но вне классов сложностей примитивной и структурной рекурсии). При этом точную оценку ты никогда не получишь, потому что проблема останова — ты сказал про «разрешимые системы типов», так вот, никакая «разрешимая» система типов не ответит на такой вопрос. А так как макросистема эквивалентна по вычислительной части самому языку — она тоже «неразрешима», поэтому не может являться никакой «верхней гранью» «разрешимых систем типов» (ещё и упорядоченных по «выразительности» :)).

Ну или для оптимизаций можно макросы использовать с тем же успехом.

Ты говоришь про макросистему как про некую форму comiler plugins с exanderом, с рефлексией, с доступом к API реализации — если можно ею проводить унификацию по коду, использовать как синтаксический фреймворк для рассуждения о свойствах программ, делать проверки типов, то хорошо, но тогда этим её использование явно не будет ограничиваться. Так что она не эквивалентна системе (и тем более теории) типов, вообще имеет к ней косвенное отношение (какое к ней имеет отношение сам хост язык? на нём можно написать тайпчекер, да).

А какая разница? Нафиг нам сдалась эта модель?

Речь, во-первых, про модель, во-вторых, про модель которая суть логическая интерпретация языка (почему я упомянул CH). Нужно это для того чтобы формально доказывать логическую корректность программ (как можно проще, что предполагает CH).

если они уже запилены внутри макросистемы?

Я говорю про структуры данных и алгоритмы имеющие отношение к предметной области, то есть про AST, функции проверки типов и т.п. — если их написать, можно будет потом спокойно и в макрос обвернуть.

Тайпчек должен идти синхронно с процессом экспанда, а то, что ты предлагаешь - это унылый кодеволкер

Да, явно второе.

quasimoto ★★★★
()
Ответ на: комментарий от anonymous

С какой такой радости backend будет сразу после раскрытия макросов, наплевав на все остальное, сверкая пятками бежать делать конкретно loop optimizations?

А я откуда знаю? Это у тебя надо спросить, почему бекенд сразу после построения АСТ бежит циклы фьюзить.

Итак, лох, рассказывай, каким образом backend узнает, кто является induction variable для цикла, выделяет условие выхода и выражение для вычисления шага.

А как он потвоему это без макросов узнает?

Да, современные SSA компиляторы всю эту информацию могут извлечь. Очень дорого и не всегда корректно. Тогда как если for остается известной компилятору конструкцией, все становится намного проще.

Да не надо ее извлекать ебанашка. Компилятору известно, что каша из лабелов и готов раньше была конкретной for-формой. С такими-то переменными, таким-то телом.

Ты совсем тупой?

Нет, это ты дебил, который не понимает очевидных вещей.

Или мы реализуем for как макрос, а наш backend ни черта не знает про циклы, у него есть только basic block-и и условные переходы между ними, или backend знает, что такое for, и тогда ни о каких макросах не может быть и речи.

Еще есть третья возможность - бекенд знает про фор, который реализован в виде макроса, и делает все нужные оптимизации. Вообще все просто - бекенд знает как оптимизировать for, он смотрит на АСТ, видит, что этот кусок кода был раньше for-ом, извлекает исходный кусок АСТ (и вообще всю историю экспанда, если нужно) из пропертей терма и делает нужные преобразования. Повторяю - он не выводит ничего ниоткуда. Вся эта информацию присоединяется к результирующему терму во время раскрытия исходного терма.

anonymous
()
Ответ на: комментарий от anonymous

каким образом backend узнает, кто является induction variable для цикла

Анализом, анон, анализом. И более того, он может посчитать за induction variable совсем не то, что считаешь ею ты, читая код. А твою induction variable вообще выкинуть в ходе оптимизаций.

Ахо и Ульмана читай.

geekless ★★
() автор топика
Ответ на: комментарий от anonymous

Луп фьюжн это не оптимизация для _циклов_, simd/распараллеливание - это форма анролинга. лифтинг - тоже общая whole-program оптимизация, циклы там не при чем.

anonymous
()
Ответ на: комментарий от anonymous

А я откуда знаю?

Мы уже выяснили, что ты про компиляторы не знаешь ровным счетом ни хера.

Это у тебя надо спросить, почему бекенд сразу после построения АСТ бежит циклы фьюзить.

На фига ему сразу это делать? Он это может сделать когда угодно, цикл - полноправный примитив в IR.

А как он потвоему это без макросов узнает?

Мне кажется, ты совершенно потерял нить дискуссии. И начал нести полную чушь. Какие такие макросы? В твоей идиотской версии реальности макросы раскрылись уже.

Компилятору известно, что каша из лабелов и готов раньше была конкретной for-формой. С такими-то переменными, таким-то телом.

Ты редкостно безмозглая свинья. Если компилятору это известно, то for для него - низкоуровневый примитив. И тогда никаких сраных макросов для реализации for не надо. А если ему это не известно, то эту информацию надо извлекать (смотри на пассы loop analysis в LLVM).

Еще есть третья возможность - бекенд знает про фор, который реализован в виде макроса, и делает все нужные оптимизации.

Ты абсолютно невменяемое ничтожество. Если бекенд знает про for, то макрос не нужен. Точка.

Смысл макросов в том, чтобы добавлять в язык новую функциональность. А если эта функциональность там уже есть, если backend умеет эту семантику понимать и оптимизировать, то макрос не нужен.

anonymous
()
Ответ на: комментарий от quasimoto

хотя некоторым системам это свойство нужно как воздух

Кстати, можно примеры реальных предметных областей?

geekless ★★
() автор топика
Ответ на: комментарий от anonymous

Луп фьюжн это не оптимизация для _циклов_,

Ты быдло без мозгов. Это оптимизация именно циклов. Например:

{
  for(int i = 0; i < N; i++) { A[i] = F(...); }
  for(int j = 0; j < N; j++) { G(A[j], ...); }
}

должно раскрыться в

for(int i = 0; i < N; i++) { A[i] = F(...); G(A[j], ...);}

Но только если F и G независимы по сайд-эффектам.

А теперь придумай, сявка, как это сделать на уровне макроэкспанда, когда у тебя никакой информации о контексте нет.

simd/распараллеливание - это форма анролинга

Ололо! Откуда столько безмозглой шпаны на ЛОРе?!?

Иди, говна кусок, читай: http://en.wikipedia.org/wiki/Polytope_model

Ничего общего с банальным и убогим loop unrolling там нет.

. лифтинг - тоже общая whole-program оптимизация, циклы там не при чем.

Ты быдло. Циклы при том, что нужен анализ инвариантов цикла. При чем тут «whole-program» я вообще не догоняю, тебя, видать, серьезно распидорасило.

anonymous
()
Ответ на: комментарий от geekless

Анализом, анон, анализом.

Дорогим и не всегда корректным.

И более того, он может посчитать за induction variable совсем не то, что считаешь ею ты, читая код.

Вообще-то мне лучше знать, когда я пишу код, что должно являться induction variable для цикла.

А твою induction variable вообще выкинуть в ходе оптимизаций.

Быдлокод-то тут при чем?

Ахо и Ульмана читай.

Эти ушлепки даже про SSA не знают. На хера их читать?

anonymous
()
Ответ на: комментарий от anonymous

То есть, у тебя в IR есть такая конструкция, как «цикл с такой-то induction variable, шагом и условием»?

Нет.

А если это не примитив, и backend про него ничего не знает, тогда как он будет пользоваться этой информацией для оптимизации?

Это не примитив, но бекенд про него знает. Мне непонятно, что тут непонятного?

Идиот. Ничего не сохраняется.

Меня просто поражает уебанство твое.

> (syntax-property (expand #'(for ([i 10]) (display i))) 'origin)
'(.#<syntax for/foldX/derived> .#<syntax for/foldX/derived> .#<syntax for/foldX/derived> .#<syntax for/foldX/derived> .#<syntax for/foldX/derived/break> .#<syntax for/fold/derived> .#<syntax:7:30 for>)
> 

Если исходная семантика известна низкому уровню, то макрос не нужен.

Почему не нужен то? Зачем делать примитивной формой то, что можно реализовать в виде библиотечного макроса?

Если компилятор и так знает про комплексные чила, то макросы не нужны.

С чего вдруг не нужны то?

Повторяю для недоумков - у тебя нет информации о контексте при раскрытии макроса.

Хватит хуйню нести, а?

И о каких ты тогда оптимизациях тут смеешь вякать?

Я же дальше пояснил - можно собрать всю нужную информацию во время экспанда внутренних макросов и раскрыть текущий в зависимости от нее.

anonymous
()
Ответ на: комментарий от anonymous

Дорогим и не всегда корректным.

Других способов нет.

Вообще-то мне лучше знать, когда я пишу код, что должно являться induction variable для цикла.

Особенно если в ходе кручения цикла надо инкрементировать указатель, а твой ЯП указателями не оперирует.

Быдлокод-то тут при чем?

Любая высокоуровневая работа с массивами внезапно оказывается быдлокодом, лол.

На хера их читать?

А нахера ты пишешь чушь?

geekless ★★
() автор топика
Ответ на: комментарий от anonymous

Это не примитив, но бекенд про него знает. Мне непонятно, что тут непонятного?

Убогое быдло, примитив, по определению, это то, чем оперирует backend.

Почему не нужен то? Зачем делать примитивной формой то, что можно реализовать в виде библиотечного макроса?

Ты абсолютно, непробиваемо тупая свинья. Если backend знает про эту семантику, то оно уже, по определению, примитивная форма. И ты не можешь ее реализовать в виде библиотечного макроса, не переписав backend.

С чего вдруг не нужны то?

С того, что ты тупой. Зачем нужен макрос, повторяющий семантику IR?

И если ты захочешь добавить в язык еще какую-либо сложную конструкцию, то тебе все равно придется ее добавлять и в backend тоже, если ты хочешь делать над этой сущностью сложные высокоуровневые оптимизации. Так зачем тогда макросы, если все равно все в backend делать придется?

можно собрать всю нужную информацию во время экспанда внутренних макросов

Дебил. Если backend эту информацию может понять, то на кой хер нужны макросы?

anonymous
()
Ответ на: комментарий от anonymous

Мне кажется, ты совершенно потерял нить дискуссии. И начал нести полную чушь. Какие такие макросы? В твоей идиотской версии реальности макросы раскрылись уже.

И? Ты можешь объяснить толком в чем проблема, по-твоему, компилятору узнать из раскрытого терма его оригинал, если во время раскрытия этот терм был присобачен в пропертях?

Если компилятору это известно, то for для него - низкоуровневый примитив.

Нет.

И тогда никаких сраных макросов для реализации for не надо.

надо.

Если бекенд знает про for, то макрос не нужен. Точка.

Нужен. Точка.

Смысл макросов в том, чтобы добавлять в язык новую функциональность.

Мы сейчас о for, по-моему? То есть о том, зачем макросы нужны разработчику языка. В данном случае - для повышения модульности, всегда лучше реализовать for макросом, чем пидорасить в ядре языка. Исходные термы сохраняются в рамках стандартного протокола, expand в определении макроса, а как будет оптимизировать это дело бекенд (и вообще будет ли) - это дело десятое. В твоем решении (с примитивной формой) все прикручено костылями к ядру.

Можно считать эту информацию о for хинтом бекенда. На самом деле это может быть даже и не сама исходная форма, а конкретно хинт, и бекенд будет ловить не форму в истории, а эти хинты. Соответственно, их сможет расставить любой пользователь в своем макросе, если хочет передать компилятору соответствующую информацию. И ему не надо будет раскрыываться в for.

Другими словами бекенд поддерживает какие-то подсказки о том, где и какие оптимизации можно провести, а как их в макросах будут расставлять - вопрос ортогональный.

anonymous
()
Ответ на: комментарий от geekless

Других способов нет.

Есть. Сказать это бэкенду прямым текстом.

Особенно если в ходе кручения цикла надо инкрементировать указатель, а твой ЯП указателями не оперирует.

Не понял. На хера тебе указатель, если их нет в языке?

Любая высокоуровневая работа с массивами внезапно оказывается быдлокодом, лол.

Почему вдруг induction variable окажется неиспользованной при работе с массивом?

А нахера ты пишешь чушь?

На себя посмотри.

anonymous
()
Ответ на: комментарий от anonymous

когда у тебя никакой информации о контексте нет.

С чего же я должен принимать за истину заведомо некорректное утверждение об отсутствии контекста?

Это оптимизация именно циклов.

Ну ты и конченый, а. Ее можно только на flow-графе делать.

Ты быдло. Циклы при том, что нужен анализ инвариантов цикла.

Я тебе уебку какбе намекаю, что эта оптимизация тоже делается только на flow-графе.

А там никаких forов уже нету, да.

anonymous
()
Ответ на: комментарий от anonymous

Сказать это бэкенду прямым текстом.

Об этом так и можно сказать, хинтом: «вот эту херню рассматривай как кандидата на induction variable». И это гораздо более правильное решение, чем пидорасить for во входной язык бэкэнда.

Не понял. На хера тебе указатель, если их нет в языке?

Указатели будут в семантике маш.кода.

Почему вдруг induction variable окажется неиспользованной при работе с массивом?

При том, что оптимизируется в инкрементирование указателя.

geekless ★★
() автор топика
Ответ на: комментарий от anonymous

И? Ты можешь объяснить толком в чем проблема, по-твоему, компилятору узнать из раскрытого терма его оригинал, если во время раскрытия этот терм был присобачен в пропертях?

Если компилятор может этот оригинал понять, то на хера его было вообще раскрывать? А если не может, то на хера эту информацию сохранять?

Нет.

Если компилятор понимает семантику for, то for - низкоуровневый примитив, по определению. Наравне с label и goto.

Мы сейчас о for, по-моему? То есть о том, зачем макросы нужны разработчику языка. В данном случае - для повышения модульности, всегда лучше реализовать for макросом, чем пидорасить в ядре языка.

Или ты его реализуешь макросом, и backend о нем ничего не знает и не может корректно оптимизировать, или backend знает про for, понимает его как примитив, и тогда макрос не нужен, он только продублирует уже существующую функциональность.

а как будет оптимизировать это дело бекенд (и вообще будет ли) - это дело десятое

Нет. Или backend про for знает и оптимизирует его (и тогда макрос не нужен), или он реализован как макрос, и backend ничего не сможет оптимизировать. Других вариантов нет, точнее, все другие варианты крайне идиотские.

Можно считать эту информацию о for хинтом бекенда.

Ну и на хера? Это уже делает его примитивной формой.

Соответственно, их сможет расставить любой пользователь в своем макросе, если хочет передать компилятору соответствующую информацию.

Ну а почему бы тогда любому пользователю не раскрывать свои макросы в примитивный for?

Другими словами бекенд поддерживает какие-то подсказки о том, где и какие оптимизации можно провести, а как их в макросах будут расставлять - вопрос ортогональный.

Другими словами, ты хочешь дублировать функциональность, но чтоб скрыть свой идиотизм, будешь называть примитивные формы «хинтами». Только вот от перемены терминологии смысл не меняется.

anonymous
()
Ответ на: комментарий от anonymous

Ну ты и конченый, а. Ее можно только на flow-графе делать.

Можно, но сложно. И на порядок проще, если на CFG навешаны аннотации об исходных циклах. И еще проще, если CFG вообще нет, а все оптимизации делаются на уровне структурного AST.

что эта оптимизация тоже делается только на flow-графе.

Это если ты комсомолец и любишь трудности. А если у тебя есть хотя бы зачатки мозга, то ты будешь делать эту оптимизацию на уровне структурного AST, без всяких там ненужных CFG.

А там никаких forов уже нету, да.

На убогий LLVM посмотри, да? Там сначала циклы раскрывают в CFG, а потом развешивают на этот самый CFG обратно информацию от loop analysis (то есть, восстанавливают исходную семантику циклов).

anonymous
()
Ответ на: комментарий от anonymous

ЗЫ: и если следовать твоей гомосексуалистской логике, то и loop unrolling тоже, представь себе, делается на CFG, и «никаких циклов там уже нет».

anonymous
()
Ответ на: комментарий от geekless

Еще один хочет смешивать оптимизации высокого и низкого уронвя. На хера тебе это надо? Массив - это массив, пусть он им и остается для всех оптимизаций циклов, распараллеливаний и т.п. Потом будешь про указатели и прочее говно думать, когда такой уровень представления не будет мешать и требовать всякого там дорогостоящего и неполноценного aliasing analysis.

anonymous
()
Ответ на: комментарий от anonymous

Массив - это массив, пусть он им и остается для всех оптимизаций циклов, распараллеливаний и т.п. Потом будешь про указатели и прочее говно думать, когда такой уровень представления не будет мешать и требовать всякого там дорогостоящего и неполноценного aliasing analysis.

Лол, как ты сообрался оптимизировать потоки управления на уровне, когда у тебя никаких потоков управления еще нет, а есть только AST? Завязывай с веществами, AST раскладывается в граф управления, и все оптимизации выполняются на нём.

Еще один хочет смешивать оптимизации высокого и низкого уронвя. На хера тебе это надо?

Это как раз я не знаю, зачем тебе надо информацию о синтаксических структурах (for) на этапе control flow analysis, когда уже никаких этих структур нет. Но раз уж тебе нужно - я тебе предлагаю решение - передавать хинты в бэкэнд. Но с точки зрения оптимизатора, это нахер ненужная информация, имхо.

geekless ★★
() автор топика
Ответ на: комментарий от geekless

facepalm.ast

Ну тупой ты, тупой.

Посмотри на хотя бы эти сраные лиспеги - где там CFG?

Не нужно ничего на уровне CFG делать, если у тебя исходный язык чисто структурный, и не позволяет порождать irreducible CFG.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.