Сообщение Re[36]: Carbon от 24.04.2024 1:54
Изменено 24.04.2024 1:57 Sinclair
Re[36]: Carbon
Здравствуйте, vdimas, Вы писали:
V>Для тебя это ликбез.
Ложные утверждения ликбезом быть не могут.
S>>Нет, компилятору совершенно всё равно, есть ли в коде шаблоны или нет. Он прекрасно оптимизирует и вот такую функцию:
S>>
V>Define "оптимизирует"? ))
Оставляет от всего кода xor eax, eax.
V>Оптимизаций много разных.
О, началось виляние.
V>"Вся оптимизация" — это какая?
Примерно вся. Распространение констант, инлайн вызовов, разворачивание и разгрузка циклов, алгебраические тождества, приведение подобных — я вспотею перечислять.
S>>Поэтому правильный ответ на вопрос "зачем" — для максимизации производительности.
V>Это делает простая бета-редукция и тотальный инлайн.
Есть множество техник оптимизации, и большинство посвящены именно что ускорению кода.
S>>Если компилятор не будет делать таких оптимизаций, то по бенчмаркам его код будет проигрывать конкурентам.
V>Рассуждения уровня детсада.
V>То ты рассуждаешь о решении уравнений, то совсем уж направление рукой показываешь.
V>Ты хоть понял, почему твоё "уравнение" компилятор и не думал решать?
Я? Нет, не понял. Поясните своими словами.
V>Шаблонного/инлайного, а не любого.
Из любого. Я же вам дал ссылку на код, где инлайна нет, а устранение арифметики — есть.
Инлайн просто протаскивает оптимизацию на один шаг дальше, позволяя устранить не только арифметику, но и бранч.
V>Это результат стандартной бета-редкции, но она возможна только до неких установленных пределов своего распространения
Вообще, вы применяете термины не по назначению. Все редукции определены для лямбда-исчисления, где у функций нет побочных эффектов. В императивном программировании примитивы другие, поэтому такими терминами компиляторщики не пользуются.
V>Ты лучше пройдись по полному списку флагов оптимизации, если решил перечислить их все — там многие десятки флагов.
Отож.
V>Мы тут рассуждали чуть о другом — почему компилятор ведёт себя определённым образом при обнаружении UB?
V>И ответ там на поверхности, вообще-то.
Ну, так я его вам дал восемь постов назад.
V>И почему же в дотнете не превратилась?
Я же вам объяснил — потому что в дотнете нет UB.
V>Т.е., когда подаёшь костанту — оно даёт сразу ответ, бо JIT и AOT инлайнят маленькие методы, т.е. производят небольшую бета-редукцию.
V>Но почему в теле ф-ии остались честные вычисления от параметров? ))
Потому, что в дотнете эта функция возвращает true только для одного значения — int.MaxValue. А для всех остальных она, в соответствии со стандартом, возвращает false.
И точно так же себя ведут плюсы, когда тип аргумента не позволяет UB.
V>Это прямое следствие того, что дотнет не имеет права оптимизировать код на уровне байт-кода.
Вы продолжаете феерически тупить. Я такого давно не видел.
V>Плюсы без агрессивных оптимизаций тоже дают верный код, как и дотнет.
Плюсы дают верный код и с агрессивными оптимизациями. Просто он верный с т.з. стандарта.
V>Вопрос здесь не почему исполняет в случае знаковых, а почему именно так?
Повторю вопрос: почему С++ с агрессивными оптимизациями не превратил is_max<unsigned long> в xor eax, eax?
V>Я ведь ниже дал хороший пример, который должен был объяснить логику разруливания UB.
Нет, не дали.
V>Ну, значит не запрограммировали оптимизацию того уникального случая, когда прибавляют единицу и сравнивают.
А для long, значит, запрограммировали?
Всё ещё хуже, чем я думал.
V>Если прибавлять двойку — уже два сравнения, больше — больше.
Это вы вообще о чём? Какие два сравнения?
V>Беззнаковые "по кругу" переполняют произвольными приращениями, это популярная техника для табличных генераторов (случайных чисел, шума, гармоник и т.д.)
Понятно. Я сдаюсь — вы не способны понять правильный ответ, даже если в него ткнуть носом.
V>Хотя, callvirt достаточно было порождать лишь для внешних зависимостей, которые имеют право чуть отличаться на момент компиляции и рантайма.
Это — досужие рассуждения. Было принято осознанное решение, в котором ошибкой является вызов метода на null-объекте, а не дереференсинг this.
V>Эдак тебя заносит. ))
V>Причина ранней диагностики ошибки по твоей ссылке понятна, когда еще не были развиты наработки по escape analisys.
V>А если this не уходит дальше, как в примере?
V>Почему дотнетные компилятор/JIt/AOT неспособны сделать escape analysis для простейших случаев?
JIT и AOT не имеют права это делать. Потому что семантика инструкции callvirt прописана в стандарте, и отклонение от неё — это бага.
А C# принял такое решение. Что непонятного-то?
V>Джава с такими вещами хорошо справляется уже лет 15, если не больше.
V>В рантайме в джаве, если код пойдёт по ошибочной ветке, будет просто выброшено исключение, а основная ветка выполнится без создания ненужного экземпляра объекта.
И в дотнете "основная ветка" выполнится без создания ненужного экземпляра объекта. А если код пойдёт по ошибочной ветке, будет просто выброшено исключение. В чём вы тут увидели разницу?
V>И, чтобы уж закрыть тему, в C# происходит проверка на null дважды: первый раз "по правилам хорошего тона" в начале ф-ий проверяются аргументы или в коде проверяются возвращаемые значения джругих методов. Второй раз проверка происходит на уровне системы как в моём примере.
Покажите пример, где дотнет проверяет на null дважды.
V>Новомодные nullable-нотации не помогают сэкономить на "системных" проверках аж никак, они помогают сэкономить только на юзверских проверках.
Всё верно, так и должно быть.
V>Т.е. nullable-подход в дотнете не является строгим. Ты можешь вернуть null или подать null в кач-ве аргумента, даже если те описаны как non-nullable.
Именно. Потому что нет гарантий, что код по обе стороны вызова скомпилирован с одной и той же конфигурацией нуллабельности.
V>И одновременно с этим обрезает оптимизации, т.е. не позволяет выкидывать ненужный код. ))
Какой именно?
V>Во всей этой истории я зацепился из-за твоего любимого взятого тона в адрес плюсов, мол, херня какая-то происходит.
V>Нет, не херня. В каждом конкретном случае или никакой оптимизации при UB не происходит вовсе (как в MSVC), либо происходит такая оптимизация, которая считает, что ошибочная ситуация произойти не должна.
Ну так это и есть херня, т.к. поведение кода радикально меняется при оптимизации и без неё. В итоге можно успешно отлаживаться, а в релизе получить булшит.
Вот вы только что с гордостью привели пример, как здорово работает код с UB в MSVC. Ну так это и провоцирует писать код в стиле приведённого мной примера — "а чо, я же знаю, что на самом деле будет происходить!".
V>Clang традиционно более щепетилен — поэтому он всегда создаёт ненужный объект в моём сниппете.
V>Но Clang — это не про производительность, это некий референс плюсов как таковых.
С тех пор, как он переехал на LLVM, он по производительности не сильно хуже gcc.
V>GCC — это существо из рил ворлд, поэтому исследует объекты на предмет побочных эффектов и убегания зависимостей, и если их нет — может "уничтожать" объекты, т.е. не конструировать их вовсе, а брать только описанную функциональность. Единственным "побочным эффектом" тут будет лишнее выделение памяти аккурат перед AV, что побочным эффектом не очень-то и считается.
Тут нет выделения памяти перед AV.
V>Лично меня тут удивило чуть другое — когда-то MSVC в деле оптимизаций драл GCC в хвост и гриву, а сейчас малость сдал позиции...
V>Но посмотрим, посмотрим...
V>В GCC аналогично.
Отож.
V>Т.е. в реальных проектах, где никто в здравом уме никогда не сравнивает this с nullptr, а передаёт его куда-то дальше, где уже и возникает ошибка, Clang никак не помогает.
С чего вы взяли, что "где-то уже" будет происходить ошибка? Покажите мне ошибку в коде Holder.
В реальных проектах такой код упадёт в рантайме, несмотря на интуитивно понятную логику и наличие проверки на null.
V>Ты допускаешь ill-formed код в своих рассуждениях, просто ждешь от компилятора некоей предсказуемой реакции на такой код в рантайм.
V>Т.е. утекание ошибки в продакшен — "а чо такого?" ))
Ну так вы же ровно этого же хотите от дотнета — чтобы он вам разрешил вызывать методы на null объектах. С т.з. C# это — ill-formed код.
Просто этот ill-formed код всегда ведёт себя предсказуемо. А в плюсах он может себя вести одним способом, а может — другим.
V>Это спор слепого со зрячим.
Да я уже понял.
V>Мы были слепы еще примерно в 90-х. Ближе к концу пошли анализаторы и общее понимание важности well-formed кода.
Ваша слепота частично развеялась за последние несколько дней, но ещё не до конца.
Вот буквально только что, пять дней тому, вы писали:
V>В общем, чем агрессивнее применяемая оптимизация, тем меньше нежданчиков должно сидеть в коде, ес-но.
V>Именно поэтому я вангую, что по мере улучшения оптимизации в дотнете, будет корректироваться и стандарт.
Вы ставите телегу впереди лошади.
V>Помнишь себя в 2004-2005-х годах как ты вещал с трибун: "Представьте, что сейчас вы напишете код, а потом он будет исполняться намного быстре на будущих версиях платформы!!!"
V>Дудки!
Ну так самое забавное, что именно так и произошло. Вы прямо в этой ветке приводите примеры кода, который стал исполняться намного быстрее на будущих версиях платформы.
V>Сначала убери из кода потенциальные ошибки. ))
В дотнете потенциальных ошибок изначально меньше.
V>Например, в дотнете (и особенно в Джаве) есть ошибки, когда в метод подают не копию объекта, а сам объект, т.е. провоцируют убегание побочных эффектов, а компилятор помочь не может, т.к. он понятия не имеет о семантике.
Это вы сейчас про defensive copying или про что? Мне прямо интересно, есть ли пределы вашей некомпетентности.
V>Для тебя это ликбез.
Ложные утверждения ликбезом быть не могут.
S>>Нет, компилятору совершенно всё равно, есть ли в коде шаблоны или нет. Он прекрасно оптимизирует и вот такую функцию:
S>>
S>>bool is_max(long a) { return (a+1) < a; }
S>>
V>Define "оптимизирует"? ))
Оставляет от всего кода xor eax, eax.
V>Оптимизаций много разных.
О, началось виляние.
V>"Вся оптимизация" — это какая?
Примерно вся. Распространение констант, инлайн вызовов, разворачивание и разгрузка циклов, алгебраические тождества, приведение подобных — я вспотею перечислять.
S>>Поэтому правильный ответ на вопрос "зачем" — для максимизации производительности.
V>Это делает простая бета-редукция и тотальный инлайн.
Есть множество техник оптимизации, и большинство посвящены именно что ускорению кода.
S>>Если компилятор не будет делать таких оптимизаций, то по бенчмаркам его код будет проигрывать конкурентам.
V>Рассуждения уровня детсада.
V>То ты рассуждаешь о решении уравнений, то совсем уж направление рукой показываешь.
V>Ты хоть понял, почему твоё "уравнение" компилятор и не думал решать?
Я? Нет, не понял. Поясните своими словами.
V>Шаблонного/инлайного, а не любого.
Из любого. Я же вам дал ссылку на код, где инлайна нет, а устранение арифметики — есть.
Инлайн просто протаскивает оптимизацию на один шаг дальше, позволяя устранить не только арифметику, но и бранч.
V>Это результат стандартной бета-редкции, но она возможна только до неких установленных пределов своего распространения
Вообще, вы применяете термины не по назначению. Все редукции определены для лямбда-исчисления, где у функций нет побочных эффектов. В императивном программировании примитивы другие, поэтому такими терминами компиляторщики не пользуются.
V>Ты лучше пройдись по полному списку флагов оптимизации, если решил перечислить их все — там многие десятки флагов.
Отож.
V>Мы тут рассуждали чуть о другом — почему компилятор ведёт себя определённым образом при обнаружении UB?
V>И ответ там на поверхности, вообще-то.
Ну, так я его вам дал восемь постов назад.
V>И почему же в дотнете не превратилась?
Я же вам объяснил — потому что в дотнете нет UB.
V>Т.е., когда подаёшь костанту — оно даёт сразу ответ, бо JIT и AOT инлайнят маленькие методы, т.е. производят небольшую бета-редукцию.
V>Но почему в теле ф-ии остались честные вычисления от параметров? ))
Потому, что в дотнете эта функция возвращает true только для одного значения — int.MaxValue. А для всех остальных она, в соответствии со стандартом, возвращает false.
И точно так же себя ведут плюсы, когда тип аргумента не позволяет UB.
V>Это прямое следствие того, что дотнет не имеет права оптимизировать код на уровне байт-кода.
Вы продолжаете феерически тупить. Я такого давно не видел.
V>Плюсы без агрессивных оптимизаций тоже дают верный код, как и дотнет.
Плюсы дают верный код и с агрессивными оптимизациями. Просто он верный с т.з. стандарта.
V>Вопрос здесь не почему исполняет в случае знаковых, а почему именно так?
Повторю вопрос: почему С++ с агрессивными оптимизациями не превратил is_max<unsigned long> в xor eax, eax?
V>Я ведь ниже дал хороший пример, который должен был объяснить логику разруливания UB.
Нет, не дали.
V>Ну, значит не запрограммировали оптимизацию того уникального случая, когда прибавляют единицу и сравнивают.
А для long, значит, запрограммировали?
Всё ещё хуже, чем я думал.
V>Если прибавлять двойку — уже два сравнения, больше — больше.
Это вы вообще о чём? Какие два сравнения?
V>Беззнаковые "по кругу" переполняют произвольными приращениями, это популярная техника для табличных генераторов (случайных чисел, шума, гармоник и т.д.)
Понятно. Я сдаюсь — вы не способны понять правильный ответ, даже если в него ткнуть носом.
V>Хотя, callvirt достаточно было порождать лишь для внешних зависимостей, которые имеют право чуть отличаться на момент компиляции и рантайма.
Это — досужие рассуждения. Было принято осознанное решение, в котором ошибкой является вызов метода на null-объекте, а не дереференсинг this.
V>Эдак тебя заносит. ))
V>Причина ранней диагностики ошибки по твоей ссылке понятна, когда еще не были развиты наработки по escape analisys.
V>А если this не уходит дальше, как в примере?
V>Почему дотнетные компилятор/JIt/AOT неспособны сделать escape analysis для простейших случаев?
JIT и AOT не имеют права это делать. Потому что семантика инструкции callvirt прописана в стандарте, и отклонение от неё — это бага.
А C# принял такое решение. Что непонятного-то?
V>Джава с такими вещами хорошо справляется уже лет 15, если не больше.
V>В рантайме в джаве, если код пойдёт по ошибочной ветке, будет просто выброшено исключение, а основная ветка выполнится без создания ненужного экземпляра объекта.
И в дотнете "основная ветка" выполнится без создания ненужного экземпляра объекта. А если код пойдёт по ошибочной ветке, будет просто выброшено исключение. В чём вы тут увидели разницу?
V>И, чтобы уж закрыть тему, в C# происходит проверка на null дважды: первый раз "по правилам хорошего тона" в начале ф-ий проверяются аргументы или в коде проверяются возвращаемые значения джругих методов. Второй раз проверка происходит на уровне системы как в моём примере.
Покажите пример, где дотнет проверяет на null дважды.
V>Новомодные nullable-нотации не помогают сэкономить на "системных" проверках аж никак, они помогают сэкономить только на юзверских проверках.
Всё верно, так и должно быть.
V>Т.е. nullable-подход в дотнете не является строгим. Ты можешь вернуть null или подать null в кач-ве аргумента, даже если те описаны как non-nullable.
Именно. Потому что нет гарантий, что код по обе стороны вызова скомпилирован с одной и той же конфигурацией нуллабельности.
V>И одновременно с этим обрезает оптимизации, т.е. не позволяет выкидывать ненужный код. ))
Какой именно?
V>Во всей этой истории я зацепился из-за твоего любимого взятого тона в адрес плюсов, мол, херня какая-то происходит.
V>Нет, не херня. В каждом конкретном случае или никакой оптимизации при UB не происходит вовсе (как в MSVC), либо происходит такая оптимизация, которая считает, что ошибочная ситуация произойти не должна.
Ну так это и есть херня, т.к. поведение кода радикально меняется при оптимизации и без неё. В итоге можно успешно отлаживаться, а в релизе получить булшит.
Вот вы только что с гордостью привели пример, как здорово работает код с UB в MSVC. Ну так это и провоцирует писать код в стиле приведённого мной примера — "а чо, я же знаю, что на самом деле будет происходить!".
V>Clang традиционно более щепетилен — поэтому он всегда создаёт ненужный объект в моём сниппете.
V>Но Clang — это не про производительность, это некий референс плюсов как таковых.
С тех пор, как он переехал на LLVM, он по производительности не сильно хуже gcc.
V>GCC — это существо из рил ворлд, поэтому исследует объекты на предмет побочных эффектов и убегания зависимостей, и если их нет — может "уничтожать" объекты, т.е. не конструировать их вовсе, а брать только описанную функциональность. Единственным "побочным эффектом" тут будет лишнее выделение памяти аккурат перед AV, что побочным эффектом не очень-то и считается.
Тут нет выделения памяти перед AV.
V>Лично меня тут удивило чуть другое — когда-то MSVC в деле оптимизаций драл GCC в хвост и гриву, а сейчас малость сдал позиции...
V>Но посмотрим, посмотрим...
V>В GCC аналогично.
Отож.
V>Т.е. в реальных проектах, где никто в здравом уме никогда не сравнивает this с nullptr, а передаёт его куда-то дальше, где уже и возникает ошибка, Clang никак не помогает.
С чего вы взяли, что "где-то уже" будет происходить ошибка? Покажите мне ошибку в коде Holder.
В реальных проектах такой код упадёт в рантайме, несмотря на интуитивно понятную логику и наличие проверки на null.
V>Ты допускаешь ill-formed код в своих рассуждениях, просто ждешь от компилятора некоей предсказуемой реакции на такой код в рантайм.
V>Т.е. утекание ошибки в продакшен — "а чо такого?" ))
Ну так вы же ровно этого же хотите от дотнета — чтобы он вам разрешил вызывать методы на null объектах. С т.з. C# это — ill-formed код.
Просто этот ill-formed код всегда ведёт себя предсказуемо. А в плюсах он может себя вести одним способом, а может — другим.
V>Это спор слепого со зрячим.
Да я уже понял.
V>Мы были слепы еще примерно в 90-х. Ближе к концу пошли анализаторы и общее понимание важности well-formed кода.
Ваша слепота частично развеялась за последние несколько дней, но ещё не до конца.
Вот буквально только что, пять дней тому, вы писали:
То есть не понимали разницы между implementation-specific behavior и undefined behavior. А тут, гляди-ка, недели не прошло — начало брезжить понимание важности well-formed кода.В данном случае ты даёшь оценку своим фантазиям, бо архитектуры/компиляторы явно определяют своё поведение при переполнении.
Т.е. UB тут для стандарта в общем, но не для конкретной связки платформы и компилятора.
V>В общем, чем агрессивнее применяемая оптимизация, тем меньше нежданчиков должно сидеть в коде, ес-но.
V>Именно поэтому я вангую, что по мере улучшения оптимизации в дотнете, будет корректироваться и стандарт.
Вы ставите телегу впереди лошади.
V>Помнишь себя в 2004-2005-х годах как ты вещал с трибун: "Представьте, что сейчас вы напишете код, а потом он будет исполняться намного быстре на будущих версиях платформы!!!"
V>Дудки!
Ну так самое забавное, что именно так и произошло. Вы прямо в этой ветке приводите примеры кода, который стал исполняться намного быстрее на будущих версиях платформы.
V>Сначала убери из кода потенциальные ошибки. ))
В дотнете потенциальных ошибок изначально меньше.
V>Например, в дотнете (и особенно в Джаве) есть ошибки, когда в метод подают не копию объекта, а сам объект, т.е. провоцируют убегание побочных эффектов, а компилятор помочь не может, т.к. он понятия не имеет о семантике.
Это вы сейчас про defensive copying или про что? Мне прямо интересно, есть ли пределы вашей некомпетентности.
Re[36]: Carbon
Здравствуйте, vdimas, Вы писали:
V>Для тебя это ликбез.
Ложные утверждения ликбезом быть не могут.
S>>Нет, компилятору совершенно всё равно, есть ли в коде шаблоны или нет. Он прекрасно оптимизирует и вот такую функцию:
S>>
V>Define "оптимизирует"? ))
Оставляет от всего кода xor eax, eax.
V>Оптимизаций много разных.
О, началось виляние.
V>"Вся оптимизация" — это какая?
Примерно вся. Распространение констант, инлайн вызовов, разворачивание и разгрузка циклов, алгебраические тождества, приведение подобных — я вспотею перечислять.
S>>Поэтому правильный ответ на вопрос "зачем" — для максимизации производительности.
V>Это делает простая бета-редукция и тотальный инлайн.
Есть множество техник оптимизации, и большинство посвящены именно что ускорению кода.
S>>Если компилятор не будет делать таких оптимизаций, то по бенчмаркам его код будет проигрывать конкурентам.
V>Рассуждения уровня детсада.
V>То ты рассуждаешь о решении уравнений, то совсем уж направление рукой показываешь.
V>Ты хоть понял, почему твоё "уравнение" компилятор и не думал решать?
Я? Нет, не понял. Поясните своими словами.
V>Шаблонного/инлайного, а не любого.
Из любого. Я же вам дал ссылку на код, где инлайна нет, а устранение арифметики — есть.
Инлайн просто протаскивает оптимизацию на один шаг дальше, позволяя устранить не только арифметику, но и бранч.
V>Это результат стандартной бета-редкции, но она возможна только до неких установленных пределов своего распространения
Вообще, вы применяете термины не по назначению. Все редукции определены для лямбда-исчисления, где у функций нет побочных эффектов. В императивном программировании примитивы другие, поэтому такими терминами компиляторщики не пользуются.
V>Ты лучше пройдись по полному списку флагов оптимизации, если решил перечислить их все — там многие десятки флагов.
Отож.
V>Мы тут рассуждали чуть о другом — почему компилятор ведёт себя определённым образом при обнаружении UB?
V>И ответ там на поверхности, вообще-то.
Ну, так я его вам дал восемь постов назад.
V>И почему же в дотнете не превратилась?
Я же вам объяснил — потому что в дотнете нет UB.
V>Т.е., когда подаёшь костанту — оно даёт сразу ответ, бо JIT и AOT инлайнят маленькие методы, т.е. производят небольшую бета-редукцию.
V>Но почему в теле ф-ии остались честные вычисления от параметров? ))
Потому, что в дотнете эта функция возвращает true только для одного значения — int.MaxValue. А для всех остальных она, в соответствии со стандартом, возвращает false.
И точно так же себя ведут плюсы, когда тип аргумента не позволяет UB.
V>Это прямое следствие того, что дотнет не имеет права оптимизировать код на уровне байт-кода.
Вы продолжаете феерически тупить. Я такого давно не видел.
V>Плюсы без агрессивных оптимизаций тоже дают верный код, как и дотнет.
Плюсы дают верный код и с агрессивными оптимизациями. Просто он верный с т.з. стандарта.
V>Вопрос здесь не почему исполняет в случае знаковых, а почему именно так?
Повторю вопрос: почему С++ с агрессивными оптимизациями не превратил is_max<unsigned long> в xor eax, eax?
V>Я ведь ниже дал хороший пример, который должен был объяснить логику разруливания UB.
Нет, не дали.
V>Ну, значит не запрограммировали оптимизацию того уникального случая, когда прибавляют единицу и сравнивают.
А для long, значит, запрограммировали?
Всё ещё хуже, чем я думал.
V>Если прибавлять двойку — уже два сравнения, больше — больше.
Это вы вообще о чём? Какие два сравнения?
V>Беззнаковые "по кругу" переполняют произвольными приращениями, это популярная техника для табличных генераторов (случайных чисел, шума, гармоник и т.д.)
Понятно. Я сдаюсь — вы не способны понять правильный ответ, даже если в него ткнуть носом.
V>Хотя, callvirt достаточно было порождать лишь для внешних зависимостей, которые имеют право чуть отличаться на момент компиляции и рантайма.
Это — досужие рассуждения. Было принято осознанное решение, в котором ошибкой является вызов метода на null-объекте, а не дереференсинг this.
V>Эдак тебя заносит. ))
V>Причина ранней диагностики ошибки по твоей ссылке понятна, когда еще не были развиты наработки по escape analisys.
V>А если this не уходит дальше, как в примере?
V>Почему дотнетные компилятор/JIt/AOT неспособны сделать escape analysis для простейших случаев?
JIT и AOT не имеют права это делать. Потому что семантика инструкции callvirt прописана в стандарте, и отклонение от неё — это бага.
А C# принял такое решение. Что непонятного-то?
V>Джава с такими вещами хорошо справляется уже лет 15, если не больше.
V>В рантайме в джаве, если код пойдёт по ошибочной ветке, будет просто выброшено исключение, а основная ветка выполнится без создания ненужного экземпляра объекта.
И в дотнете "основная ветка" выполнится без создания ненужного экземпляра объекта. А если код пойдёт по ошибочной ветке, будет просто выброшено исключение. В чём вы тут увидели разницу?
V>И, чтобы уж закрыть тему, в C# происходит проверка на null дважды: первый раз "по правилам хорошего тона" в начале ф-ий проверяются аргументы или в коде проверяются возвращаемые значения джругих методов. Второй раз проверка происходит на уровне системы как в моём примере.
Покажите пример, где дотнет проверяет на null дважды.
V>Новомодные nullable-нотации не помогают сэкономить на "системных" проверках аж никак, они помогают сэкономить только на юзверских проверках.
Всё верно, так и должно быть.
V>Т.е. nullable-подход в дотнете не является строгим. Ты можешь вернуть null или подать null в кач-ве аргумента, даже если те описаны как non-nullable.
Именно. Потому что нет гарантий, что код по обе стороны вызова скомпилирован с одной и той же конфигурацией нуллабельности.
V>И одновременно с этим обрезает оптимизации, т.е. не позволяет выкидывать ненужный код. ))
Какой именно?
V>Во всей этой истории я зацепился из-за твоего любимого взятого тона в адрес плюсов, мол, херня какая-то происходит.
V>Нет, не херня. В каждом конкретном случае или никакой оптимизации при UB не происходит вовсе (как в MSVC), либо происходит такая оптимизация, которая считает, что ошибочная ситуация произойти не должна.
Ну так это и есть херня, т.к. поведение кода радикально меняется при оптимизации и без неё. В итоге можно успешно отлаживаться, а в релизе получить булшит.
Вот вы только что с гордостью привели пример, как здорово работает код с UB в MSVC. Ну так это и провоцирует писать код в стиле приведённого мной примера — "а чо, я же знаю, что на самом деле будет происходить!".
V>Clang традиционно более щепетилен — поэтому он всегда создаёт ненужный объект в моём сниппете.
V>Но Clang — это не про производительность, это некий референс плюсов как таковых.
Теперь уже и про производительность. Потому что в LLVM вваливают очень много ресурсов, в том числе — и в оптимизации.
V>GCC — это существо из рил ворлд, поэтому исследует объекты на предмет побочных эффектов и убегания зависимостей, и если их нет — может "уничтожать" объекты, т.е. не конструировать их вовсе, а брать только описанную функциональность. Единственным "побочным эффектом" тут будет лишнее выделение памяти аккурат перед AV, что побочным эффектом не очень-то и считается.
Тут нет выделения памяти перед AV.
V>Лично меня тут удивило чуть другое — когда-то MSVC в деле оптимизаций драл GCC в хвост и гриву, а сейчас малость сдал позиции...
V>Но посмотрим, посмотрим...
V>В GCC аналогично.
Отож.
V>Т.е. в реальных проектах, где никто в здравом уме никогда не сравнивает this с nullptr, а передаёт его куда-то дальше, где уже и возникает ошибка, Clang никак не помогает.
С чего вы взяли, что "где-то уже" будет происходить ошибка? Покажите мне ошибку в коде Holder.
В реальных проектах такой код упадёт в рантайме, несмотря на интуитивно понятную логику и наличие проверки на null.
V>Ты допускаешь ill-formed код в своих рассуждениях, просто ждешь от компилятора некоей предсказуемой реакции на такой код в рантайм.
V>Т.е. утекание ошибки в продакшен — "а чо такого?" ))
Ну так вы же ровно этого же хотите от дотнета — чтобы он вам разрешил вызывать методы на null объектах. С т.з. C# это — ill-formed код.
Просто этот ill-formed код всегда ведёт себя предсказуемо. А в плюсах он может себя вести одним способом, а может — другим.
V>Это спор слепого со зрячим.
Да я уже понял.
V>Мы были слепы еще примерно в 90-х. Ближе к концу пошли анализаторы и общее понимание важности well-formed кода.
Ваша слепота частично развеялась за последние несколько дней, но ещё не до конца.
Вот буквально только что, пять дней тому, вы писали:
V>В общем, чем агрессивнее применяемая оптимизация, тем меньше нежданчиков должно сидеть в коде, ес-но.
V>Именно поэтому я вангую, что по мере улучшения оптимизации в дотнете, будет корректироваться и стандарт.
Вы ставите телегу впереди лошади.
V>Помнишь себя в 2004-2005-х годах как ты вещал с трибун: "Представьте, что сейчас вы напишете код, а потом он будет исполняться намного быстре на будущих версиях платформы!!!"
V>Дудки!
Ну так самое забавное, что именно так и произошло. Вы прямо в этой ветке приводите примеры кода, который стал исполняться намного быстрее на будущих версиях платформы.
V>Сначала убери из кода потенциальные ошибки. ))
В дотнете потенциальных ошибок изначально меньше.
V>Например, в дотнете (и особенно в Джаве) есть ошибки, когда в метод подают не копию объекта, а сам объект, т.е. провоцируют убегание побочных эффектов, а компилятор помочь не может, т.к. он понятия не имеет о семантике.
Это вы сейчас про defensive copying или про что? Мне прямо интересно, есть ли пределы вашей некомпетентности.
V>Для тебя это ликбез.
Ложные утверждения ликбезом быть не могут.
S>>Нет, компилятору совершенно всё равно, есть ли в коде шаблоны или нет. Он прекрасно оптимизирует и вот такую функцию:
S>>
S>>bool is_max(long a) { return (a+1) < a; }
S>>
V>Define "оптимизирует"? ))
Оставляет от всего кода xor eax, eax.
V>Оптимизаций много разных.
О, началось виляние.
V>"Вся оптимизация" — это какая?
Примерно вся. Распространение констант, инлайн вызовов, разворачивание и разгрузка циклов, алгебраические тождества, приведение подобных — я вспотею перечислять.
S>>Поэтому правильный ответ на вопрос "зачем" — для максимизации производительности.
V>Это делает простая бета-редукция и тотальный инлайн.
Есть множество техник оптимизации, и большинство посвящены именно что ускорению кода.
S>>Если компилятор не будет делать таких оптимизаций, то по бенчмаркам его код будет проигрывать конкурентам.
V>Рассуждения уровня детсада.
V>То ты рассуждаешь о решении уравнений, то совсем уж направление рукой показываешь.
V>Ты хоть понял, почему твоё "уравнение" компилятор и не думал решать?
Я? Нет, не понял. Поясните своими словами.
V>Шаблонного/инлайного, а не любого.
Из любого. Я же вам дал ссылку на код, где инлайна нет, а устранение арифметики — есть.
Инлайн просто протаскивает оптимизацию на один шаг дальше, позволяя устранить не только арифметику, но и бранч.
V>Это результат стандартной бета-редкции, но она возможна только до неких установленных пределов своего распространения
Вообще, вы применяете термины не по назначению. Все редукции определены для лямбда-исчисления, где у функций нет побочных эффектов. В императивном программировании примитивы другие, поэтому такими терминами компиляторщики не пользуются.
V>Ты лучше пройдись по полному списку флагов оптимизации, если решил перечислить их все — там многие десятки флагов.
Отож.
V>Мы тут рассуждали чуть о другом — почему компилятор ведёт себя определённым образом при обнаружении UB?
V>И ответ там на поверхности, вообще-то.
Ну, так я его вам дал восемь постов назад.
V>И почему же в дотнете не превратилась?
Я же вам объяснил — потому что в дотнете нет UB.
V>Т.е., когда подаёшь костанту — оно даёт сразу ответ, бо JIT и AOT инлайнят маленькие методы, т.е. производят небольшую бета-редукцию.
V>Но почему в теле ф-ии остались честные вычисления от параметров? ))
Потому, что в дотнете эта функция возвращает true только для одного значения — int.MaxValue. А для всех остальных она, в соответствии со стандартом, возвращает false.
И точно так же себя ведут плюсы, когда тип аргумента не позволяет UB.
V>Это прямое следствие того, что дотнет не имеет права оптимизировать код на уровне байт-кода.
Вы продолжаете феерически тупить. Я такого давно не видел.
V>Плюсы без агрессивных оптимизаций тоже дают верный код, как и дотнет.
Плюсы дают верный код и с агрессивными оптимизациями. Просто он верный с т.з. стандарта.
V>Вопрос здесь не почему исполняет в случае знаковых, а почему именно так?
Повторю вопрос: почему С++ с агрессивными оптимизациями не превратил is_max<unsigned long> в xor eax, eax?
V>Я ведь ниже дал хороший пример, который должен был объяснить логику разруливания UB.
Нет, не дали.
V>Ну, значит не запрограммировали оптимизацию того уникального случая, когда прибавляют единицу и сравнивают.
А для long, значит, запрограммировали?
Всё ещё хуже, чем я думал.
V>Если прибавлять двойку — уже два сравнения, больше — больше.
Это вы вообще о чём? Какие два сравнения?
V>Беззнаковые "по кругу" переполняют произвольными приращениями, это популярная техника для табличных генераторов (случайных чисел, шума, гармоник и т.д.)
Понятно. Я сдаюсь — вы не способны понять правильный ответ, даже если в него ткнуть носом.
V>Хотя, callvirt достаточно было порождать лишь для внешних зависимостей, которые имеют право чуть отличаться на момент компиляции и рантайма.
Это — досужие рассуждения. Было принято осознанное решение, в котором ошибкой является вызов метода на null-объекте, а не дереференсинг this.
V>Эдак тебя заносит. ))
V>Причина ранней диагностики ошибки по твоей ссылке понятна, когда еще не были развиты наработки по escape analisys.
V>А если this не уходит дальше, как в примере?
V>Почему дотнетные компилятор/JIt/AOT неспособны сделать escape analysis для простейших случаев?
JIT и AOT не имеют права это делать. Потому что семантика инструкции callvirt прописана в стандарте, и отклонение от неё — это бага.
А C# принял такое решение. Что непонятного-то?
V>Джава с такими вещами хорошо справляется уже лет 15, если не больше.
V>В рантайме в джаве, если код пойдёт по ошибочной ветке, будет просто выброшено исключение, а основная ветка выполнится без создания ненужного экземпляра объекта.
И в дотнете "основная ветка" выполнится без создания ненужного экземпляра объекта. А если код пойдёт по ошибочной ветке, будет просто выброшено исключение. В чём вы тут увидели разницу?
V>И, чтобы уж закрыть тему, в C# происходит проверка на null дважды: первый раз "по правилам хорошего тона" в начале ф-ий проверяются аргументы или в коде проверяются возвращаемые значения джругих методов. Второй раз проверка происходит на уровне системы как в моём примере.
Покажите пример, где дотнет проверяет на null дважды.
V>Новомодные nullable-нотации не помогают сэкономить на "системных" проверках аж никак, они помогают сэкономить только на юзверских проверках.
Всё верно, так и должно быть.
V>Т.е. nullable-подход в дотнете не является строгим. Ты можешь вернуть null или подать null в кач-ве аргумента, даже если те описаны как non-nullable.
Именно. Потому что нет гарантий, что код по обе стороны вызова скомпилирован с одной и той же конфигурацией нуллабельности.
V>И одновременно с этим обрезает оптимизации, т.е. не позволяет выкидывать ненужный код. ))
Какой именно?
V>Во всей этой истории я зацепился из-за твоего любимого взятого тона в адрес плюсов, мол, херня какая-то происходит.
V>Нет, не херня. В каждом конкретном случае или никакой оптимизации при UB не происходит вовсе (как в MSVC), либо происходит такая оптимизация, которая считает, что ошибочная ситуация произойти не должна.
Ну так это и есть херня, т.к. поведение кода радикально меняется при оптимизации и без неё. В итоге можно успешно отлаживаться, а в релизе получить булшит.
Вот вы только что с гордостью привели пример, как здорово работает код с UB в MSVC. Ну так это и провоцирует писать код в стиле приведённого мной примера — "а чо, я же знаю, что на самом деле будет происходить!".
V>Clang традиционно более щепетилен — поэтому он всегда создаёт ненужный объект в моём сниппете.
V>Но Clang — это не про производительность, это некий референс плюсов как таковых.
Теперь уже и про производительность. Потому что в LLVM вваливают очень много ресурсов, в том числе — и в оптимизации.
V>GCC — это существо из рил ворлд, поэтому исследует объекты на предмет побочных эффектов и убегания зависимостей, и если их нет — может "уничтожать" объекты, т.е. не конструировать их вовсе, а брать только описанную функциональность. Единственным "побочным эффектом" тут будет лишнее выделение памяти аккурат перед AV, что побочным эффектом не очень-то и считается.
Тут нет выделения памяти перед AV.
V>Лично меня тут удивило чуть другое — когда-то MSVC в деле оптимизаций драл GCC в хвост и гриву, а сейчас малость сдал позиции...
V>Но посмотрим, посмотрим...
V>В GCC аналогично.
Отож.
V>Т.е. в реальных проектах, где никто в здравом уме никогда не сравнивает this с nullptr, а передаёт его куда-то дальше, где уже и возникает ошибка, Clang никак не помогает.
С чего вы взяли, что "где-то уже" будет происходить ошибка? Покажите мне ошибку в коде Holder.
В реальных проектах такой код упадёт в рантайме, несмотря на интуитивно понятную логику и наличие проверки на null.
V>Ты допускаешь ill-formed код в своих рассуждениях, просто ждешь от компилятора некоей предсказуемой реакции на такой код в рантайм.
V>Т.е. утекание ошибки в продакшен — "а чо такого?" ))
Ну так вы же ровно этого же хотите от дотнета — чтобы он вам разрешил вызывать методы на null объектах. С т.з. C# это — ill-formed код.
Просто этот ill-formed код всегда ведёт себя предсказуемо. А в плюсах он может себя вести одним способом, а может — другим.
V>Это спор слепого со зрячим.
Да я уже понял.
V>Мы были слепы еще примерно в 90-х. Ближе к концу пошли анализаторы и общее понимание важности well-formed кода.
Ваша слепота частично развеялась за последние несколько дней, но ещё не до конца.
Вот буквально только что, пять дней тому, вы писали:
То есть не понимали разницы между implementation-specific behavior и undefined behavior. А тут, гляди-ка, недели не прошло — начало брезжить понимание важности well-formed кода.В данном случае ты даёшь оценку своим фантазиям, бо архитектуры/компиляторы явно определяют своё поведение при переполнении.
Т.е. UB тут для стандарта в общем, но не для конкретной связки платформы и компилятора.
V>В общем, чем агрессивнее применяемая оптимизация, тем меньше нежданчиков должно сидеть в коде, ес-но.
V>Именно поэтому я вангую, что по мере улучшения оптимизации в дотнете, будет корректироваться и стандарт.
Вы ставите телегу впереди лошади.
V>Помнишь себя в 2004-2005-х годах как ты вещал с трибун: "Представьте, что сейчас вы напишете код, а потом он будет исполняться намного быстре на будущих версиях платформы!!!"
V>Дудки!
Ну так самое забавное, что именно так и произошло. Вы прямо в этой ветке приводите примеры кода, который стал исполняться намного быстрее на будущих версиях платформы.
V>Сначала убери из кода потенциальные ошибки. ))
В дотнете потенциальных ошибок изначально меньше.
V>Например, в дотнете (и особенно в Джаве) есть ошибки, когда в метод подают не копию объекта, а сам объект, т.е. провоцируют убегание побочных эффектов, а компилятор помочь не может, т.к. он понятия не имеет о семантике.
Это вы сейчас про defensive copying или про что? Мне прямо интересно, есть ли пределы вашей некомпетентности.