Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Casting and width promotion #151

Closed
gnzlbg opened this issue Oct 25, 2017 · 12 comments
Closed

Casting and width promotion #151

gnzlbg opened this issue Oct 25, 2017 · 12 comments

Comments

@gnzlbg
Copy link
Contributor

gnzlbg commented Oct 25, 2017

Currently, we define the following casts with as_... methods:

define_casts!(
    (f32x2, f64x2, as_f64x2),
    (f32x2, u32x2, as_u32x2),
    (f32x2, i32x2, as_i32x2),
    (u32x2, f32x2, as_f32x2),
    (u32x2, i32x2, as_i32x2),
    (i32x2, f32x2, as_f32x2),
    (i32x2, u32x2, as_u32x2),
    (u16x4, i16x4, as_i16x4),
    (i16x4, u16x4, as_u16x4),
    (u8x8, i8x8, as_i8x8),
    (i8x8, u8x8, as_u8x8),
);

simd_cast<T> can be used to cast between types of different widths, where each lane gets promoted. For example, for some ARM implementations I've needed:

define_casts!(
    (i8x8, i16x8, as_i16x8),
    (i16x4, i32x4, as_i32x4),
    (i32x2, i64x2, as_i64x2),
    (u8x8, u16x8, as_u16x8),
    (u16x4, u32x4, as_u32x4),
    (u32x2, u64x2, as_u64x2)
);

@BurntSushi how do you envision these casts? When should we add an as_... function? Should we use simd_cast in the library internally? Or should we do all the casts using calls to the intrinsics that perform them ?

@alexcrichton
Copy link
Member

I think it personally makes sense to have all these casts. For any source/target pair I think the we can pretty easily define the semantics of the cast, right? If there's the same number of lanes then the elements are converted lane-wise and otherwise the bit sizes are the same and it's effectively a transmute, right?

@alexcrichton
Copy link
Member

Although now that I say that we may wish to call these two operations different things... For example u64 as f64 in Rust code is not a transmute-style cast

@gnzlbg
Copy link
Contributor Author

gnzlbg commented Oct 25, 2017

What's the win of implementing all these .as_... methods over just exposing simd_cast<T> ?


I am thinking from the POV of writing a high-level wrapper over the SIMD instructions in stable Rust once stdsimd is stabilized. The first thing I would do is implement simd_cast there.

For that, I need stdsimd to provide all possible combinations of interesting .as_... method. If it doesn't, I cannot reimplement the missing ones externally because I would need to access simd_llvm::simd_cast from there. Note that 1) there aren't intrinsics for conversions on all architectures, and 2) that the simd types are portable, so they actually do work on architectures that do not provide these casting intrinsics (llvm emulates these).

@alexcrichton
Copy link
Member

AFAIK simd_cast is riddled with LLVM assertions and compiler segfaults if you call it the wrong way, so it's not at all a stable interface which we'd want to expose.

@gnzlbg
Copy link
Contributor Author

gnzlbg commented Oct 25, 2017

So for the cases that I've tested:

  • same number of lanes, different element type: simd_cast<T> just behaves like as-element wise.
  • different number of lanes, different element type, but same vector width: simd_cast<T> behaves like mem::transmute

I don't know if simd_cast works like this for all possible combinations (maybe we should test this), but maybe it would be better to provide an API "like this" instead of all those .as_... casts.

For example, we could provide:

  • simd_as<T>: does element-wise as-like cats, fails to compile if the number of lanes differs.
  • simd_transmute<T>: does element-wise mem::transmute, fails to compile if the vector width differs.

As soon as we update this crate on crates.io, I'd like building these functions in a third-party crate. But if they cannot be built from stdsimds API then we will need to do something about it.

@alexcrichton
Copy link
Member

I don't think we'll ever provide generic functions, these will always be concrete in the stable surface area of the standard library. This is sort of like generic numeric operations in libstd, we just don't have them and have explicit typed operations instead.

@BurntSushi
Copy link
Member

IIRC, the intent here is for the as methods to be isomorphic to Rust's as operation, while the From impls are meant to be bitcasts (where the latter specifically doesn't support float<->int). And yeah, I'd guess that we just add as many as methods that we need.

It seems like we should just use simd_cast to implement them, unless there is a reason not to?

@gnzlbg
Copy link
Contributor Author

gnzlbg commented Oct 26, 2017

Sounds good, I think we should write this down in the docs somewhere.

@gnzlbg
Copy link
Contributor Author

gnzlbg commented Mar 1, 2018

So what's the reason that we currently do not provide bitwise transmutes between floating-point and integer vector types ?

@gnzlbg
Copy link
Contributor Author

gnzlbg commented Mar 1, 2018

So thinking about how to do this in a form suitable for an RFC. I'd like to do the following.

Make From/Into do simd_cast instead of transmutes. Add two traits FromBits/IntoBits, that allows doing the transmutes by just doing .into_bits() (similar to the f{32,64}::from_bits API).

@BurntSushi
Copy link
Member

@gnzlbg SGTM!

@gnzlbg
Copy link
Contributor Author

gnzlbg commented Jul 19, 2018

@gnzlbg gnzlbg closed this as completed Jul 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants