Description
openedon Jan 21, 2022
See previous conversation in https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Musing.20on.20intrinsics.20with.20MIR.20available/near/243719813 which was split off from https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Considering.20a.20future.20integration.20of.20the.20gcc.20backend/near/243686539
As we get more backends, and as people write more out-of-tree backends, it gets harder and harder to add intrinsics. Right now, you already have to implement every new intrinsic
- in a way that works for
bootstrap
- in MIRI, for CTFE
- in cg_llvm
- in cg_clif
And that list will just get longer with cg_gcc and whatever.
It would be really nice if there was an easy way to add an intrinsic that only required updating the type/safety checking parts of the compilers, not the backends at all. Then the changes the specific backends to implement the intrinsic in a more efficient way are separable from adding the intrinsic in the first place.
That would probably mean having MIR available for the intrinsic somehow, so the fallback path for intrinsics in backends could be to just use that MIR, rather than failing.
The intrinsics would then only need to be implemented in backends that care. For example, cg_clif
might not bother overriding some of the unchecked math ones.
And it would be really nice for simd, as the fallback implementations would define their semantics in terms of normal scalar rust, which MIRI will always want anyway, and will be very convenient for other platforms or backends that don't have it implemented (yet or ever).
A sketch
This might not be the best way, but for the sake of a starting point, here's a sketch of how maybe it could work.
Back in #61885, which added an unchecked_sub
intrinsic, I solved step (1) above by adding
/// For bootstrapping, implement unchecked_sub as just wrapping_sub.
#[cfg(bootstrap)]
pub unsafe fn unchecked_sub<T>(x: T, y: T) -> T {
sub_with_overflow(x, y).0
}
It would be nice if, rather than the intrinsic being only declared
extern "rust-intrinsic" {
#[cfg(not(bootstrap))]
pub fn unchecked_sub<T>(x: T, y: T) -> T;
}
it could instead be defined in core
with the fallback body
pub unsafe extern "rust-intrinsic" fn unchecked_sub<T>(x: T, y: T) -> T {
sub_with_overflow(x, y).0
}
Then the backend could use that MIR, available like the MIR of any generic function (or inline, for non-generics).