I already blogged about it before now I'm trying to complete it, few instructions per day.
How we support Altivec intrinsics
The Altivec intrinsics are sort of polymorphic: vec_add(a, b) -> c
works for plenty of combinations of a
and b
(and c
).
We want to support that in rust as well and that means we have to add plenty of traits and boilerplate (lots of it) to produce it.
Luckily we can leverage llvm
low level intrinsics so the large part of the problem is wiring the low-level to an high level abstraction, here an example.
pub trait VectorAdd<Other> {
type Return;
vec_add(self, b: Other) -> Self::Return;
}
impl VectorAdd<vector_signed_char> for vector_bool_char {
type Result = vector_signed_char;
#[inline]
#[target_feature(enable = "altivec")]
unsafe fn vec_add(self, other: vector_signed_char) -> Self::Result {
vec_add_bc_sc(self, other)
}
}
...
And then eventually you implement the generic function vec_add
:
#[inline]
#[target_feature(enable = "altivec")]
pub unsafe fn vec_add<T, U>(a: T, b: U) -> <T as sealed::VectorAdd<U>>::Result
where
T: sealed::VectorAdd<U>,
{
a.vec_add(b)
}
It is really boring endeavor that consists in:
- write a simple C testcase for the instruction
- feed it to
clang
to produce a.ll
file and a.s
file - write the stub for the
llvm
-internal intrinsic - write an
assert_instr
-wrapped test-function - write a wrapper trait
- write the implementations for all the type combinations have to support
- write the public generic function
- write a test or many to make sure you did not botch all the previous steps.
Current limitations
Both rust and C do not have exactly great way to described a function argument as literal-only.
Altivec has plenty of intrinsics that really need to be explicit and strict about that since one of the argument of them is a 5-bit literal that is embedded right in the coded instruction.
In rust we have rustc_args_required_const to mark the argument as a compile-time constant.
Sadly the information is not forwarded so until this isn't addressed all those instructions (some relatively fringe such as vec_ctf some useful such as the family of vec_splat_{type} immediates) do not have a sane way to be implemented.
That's all for tonight, I'll edit this again soon and publish it on my other blog once I have more to write about this.
Coming soon: cargo-c development notes and some more information about crav1e and rav1e getting closer to its first ready-for-distribution snapshot.
Top comments (2)
I did a lot of work with AltiVec for the PowerPC-based PS3 and Xbox360 so it has a special place in my heart.
Besides the loss of constants, how painful is casting between the different vec types?
Truth be told I've yet to look at stdsimd, should probably get around to it one of these days. Working with all of AltiVec, SSE, and NEON was always interesting.
Tomorrow I'll try to get the constants part done since there is a way to do that (arguably it is an hack but it should work for the intended purposes)