Rustc еще не знает, как делать хвостовые вызовы («be», а не «ret»). Научить этому не должно быть слишком сложно.
Согласно Грейдону, нам нужно еще немного подумать о соглашениях о вызовах, прежде чем реализовывать это. LLVM требует соглашения fastcc для реализации хвостовых вызовов, но это не совсем то, что нам нужно:
greydon: brson: судя по комментариям в llvm-land, у нас могут быть проблемы. мы могли бы компенсировать то, что fastcc делает сегодня, но завтра ему позволено передумать.
greydon: Я думал, что fastcc == x86_fastcall, но ошибся.
грейдон: это разные соглашения о вызовах. fastcc - это "все, что llvm чувствует на этой неделе"
Graydon: нам нужно переключиться на x86_fastcall, а затем, в долгосрочной перспективе, написать собственное соглашение о вызовах.
В настоящее время это реализовано наполовину из-за некоторых сложностей в том, как LLVM обрабатывает хвостовые вызовы. Rustc анализирует выражения «be» и переводит их в пары call+ret, чего достаточно, чтобы заставить нас «работать» над простыми, не очень глубокими случаями. Может быть достаточно для начальной загрузки.
По-видимому, существует только один CC (fastcc), который поддерживает гарантированные вызовы хвоста, и чтобы адаптироваться к нему, нам нужно изменить наши предположения ABI в нескольких местах (он превращается в callee-restore, когда вы включаете флаг -tailcallopt). Таким образом, даже если мы аннотируем наши пары call+ret как «хвост», как требуется, мы не можем сказать LLVM, чтобы он начал выполнять эту оптимизацию.
Оказалось, что для самостоятельного хостинга не требуется больше реализации, чем показано здесь. Переход к следующей вехе.
Кто-нибудь думает, что мы на самом деле собираемся делать это больше?
Не похоже, что это произойдет.
Как обстоят дела с LLVM и хвостовыми вызовами? Если бы их можно было заставить надежно работать без каких-либо инвазивных вещей, таких как объявление вызываемого объекта хвостовым вызовом, мы могли бы определить ограниченный набор вещей, которые могут быть переданы хвостовым вызовам (собственные аргументы вызывающего объекта, скаляры), и ошибка, когда что-то остальное пройдено. Однако такие хвостовые вызовы могут оказаться не очень полезными на практике.
Возможно ли, что просмотр бэкенда Haskell GHC LLVM может быть полезен?
http://hackage.haskell.org/trac/ghc/wiki/Commentary/Compiler/Backends/LLVM
http://llvm.org/docs/LangRef.html#callingconv
http://llvm.org/docs/CodeGenerator.html#tailcallopt
Они работают только с вызываемым ABI, который является неоптимальным в случаях без хвостового вызова. Так что в некотором смысле да, они требуют, чтобы вызываемый объект был объявлен как хвостовой вызов.
Мы могли бы реализовать это, скажем, проанализировав крейт, и когда мы находим функцию, вызываемую хвостом, либо отдельно скомпилировав ее под дружественным к хвостовому вызову ABI, либо скомпилировав обертки, которые переключают ABI при входе, или что-то в этом роде. Или, в качестве альтернативы, мы можем переключить _every_ функцию везде на использование ABI, удобного для хвостового вызова. Я не уверен, делаем ли мы это сейчас. Мы были на некоторое время, но мы, возможно, остановились. Это LLVM «fastcall» ABI, который, я думаю, мы больше не используем.
В любом случае, это немного беспорядок.
Теперь у нас есть оптимизация одноуровневых вызовов. Планируем ли мы попытаться сделать больше?
Не произойдет, за исключением случаев, указанных в #2216. Решение для #2216 должно быть достаточно широким, чтобы поддерживать кодирование общего конечного автомата.
Это продолжает всплывать в разговорах, и мы снова зарезервировали be
. Открытие.
Я думаю, что комментарий Грейдона в списке рассылки:
https://mail.mozilla.org/pipermail/rust-dev/2013-April/003557.html
вбивает гвоздь в этот гроб. Воспроизведено здесь:
04.10.2013, 5:43, Artella Coding пишет:
Привет, ржавчина делает оптимизацию хвостового вызова? Причина, по которой я спрашиваю, заключается в том, что
следующая рекурсивная реализация хвостового вызова приводит к стеку
переполнение. Спасибо.
Нет, и, скорее всего, не будет. У нас есть давняя ошибка:
https://github.com/mozilla/rust/issues/217
а также вики-страницу и несколько веток списка рассылки:
https://github.com/mozilla/rust/wiki/Bikeshed-tailcall
https://mail.mozilla.org/pipermail/rust-dev/2011-August/000689.html
https://mail.mozilla.org/pipermail/rust-dev/2012-January/001280.html
...
Итог всего этого таков:
Мне жаль говорить все это, и это с тяжелым сердцем, но мы
пытался и не нашел способ сделать компромиссы, связанные с ними
подведите итог аргументу для включения в ржавчину.
-Грейдон
Возможно, стоит отметить, что Haskell обычно требует преобразования статического аргумента для встраивания, слияния и т. д. http://stackoverflow.com/a/9660027/667457
Rust мог бы поддерживать преобразование статического аргумента, говоря, что функции, определенные внутри другой функции, должны иметь право на оптимизацию хвостового вызова. Или просто предупредите, если хвостовые вызовы между функциями, вложенными в другую функцию, не увенчались успехом при оптимизации родственного элемента. Не уверен в текущей ситуации.
Жаль, что хвостовая рекурсия реализована не будет. Тогда у меня возникает вопрос: зачем создавать синтаксис языка, который выглядит как синтаксис функционального языка, если в нем отсутствует существенная особенность функционала?
Я новости в ржавчине, и мне очень грустно. Я пробую хвостовую рекурсивную функцию, и я так быстро переполняю стек. худшее, когда я компилирую в выпуске изменение поведения. Он просто не вызывает мою функцию. Друг сказал мне, что LLVM оптимизирует до неопределенного значения (LLVM знает, что хвостовая рекурсия бесконечна?!?).
fn rec(i: i32) {
rec(i + 1)
}
fn main() {
println!("{}", rec(0));
}
Я согласен с Boiethios, языком с функциональными возможностями, который не реализует хвостовой вызов.
Я пишу на C и C++, они не гарантируют хвостовой вызов, но на самом деле очень хорошо с этим справляются. Меня не остановит изучение ржавчины, теперь я знаю, что ржавчина с этим не справится. Я буду кодировать без так что это не большая проблема.
Но я думаю, что это очень хорошая особенность для современного языка.
Заметь
fn rec(i: i32) {
println!("Hello");
rec(i + 1)
}
переполнение стека тоже в режиме выпуска груза
У нас есть планы в конечном итоге реализовать гарантированную совокупную стоимость владения, если это возможно. Мы даже зарезервировали для него ключевое слово «стать». Пожалуйста, проверьте репозиторий RFC.
3 августа 2016 г., 19:46 -04:00, Антуан ПЛАСКОВСКИЙ , [email protected], написал:
Я новости в ржавчине, и мне очень грустно. Я пробую хвостовую рекурсивную функцию, и я так быстро переполняю стек. худшее, когда я компилирую в выпуске изменение поведения. Он просто не вызывает мою функцию. Друг сказал мне, что LLVM оптимизируется до неопределенного значения (LLVM знает, что хвостовая рекурсия бесконечна?!?).
fn rec(i: i32) { rec(i + 1) } fn main() { println!("{}", rec(0)); }
Я согласен с Boiethios, языком с функциональными возможностями, который не реализует хвостовой вызов.
Я пишу на C и C++, они не гарантируют хвостовой вызов, но на самом деле они очень хорошо с этим справляются. Это не помешает мне изучить ржавчину, теперь я знаю, что ржавчина не справляется с этим, я буду кодировать без нее, так что это не большая проблема.
Но я думаю, что это очень хорошая особенность для современного языка.
—
Вы получаете это, потому что подписаны на эту тему.
Ответьте на это письмо напрямую, просмотрите его на GitHub (https://github.com/rust-lang/rust/issues/217#issuecomment-237409642) или отключите ветку (https://github.com/notifications/unsubscribe). -auth/AABsipoedHrbnKDekmzCr-dl8M6g-Gojks5qcShKgaJpZM4AC-q_).
Просто вопрос: гипотетически возможно выполнить анализ графа вызовов и преобразовать хвостовые вызовы в циклы, по крайней мере, в пределах одного ящика, но это требует больших вычислительных ресурсов во время компиляции и довольно сложно кодировать. Было ли обсуждение этой возможности? Это все еще будет вариантом сейчас, независимо от выбора соглашения о вызовах.
Подход lbstanza заключается в том, чтобы требовать аннотации функций, чтобы сделать их подходящими для TCO (defn+ вместо defn). В ржавчине это в значительной степени уменьшит дополнительные накладные расходы на компиляцию по предложению timthelion, просто до тех пор, пока вы не используете хвостовые вызовы буквально везде, лол.
Самый полезный комментарий
У нас есть планы в конечном итоге реализовать гарантированную совокупную стоимость владения, если это возможно. Мы даже зарезервировали для него ключевое слово «стать». Пожалуйста, проверьте репозиторий RFC.
3 августа 2016 г., 19:46 -04:00, Антуан ПЛАСКОВСКИЙ , [email protected], написал: