[rust-dev] compiling Rust to C?

2014-07-18 Thread Josh Haberman
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?

2014-07-18 Thread Cameron Zwarich
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)

2014-07-18 Thread Cameron Zwarich
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

2014-07-18 Thread Sebastian Gesemann
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?

2014-07-18 Thread Josh Haberman
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?

2014-07-18 Thread Cameron Zwarich
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?

2014-07-18 Thread Eric Christopher
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

2014-07-18 Thread Aljaž Srebrnič
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

2014-07-18 Thread Brian Anderson


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