1. JavaScript / Говнокод #27414

    +1

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    6. 6
    function main() {    
        const x = 21;
        let s = "foo";
        const r = `a${x * 2}X${s}X${s}Z`;
        print(r);
    }

    Продолжаем будни говно-писания говно-компилятора на LLVM. серия - а ваш говно-компилятор может так...

    и результат работы
    >>
    C:\temp\MLIR_to_exe>out.exe
    a42XfooXfooZ

    Запостил: ASD_77, 10 Мая 2021

    Комментарии (33) RSS

    • и дайте знать если кому интересно глянуть на дамп асма
      Ответить
    • Какой скилл )))
      Ответить
      • я понял что народу нужен дамп :) https://pastebin.com/eZxkjgqd
        Ответить
        • Мне не нужен, я в нём не разбираюсь, я анскильный.
          Ответить
          • нет уж. ты полистай и посмотри :)
            Ответить
            • Я так думаю можно было просто высрать constexpr строку "a42XfooXfooZ", которой в высере я не нашёл. Поэтому анскилл )))
              Ответить
        • Это не настоящий асм, это какая-то LLVM-питушня.
          Ответить
          • Ты хоть мне объясни чем настоящий асм отличается от llvm

            Тем, что в нём нету регистра 33?
            Ответить
            • Ну да, это такой псевдокот, очень далёкий от реальных процессоров. Даже сраная jvm ближе к железу.
              Ответить
              • Общеизвестно, что в процессоре куда больше регистров, чем в его ISA (Томасуло и его станции резервирования вроде бы на этом основаны, а за одно и мельтдаун со спектром)

                Если я сделаю процессор, в котором можно "создать" 64 регистра, то я смогу запустить на нём llvm?
                Ответить
                • В LLVM байткоте вроде SSA, т.е. тебе нужно в теории бесконечое количество регистров.
                  Ответить
                  • По идее их можно как-то эмулировать в памяти, но наверное это уже будет не просто на настоящем железе

                    А что, их вообще может быть сколько угодно много? Фронтэнд может сгенерить код, в котором будет 65536 регистров?
                    Ответить
                    • > Фронтэнд может сгенерить код, в котором будет 65536 регистров

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

                      Ну и да, посколько это single assignment, то там одна переменная может в десяток-другой раскрыться, чтобы для оптимизатора поток данных нагляднее был.
                      Ответить
                  • Ну можно выделить под них место на стеке и закешировать верхние штук 30-60 в чём-то более быстром.
                    Ответить
                    • Но если фронт не будет про них знать, что он похерит нахер весь перформанс же?

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

                      Ябло вроде хвасталось, что перейдя на llvm они смогли применять какие-то фиксы (типа ARC или чего-то такого) уже вот прямо к llvm коду
                      Ответить
                      • А не надо фронту про это знать. Аллокация реальных регистров и слотов на стеке -- это уже прям одна из финальных фаз конпеляции, когда все общие оптимизации пройдены.

                        В gcc тоже промежуточный код был, как без него. Вроде даже джва. Но он там пиздец запутанный и фазы не так чётко разделены как в llvm, емнип.
                        Ответить
                        • Тем более, что и куда аллоцировать по определению может знать только бэкенд.
                          Ответить
                        • Я не очень понял

                          вот clang же высирает код в llvm, а далее llvm генерит по нему код под x86, верно?

                          как же сlang может чего-то не знать?
                          Ответить
                          • Когда фронт clang'а высирает LLVM IR, он ещё не знает под какой процессор это будет конпелироваться в итоге. Ну, какие-то вещи типа длины интов он знает, конечно. Но в целом он об этом не задумывается.

                            А соглашения о вызовах, аллокация конкретных регистров, выбор конкретных инструкций -- это уже задача бэка.
                            Ответить
                            • В каком месте тут ошибка в рассуждениях:

                              * в "промежуточном коде" LLVM есть понятие "регистр"
                              * в этом коде регистров может быть неограниченное количество
                              * clang генерирует это код, используя понятие "регистр"
                              * clang может создать промежуточный код, в котором используется 234234 регистра
                              * если доступ к первым пяти будет дешевым, а к остальным дорогим (бо в реальной архитектуре они эмулируются), то clang сгенерит неоптимизированный код

                              Или бекенд может "оптимизировать" код, удалив лишне регистры, если он знает, что делает код для гиоптетчиской LLVM машины с пятью регистрами?

                              Типа clang насрал 100500 регистров, а бек их причесал?
                              Ответить
                              • Ну суть в том, что в IR нет переменных. Есть только вот эти "регистры", которые ещё и присваиваются по одному разу, емнип.

                                Какие из них горячие, а какие нет фронт не знает. Да его это и не должно ебать. Выделять регистры и слоты на стеке -- задача бэка и только бэка. Ибо только он знает сколько там регистров на таргете и видит более-менее финальную форму кода после кучи перестановок и оптимизаций.
                                Ответить
                              • > в "промежуточном коде" LLVM есть понятие "регистр"

                                LLVM IR регистры — абстрактные, и к хардварным отношения не имеют.

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

                                Да, потому что SSA, и LLVM "регистры" иммутабельные. Если фронтенд заанроллит цикл с 234234 итерациями, то под i понадобится 234234 регистров.

                                > clang генерирует это код, используя понятие "регистр"

                                ...из LLVM IR.

                                > Или бекенд может "оптимизировать" код, удалив лишне регистры, если он знает, что делает код для гиоптетчиской LLVM машины с пятью регистрами?

                                Бекенд по определению не делает код для гипотетической машины, он делает код для конкретной хардварной рахитектуры.
                                Ответить
                                • понятно

                                  я просто думал, реально ли сделать такое

                                  фронт --> LLVM код --> реальный проц

                                  но уже понял, что без бека это нереально
                                  Ответить
                                  • Да реально в принципе... Просто с пирфомансом можешь попрощаться.
                                    Ответить
                                    • ну да, если только я не выдумаю такой процессор, который умеет забесплатно создавать регистры налету
                                      Ответить
                                  • LLVM это и есть по сути "универсальный" бэкенд. (В кавычках, т.к. GHC-шники об него обломались)
                                    Ответить
                                    • вроде пишут, что GHC умеет в llvm, но не очень перформансно..
                                      Ответить
                                    • > GHC-шники об него обломались

                                      А почему? Их ленивые thunk'и плохо вписались в LLVM IR?
                                      Ответить
                                      • Не вникал. По слухам, там с TCO были проблемы. Плюс у GHC свой особый call convention.
                                        Ответить
                                    • > LLVM это и есть по сути "универсальный" бэкенд.

                                      Этот "универсальный" бэкенд настолько же универсален, как и какое-нибудь внутреннее говнопредставление из GCC. Нихуя такого прорывного там нет с т.з. фундаментальных вещей, просто еще одна питушня для промежуточного представления питушни с целью трансформации-оптимизации, коих было дохуя, есть дохуя, и будет еще дохуя. Не очень-то ясно, с хуев каких на него так все надрачивают.
                                      Ответить
                          • Ну и вот например ты можешь написать такой код:
                            return (x << 15) | (x >> 15);
                            Фронт это высрет как есть. А бэк подумает: "ага, у моего проца есть инструкция rol, заюзаю ка я её вместо этого говна!"
                            Ответить
                            • Эт я понимаю

                              Я думал, что если я создам такую машину, которая запускает LLVM код напрямую, и в ней будет 4 регистра (а остальные эмулируются), то код будет не оптимальным

                              Но теперь я понял, что мне всё равно нужен будет для нее бек, и превратить идеальный LLVM код в реальный это будет задача уже бека
                              Ответить
                              • > то код будет не оптимальным

                                Ну да, если ты надумаешь исполнять LLVM код "вживую", он будет неоптимальным. Ну потому что эта промежуточная форма весьма далека от железа.

                                А если у тебя будет бэк, то ты уже не LLVM код исполняешь, лол.
                                Ответить

    Добавить комментарий