Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upTeach rustc to do tail calls #217
Comments
This comment has been minimized.
This comment has been minimized.
|
Per Graydon, we need to do some more thinking about calling conventions before implementing this. LLVM requires the fastcc convention to implement tail calls, but it doesn't do quite what we want: graydon: brson: judging from comments in llvm-land, we may be in trouble. we might be able to compensate for what fastcc is doing today, but it's allowed to change its mind tomorrow. |
This comment has been minimized.
This comment has been minimized.
|
This is currently half-implemented due to some complications in the way LLVM treats tail calls. Rustc parses 'be' expressions and translates them as call+ret pairs, which is enough to get us to 'working' on simple, not-very-deep cases. Might be enough to bootstrap. There is apparently only one CC (fastcc) which supports guaranteed tail calls, and to adapt to it we need to change our ABI assumptions in several places (it turns into callee-restore when you enable the -tailcallopt flag). So even if we annotate our call+ret pairs with 'tail', as required, we can't actually tell LLVM to start performing that optimization yet. |
This comment has been minimized.
This comment has been minimized.
|
Turned out not to need more implementation than is shown here for self-hosting. Punting to next milestone. |
ghost
assigned
espindola
May 5, 2011
brson
referenced this issue
Nov 28, 2011
Closed
foo(...)->f as b should be tail callable if both are aliases of the same type #1215
This comment has been minimized.
This comment has been minimized.
|
Anyone feel we're actually going to do this anymore? |
This comment has been minimized.
This comment has been minimized.
|
Doesn't seem like it's going to happen. |
This comment has been minimized.
This comment has been minimized.
|
What is the situation with LLVM and tail calls? If they can be made to reliably work without some invasive stuff like declaring the callee to be tail-called, we could define a limited set of things that can be passed to tail-calls (caller's own arguments, scalars), and error when something else is passed. Such tail calls might not be very useful in practice, though. |
This comment has been minimized.
This comment has been minimized.
kud1ing
commented
Dec 18, 2011
|
Is it possible that looking at Haskell's GHC LLVM-backend might be helpful? http://hackage.haskell.org/trac/ghc/wiki/Commentary/Compiler/Backends/LLVM |
This comment has been minimized.
This comment has been minimized.
|
They only work with a callee ABI that is suboptimal in non-tail-call cases. So in a sense, yes, they require the callee to be declared-to-be-tail-called. We could implement this by, say, analyzing a crate and when we find a function that is tail called, either separately compiling it under the friendly-to-tail-call ABI, or compiling wrappers that switch ABI on entry, or something. Or alternatively we can switch every function everywhere to using the tail-call-friendly ABI. I'm not sure if we're currently doing that. We were for a while but we may have stopped. It's the LLVM "fastcall" ABI, which I don't think we're using anymore. In any case, it's a bit of a mess. |
ghost
assigned
graydon
Mar 15, 2012
This comment has been minimized.
This comment has been minimized.
|
We have sibling call optimization, now. Are we planning to try to do more? |
This comment has been minimized.
This comment has been minimized.
catamorphism
closed this
Jul 21, 2012
This comment has been minimized.
This comment has been minimized.
|
This continues to come up in conversation, and we've reserved |
brson
reopened this
Sep 28, 2012
catamorphism
referenced this issue
Oct 8, 2012
Closed
Make recursing too deep a fatal runtime error and make the limit larger #3695
This comment has been minimized.
This comment has been minimized.
|
I think Graydon's comment on the mailing list: https://mail.mozilla.org/pipermail/rust-dev/2013-April/003557.html puts a nail in this coffin. Reproduced here: On 10/04/2013 5:43 AM, Artella Coding wrote:
No, and it very likely won't. We have a longstanding bug on this: as well as a wiki page and several mailing list threads: https://github.com/mozilla/rust/wiki/Bikeshed-tailcall The summary of all this is:
I'm sorry to be saying all this, and it is with a heavy heart, but we -Graydon
|
bstrie
closed this
Apr 10, 2013
graydon
removed their assignment
Jun 16, 2014
This comment has been minimized.
This comment has been minimized.
burdges
commented
Jul 31, 2015
|
It's maybe worth noting that Haskell commonly needs a static argument transformation for inlining, fusion, etc. http://stackoverflow.com/a/9660027/667457 Rust could support the static argument transformation by saying that functions defined inside another function should be elidgible for tailcall optimizations. Or simply warn if tailcalls between functions nested inside another fuction failed sibling optimization. Not sure the current situation. |
This comment has been minimized.
This comment has been minimized.
Boiethios
commented
Jul 20, 2016
|
It is sad the tail recursion will not be implemented. Then I have a question: why creating a language syntax that seems like a functional language syntax if there lacks an essential feature of functional? |
This comment has been minimized.
This comment has been minimized.
Stargateur
commented
Aug 3, 2016
•
|
I'm news in rust and I'm very sad. I try a tail recursive function and I stack overflow so fast. worst when I compile in release the behavior change. He just don't call my function. A friend said to me that the LLVM optimize to undefined value (LLVM know that is a tail recursion infinite ?!?). fn rec(i: i32) {
rec(i + 1)
}
fn main() {
println!("{}", rec(0));
}I agree with Boiethios, a language with functional features who doesn't implement tail call miss something. I write in C and C++, they don't guarantee tail call, but in fact they handle it very well. It's not gonna stop me to learn rust, now I know that rust doesn't handle it. I will code without so it's not a big problem. But I think that is a very good feature for a modern language. notice that fn rec(i: i32) {
println!("Hello");
rec(i + 1)
}stack overflow too in release mode of cargo |
This comment has been minimized.
This comment has been minimized.
|
We have plans to eventually implement guaranteed TCO, if possible. We even reserved a keyword for it, "become". Please check the RFCs repo. On Aug 3, 2016, 19:46 -0400, Antoine PLASKOWSKI notifications@github.com, wrote:
|
telkkar
added a commit
to telkkar/rust_playing_around
that referenced
this issue
Dec 5, 2016
This comment has been minimized.
This comment has been minimized.
timthelion
commented
Mar 23, 2017
|
Just a question: It is hypothetically possible to do call graph analysis and transform tail calls into loops, at least within a single crate, but it is computationally expensive at compile time and quite tricky to code. Was there any discussion of this possibility? That would still be an option now, without regard to the choice of calling convention. |
keeperofdakeys
pushed a commit
to keeperofdakeys/rust
that referenced
this issue
Dec 12, 2017
This comment has been minimized.
This comment has been minimized.
ewtoombs
commented
Jan 29, 2018
|
lbstanza's approach is to require annotation of functions to make them eligible for TCO (defn+ instead of defn). In rust, that would largely mitigate the extra compile time overhead to timthelion's suggestion, just so long as you aren't using tail calls literally everywhere lol. |
graydon commentedJan 27, 2011
Rustc doesn't know how to do tail calls ('be' rather than 'ret') yet. It shouldn't be too hard to teach it how.