[rust-dev] compiling Rust to C?
Is there any prospect of compiling Rust to C anytime in the mid to near future? This would be a really attractive option for anyone who wants to write in Rust, but wants the extreme portability of C. Actually maybe I should first ask if this is actually a tractable problem. Are there technical reasons that would prevent compiling Rust into portable C? LLVM's C Backend seems to have fallen out of maintenance -- would this provide the solution I am looking for, if it were maintained? Thanks, Josh ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] compiling Rust to C?
The biggest problem would be probably be handling stack unwinding (IIRC the LLVM C backend never tried to handle this either). The only option when targeting C is to use setjmp / longjmp, but that is going to be pretty inefficient. Alternatively you could just abort instead of unwinding. Cameron On Jul 18, 2014, at 12:29 AM, Josh Haberman jhaber...@gmail.com wrote: Is there any prospect of compiling Rust to C anytime in the mid to near future? This would be a really attractive option for anyone who wants to write in Rust, but wants the extreme portability of C. Actually maybe I should first ask if this is actually a tractable problem. Are there technical reasons that would prevent compiling Rust into portable C? LLVM's C Backend seems to have fallen out of maintenance -- would this provide the solution I am looking for, if it were maintained? Thanks, Josh ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Requesting information (about globs, macros, subtyping)
On Jul 16, 2014, at 10:54 AM, Gábor Lehel glaebho...@gmail.com wrote: 3. As far as I'm aware, subtyping in the current language arises only from subtyping of lifetimes. Where is this important? One example was mentioned in [Niko's recent blog post](http://smallcultfollowing.com/babysteps/blog/2014/07/06/implied-bounds/). Where else? Without this subtyping of lifetimes, what would break? How burdensome would it be if one had to use explicit casts in those circumstances? I’ve been thinking about this a bit recently, so I might as well post my thoughts in this thread rather than following up privately with people. All subtyping in Rust is ultimately derived from the inclusion of lifetimes and the contravariance of the /mut type constructors in their lifetime parameter: a pointer to something that lives longer than ‘a is usable in any place where we are using a pointer to something with lifetime ‘a. As far as I know, there are only 3 original sources of bounds ‘a = ‘b for lifetimes ‘a and ‘b: 1) Inclusion of concrete lifetimes, i.e. control-flow regions (currently lexical scopes, but soon to be extended to arbitrary single-entry / multiple exit regions), in the same function. 2) That if a function is parameterized in lifetime ‘b and lifetime ‘a is a concrete lifetime in that function, then ‘a = ‘b. 3) That the scope of a borrow is always included in the lifetime of its referent, e.g. that ‘a = ‘b in ’a ’b T. This is described by Niko in his blog post http://smallcultfollowing.com/babysteps/blog/2013/04/04/nested-lifetimes/. This rule is different than the first two because it is the only way that a bound can be propagated on two lifetime *parameters*, whereas the first two involve a concrete lifetime in one of the positions. This is handwaving a bit, since the specifics of 1) and how these all interact in the current lifetime inference (and Niko’s proposed simplification) are all relevant in practice, but I hope this is a correct abstraction of the situation. The simplest question to ask is whether it is possible to remove lifetime subtyping entirely from Rust. Unfortunately, this is not possible, because if you try to do this (see the Tofte-Talpin region system, which is probably the closest thing to pure Hindley-Milner type inference for a region system) then you have lifetime variables for local variables in a function caller and callee unified, so that a called function is allocating local variables in the caller’s lifetime. This means that lifetimes no longer correspond to nested stack frames, and you also can’t implement destructors properly (at least in any trivial way that I can think of). This is not suitable for a systems language. The next logical question to ask is whether you can eliminate the non-invariance of type constructors, since that is how subtyping infects the rest of the language. Since /mut are contravariant in their lifetime parameter, the vast majority of type constructors get their variance inferred as contravariant in lifetime parameters. Most examples of contravariance come from something like this: struct A‘a { x: ’a int, y: ’a int, } If I have two distinct int borrows with concrete lifetimes (meaning an actual control-flow region in the calling function, rather than a lifetime parameter) being used at a construction of A‘a, then one of the lifetimes is nested in the other. Hence I if ‘a is the inner lifetime and ‘b is the outer lifetime, I can coerce the ’b to an ’a and construct an A‘a. What do I lose by this? Well, it only works at the first level, so that something like this will fail to type-check: struct A'a { x: 'a int } fn foo(i: int) { let a = A { x: i }; if i 1 { let j = 2; let b = if i 10 { a } else { A { x: j } }; } } There are obvious workarounds here, but in more complex examples they could possibly hurt the readability / performance of the program. However, the fallout is internal to a single function, since there is no way to directly propagate the knowledge that one concrete lifetime is included in another to another function (beside the 3rd source of bounds mentioned above. which I will talk about below). You can do similar coercions with the sources of bounds 2) and 3). In 2) one of the lifetimes is a concrete lifetime again, so again all of the fallout is internal to a single function. However, in 3) there is a new complication. since knowledge of the relationship between two lifetimes can actually leak outside of the functions where they originate. Here is the example in Niko’s blog post on 3): struct BorrowedCursor'b, T { buffer: 'b [T], position: uint } impl'b, T CursorT for BorrowedCursor'b, T { fn get'c('c self) - 'c T { self.buffer[self.position] } ... } This would still work, because we’re dealing directly with the type constructor, and we could still coerce an ’b [] to
[rust-dev] Sendable References for data-parallel fork/join-style algorithms
Hi! I was thinking about fork/join-style parallelism and about whether this can be made to work including the possibility to pass references (or something similar to references) across task boundaries. So far, I came up with a little low-level building block that could be of interest to the community. This basically allows to send reference-like things across task boundaries without any dangling pointer issues (I believe). A use case I had in mind was a divide-and-conquer algorithm where the recursion could benefit from concurrency because the division produces independent problems operating on non-overlapping mut slices. In my case, I tried to parallelize a multibody simulation with this. But you could also think about a parallelized quicksort if you want. After partitioning, sorting the two halves can be done independently and concurrently. But you may wish to avoid splitting one vector into two and joining them together. Instead you may want different tasks to work on the same vector but restricted to their non-overlapping sub-slices. The basic idea is to erase the lifetime parameter (to make the reference-like objects sendable) and to keep it safe w.r.t. to lifetimes by creating a new scope that won't be left by execution until all the borrowed and life-time erased pseudo-references are gone. This is done by reference counting and signal/wait on a mutex. Let me just show you for now how this can be used: trait IntoSendBorrowOut { unsafe fn into_sendable(self) - Out; fn sendableU(self, func:|Out|-U) - U { ... } } fn partition_inplace'a(s: 'a mut[int]) - ('a mut[int],'a mut[int]) { ... } fn main() { let mut vec = Vec::from_fn(10,|u|-(u as int)); partition_inplace(vec.as_mut_slice()).sendable(|(left,right)|{ // Here, left and right are sendable slices: SendMutSliceint // A sendable reference internally refers to a reference counter // stored in a mutex and increases/decreases it on clone/drop. // If the counter reaches zero, it will send a signal. spawn(proc() { let mut left = left; // needed for unique borrowing left.as_mut_slice().sort(); }); let mut right = right; // needed for unique borrowing right.as_mut_slice().sort(); }); // -- in case the reference counter is not null, sendable waits // for the signal and blocks until until it reaches zero. // This is done within a destructor of a function-local object // that carries the reference counter as a member. for i in vec.iter() { println!({}, i) } } IntoSendBorrow is simply implemented for all reference-like things (T, mut T, [T], mut[T] and tuples of these). I'm planning on putting the whole source code online on github. Feel free to comment -- especially if you find this useful. :) One thing I learned is that it does not seem to be possible to emulate the behaviour of mutable references and mutable slices perfectly in the sense that they could be uniquely borrowed without being mutable. I think, I would have to write something like this: implT SendMutSliceT { ... fn get'a('a uniq self, index: uint) - 'a mut T ... } where self is only uniquely borrowed but does not have to be mutable. At least a unique borrow is needed to avoid returning mutable aliases. Since this is not possible right now, I have to put a mut there instead and that's why I need the lines let mut left = left; let mut right = right; in the above example. Cheers! sg ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] compiling Rust to C?
On Fri, Jul 18, 2014 at 12:35 AM, Cameron Zwarich zwar...@mozilla.com wrote: The biggest problem would be probably be handling stack unwinding (IIRC the LLVM C backend never tried to handle this either). Interesting, I can see what that would be a challenge. The only option when targeting C is to use setjmp / longjmp, but that is going to be pretty inefficient. Why do you think of setjmp/longjmp as inefficient? If you use the _setjmp/_longjmp variants that don't fiddle with the signal mask, they seem pretty efficient to me. The bigger problem with setjmp/longjmp to me is that they don't let you clean up variables sitting on the stack, as Rust language semantics do I believe? I can think of a way to do this portably, but it costs two extra pointers every time you declare any stack variables. Basically you could, every time you declare local variables, make them part of a struct that has a pointer to the enclosing local var struct, and a pointer to an unwind function. Then when a task fails, traverse this list of frames and run the unwind function for each one before calling longjmp(). It's wasteful of stack space (since this is basically duplicating unwind info that exists at the system level, like in .eh_frame), but it is portable. In any case, it sounds like no one is working on this, so it's probably unlikely to happen unless someone takes it up. Thanks for the info! Josh ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] compiling Rust to C?
On Jul 18, 2014, at 9:52 AM, Josh Haberman jhaber...@gmail.com wrote: The only option when targeting C is to use setjmp / longjmp, but that is going to be pretty inefficient. Why do you think of setjmp/longjmp as inefficient? If you use the _setjmp/_longjmp variants that don't fiddle with the signal mask, they seem pretty efficient to me. The bigger problem with setjmp/longjmp to me is that they don't let you clean up variables sitting on the stack, as Rust language semantics do I believe? I can think of a way to do this portably, but it costs two extra pointers every time you declare any stack variables. Basically you could, every time you declare local variables, make them part of a struct that has a pointer to the enclosing local var struct, and a pointer to an unwind function. Then when a task fails, traverse this list of frames and run the unwind function for each one before calling longjmp(). It's wasteful of stack space (since this is basically duplicating unwind info that exists at the system level, like in .eh_frame), but it is portable. This is more along the lines of what I meant. The 32-bit ARM Darwin ABI actually uses this form of exception handling, and LLVM has some support for it. Unlike DWARF unwinding you incur a cost for every cleanup that you register, so it can be quite expensive. Having had to debug issues with it in the past in LLVM, I'm not sure I would really trust the codegen to be correct. Cameron ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] compiling Rust to C?
On Fri, Jul 18, 2014 at 12:29 AM, Josh Haberman jhaber...@gmail.com wrote: Is there any prospect of compiling Rust to C anytime in the mid to near future? This would be a really attractive option for anyone who wants to write in Rust, but wants the extreme portability of C. Actually maybe I should first ask if this is actually a tractable problem. Are there technical reasons that would prevent compiling Rust into portable C? LLVM's C Backend seems to have fallen out of maintenance -- would this provide the solution I am looking for, if it were maintained? FWIW I removed the C Backend a few years ago because it was largely unmaintained. It would likely need to be rewritten from scratch to do this. If you're curious about it, let me know. -eric ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Rust universal build issues
On 17/lug/2014, at 20:08, Brian Anderson bander...@mozilla.com wrote: Thanks for your work on MacPorts. Did you use any flags to configure or arguments to make? What version of OS X, clang/gcc? Yes, sorry, I’m building this on OS X 10.9.4 with system clang (5.1). After further inspection, I can build it with target and host set to x86_64-apple-darwin, but when I try to add i686-apple-darwin to the target list, the build fails. Is compiling for 32 bit on 64 bit host still supported? On 07/17/2014 01:17 AM, Aljaž Srebrnič wrote: Hello list, I’m ono of the maintainers of rust on MacPorts, and I found some issues with the build. The script in src/compiler-rt/make/platform/clang_darwin.mk has a comment on line 135: # Forcibly strip off any -arch, as that totally breaks our universal support. Now, it looks like that script strips any -arch flags and adds -arch flags for *all* the supported architectures by the host compiler. As a result, some of the files are compiled as x86_64 only (the original arch flags) and some as a fat binary (i386 and x86_64). In stage3, linking fails: I don't believe the build system is supposed to build stage3 on OS X. Seems suspicious. I could be wrong about the stage number, I just inferred because the stage3 directory had no files in it. […] error: ar 'x' '/opt/local/var/macports/build/_opt_local_var_macports_sources_svn.macports.org_dports_lang_rust/rust/work/rust-0.11.0/i686-apple-darwin/rt/libjemalloc.a' failed with: exit code: 1 note: stdout --- note: stderr --- ar: /opt/local/var/macports/build/_opt_local_var_macports_sources_svn.macports.org_dports_lang_rust/rust/work/rust-0.11.0/i686-apple-darwin/rt/libjemalloc.a is a fat file (use libtool(1) or lipo(1) and ar(1) on it) ar: /opt/local/var/macports/build/_opt_local_var_macports_sources_svn.macports.org_dports_lang_rust/rust/work/rust-0.11.0/i686-apple-darwin/rt/libjemalloc.a: Inappropriate file type or format […] I saw a env variable, $RC_SUPPORTED_ARCHS and tried to set RC_SUPPORTED_ARCHS=“x86_64”, but to no avail. How can I instruct compiler-rt to build for my architecture only? Thanks, Aljaž -- Aljaž Srebrnič a.k.a g5pw My public key: http://bit.ly/g5pw_pubkey ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev -- Aljaž Srebrnič a.k.a g5pw My public key: http://bit.ly/g5pw_pubkey ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Rust universal build issues
On 07/18/2014 03:43 PM, Aljaž Srebrnič wrote: On 17/lug/2014, at 20:08, Brian Anderson bander...@mozilla.com wrote: Thanks for your work on MacPorts. Did you use any flags to configure or arguments to make? What version of OS X, clang/gcc? Yes, sorry, I’m building this on OS X 10.9.4 with system clang (5.1). After further inspection, I can build it with target and host set to x86_64-apple-darwin, but when I try to add i686-apple-darwin to the target list, the build fails. Is compiling for 32 bit on 64 bit host still supported? Yes, it should work. I suspect there is some interaction with your (relatively new) toolchain that nobody has seen before. On 07/17/2014 01:17 AM, Aljaž Srebrnič wrote: Hello list, I’m ono of the maintainers of rust on MacPorts, and I found some issues with the build. The script in src/compiler-rt/make/platform/clang_darwin.mk has a comment on line 135: # Forcibly strip off any -arch, as that totally breaks our universal support. Now, it looks like that script strips any -arch flags and adds -arch flags for *all* the supported architectures by the host compiler. As a result, some of the files are compiled as x86_64 only (the original arch flags) and some as a fat binary (i386 and x86_64). In stage3, linking fails: I don't believe the build system is supposed to build stage3 on OS X. Seems suspicious. I could be wrong about the stage number, I just inferred because the stage3 directory had no files in it. […] error: ar 'x' '/opt/local/var/macports/build/_opt_local_var_macports_sources_svn.macports.org_dports_lang_rust/rust/work/rust-0.11.0/i686-apple-darwin/rt/libjemalloc.a' failed with: exit code: 1 note: stdout --- note: stderr --- ar: /opt/local/var/macports/build/_opt_local_var_macports_sources_svn.macports.org_dports_lang_rust/rust/work/rust-0.11.0/i686-apple-darwin/rt/libjemalloc.a is a fat file (use libtool(1) or lipo(1) and ar(1) on it) ar: /opt/local/var/macports/build/_opt_local_var_macports_sources_svn.macports.org_dports_lang_rust/rust/work/rust-0.11.0/i686-apple-darwin/rt/libjemalloc.a: Inappropriate file type or format […] I saw a env variable, $RC_SUPPORTED_ARCHS and tried to set RC_SUPPORTED_ARCHS=“x86_64”, but to no avail. How can I instruct compiler-rt to build for my architecture only? Thanks, Aljaž -- Aljaž Srebrnič a.k.a g5pw My public key: http://bit.ly/g5pw_pubkey ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev -- Aljaž Srebrnič a.k.a g5pw My public key: http://bit.ly/g5pw_pubkey ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev