Skip to content

Wishlist: allow adding intrinsics in a way that doesn't break every backend #93145

Closed

Description

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

  1. in a way that works for bootstrap
  2. in MIRI, for CTFE
  3. in cg_llvm
  4. 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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

Labels

A-codegenArea: Code generationA-intrinsicsArea: IntrinsicsC-feature-requestCategory: A feature request, i.e: not implemented / a PR.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions