Skip to content

Commit ed81f97

Browse files
committed
Auto merge of rust-lang#120500 - oli-obk:intrinsics2.0, r=WaffleLapkin
Implement intrinsics with fallback bodies fixes rust-lang#93145 (though we can port many more intrinsics) cc rust-lang#63585 The way this works is that the backend logic for generating custom code for intrinsics has been made fallible. The only failure path is "this intrinsic is unknown". The `Instance` (that was `InstanceDef::Intrinsic`) then gets converted to `InstanceDef::Item`, which represents the fallback body. A regular function call to that body is then codegenned. This is currently implemented for * codegen_ssa (so llvm and gcc) * codegen_cranelift other backends will need to adjust, but they can just keep doing what they were doing if they prefer (though adding new intrinsics to the compiler will then require them to implement them, instead of getting the fallback body). cc `@scottmcm` `@WaffleLapkin` ### todo * [ ] miri support * [x] default intrinsic name to name of function instead of requiring it to be specified in attribute * [x] make sure that the bodies are always available (must be collected for metadata)
2 parents ffa6841 + 98c8eaa commit ed81f97

File tree

1 file changed

+98
-95
lines changed

1 file changed

+98
-95
lines changed

core/src/intrinsics.rs

Lines changed: 98 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -2368,32 +2368,6 @@ extern "rust-intrinsic" {
23682368
#[rustc_nounwind]
23692369
pub fn ptr_guaranteed_cmp<T>(ptr: *const T, other: *const T) -> u8;
23702370

2371-
/// Allocates a block of memory at compile time.
2372-
/// At runtime, just returns a null pointer.
2373-
///
2374-
/// # Safety
2375-
///
2376-
/// - The `align` argument must be a power of two.
2377-
/// - At compile time, a compile error occurs if this constraint is violated.
2378-
/// - At runtime, it is not checked.
2379-
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
2380-
#[rustc_nounwind]
2381-
pub fn const_allocate(size: usize, align: usize) -> *mut u8;
2382-
2383-
/// Deallocates a memory which allocated by `intrinsics::const_allocate` at compile time.
2384-
/// At runtime, does nothing.
2385-
///
2386-
/// # Safety
2387-
///
2388-
/// - The `align` argument must be a power of two.
2389-
/// - At compile time, a compile error occurs if this constraint is violated.
2390-
/// - At runtime, it is not checked.
2391-
/// - If the `ptr` is created in an another const, this intrinsic doesn't deallocate it.
2392-
/// - If the `ptr` is pointing to a local variable, this intrinsic doesn't deallocate it.
2393-
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
2394-
#[rustc_nounwind]
2395-
pub fn const_deallocate(ptr: *mut u8, size: usize, align: usize);
2396-
23972371
/// Determines whether the raw bytes of the two values are equal.
23982372
///
23992373
/// This is particularly handy for arrays, since it allows things like just
@@ -2517,83 +2491,112 @@ extern "rust-intrinsic" {
25172491
where
25182492
G: FnOnce<ARG, Output = RET>,
25192493
F: FnOnce<ARG, Output = RET>;
2494+
}
25202495

2521-
/// Returns whether the argument's value is statically known at
2522-
/// compile-time.
2523-
///
2524-
/// This is useful when there is a way of writing the code that will
2525-
/// be *faster* when some variables have known values, but *slower*
2526-
/// in the general case: an `if is_val_statically_known(var)` can be used
2527-
/// to select between these two variants. The `if` will be optimized away
2528-
/// and only the desired branch remains.
2529-
///
2530-
/// Formally speaking, this function non-deterministically returns `true`
2531-
/// or `false`, and the caller has to ensure sound behavior for both cases.
2532-
/// In other words, the following code has *Undefined Behavior*:
2533-
///
2534-
/// ```no_run
2535-
/// #![feature(is_val_statically_known)]
2536-
/// #![feature(core_intrinsics)]
2537-
/// # #![allow(internal_features)]
2538-
/// use std::hint::unreachable_unchecked;
2539-
/// use std::intrinsics::is_val_statically_known;
2540-
///
2541-
/// unsafe {
2542-
/// if !is_val_statically_known(0) { unreachable_unchecked(); }
2543-
/// }
2544-
/// ```
2545-
///
2546-
/// This also means that the following code's behavior is unspecified; it
2547-
/// may panic, or it may not:
2548-
///
2549-
/// ```no_run
2550-
/// #![feature(is_val_statically_known)]
2551-
/// #![feature(core_intrinsics)]
2552-
/// # #![allow(internal_features)]
2553-
/// use std::intrinsics::is_val_statically_known;
2554-
///
2555-
/// unsafe {
2556-
/// assert_eq!(is_val_statically_known(0), is_val_statically_known(0));
2557-
/// }
2558-
/// ```
2559-
///
2560-
/// Unsafe code may not rely on `is_val_statically_known` returning any
2561-
/// particular value, ever. However, the compiler will generally make it
2562-
/// return `true` only if the value of the argument is actually known.
2563-
///
2564-
/// When calling this in a `const fn`, both paths must be semantically
2565-
/// equivalent, that is, the result of the `true` branch and the `false`
2566-
/// branch must return the same value and have the same side-effects *no
2567-
/// matter what*.
2568-
#[rustc_const_unstable(feature = "is_val_statically_known", issue = "none")]
2569-
#[rustc_nounwind]
2570-
pub fn is_val_statically_known<T: Copy>(arg: T) -> bool;
2571-
2572-
/// Returns the value of `cfg!(debug_assertions)`, but after monomorphization instead of in
2573-
/// macro expansion.
2574-
///
2575-
/// This always returns `false` in const eval and Miri. The interpreter provides better
2576-
/// diagnostics than the checks that this is used to implement. However, this means
2577-
/// you should only be using this intrinsic to guard requirements that, if violated,
2578-
/// immediately lead to UB. Otherwise, const-eval and Miri will miss out on those
2579-
/// checks entirely.
2580-
///
2581-
/// Since this is evaluated after monomorphization, branching on this value can be used to
2582-
/// implement debug assertions that are included in the precompiled standard library, but can
2583-
/// be optimized out by builds that monomorphize the standard library code with debug
2584-
/// assertions disabled. This intrinsic is primarily used by [`assert_unsafe_precondition`].
2585-
#[rustc_const_unstable(feature = "delayed_debug_assertions", issue = "none")]
2586-
#[rustc_safe_intrinsic]
2587-
#[cfg(not(bootstrap))]
2588-
pub(crate) fn debug_assertions() -> bool;
2496+
/// Returns whether the argument's value is statically known at
2497+
/// compile-time.
2498+
///
2499+
/// This is useful when there is a way of writing the code that will
2500+
/// be *faster* when some variables have known values, but *slower*
2501+
/// in the general case: an `if is_val_statically_known(var)` can be used
2502+
/// to select between these two variants. The `if` will be optimized away
2503+
/// and only the desired branch remains.
2504+
///
2505+
/// Formally speaking, this function non-deterministically returns `true`
2506+
/// or `false`, and the caller has to ensure sound behavior for both cases.
2507+
/// In other words, the following code has *Undefined Behavior*:
2508+
///
2509+
/// ```no_run
2510+
/// #![feature(is_val_statically_known)]
2511+
/// #![feature(core_intrinsics)]
2512+
/// # #![allow(internal_features)]
2513+
/// use std::hint::unreachable_unchecked;
2514+
/// use std::intrinsics::is_val_statically_known;
2515+
///
2516+
/// if !is_val_statically_known(0) { unsafe { unreachable_unchecked(); } }
2517+
/// ```
2518+
///
2519+
/// This also means that the following code's behavior is unspecified; it
2520+
/// may panic, or it may not:
2521+
///
2522+
/// ```no_run
2523+
/// #![feature(is_val_statically_known)]
2524+
/// #![feature(core_intrinsics)]
2525+
/// # #![allow(internal_features)]
2526+
/// use std::intrinsics::is_val_statically_known;
2527+
///
2528+
/// assert_eq!(is_val_statically_known(0), is_val_statically_known(0));
2529+
/// ```
2530+
///
2531+
/// Unsafe code may not rely on `is_val_statically_known` returning any
2532+
/// particular value, ever. However, the compiler will generally make it
2533+
/// return `true` only if the value of the argument is actually known.
2534+
///
2535+
/// When calling this in a `const fn`, both paths must be semantically
2536+
/// equivalent, that is, the result of the `true` branch and the `false`
2537+
/// branch must return the same value and have the same side-effects *no
2538+
/// matter what*.
2539+
#[rustc_const_unstable(feature = "is_val_statically_known", issue = "none")]
2540+
#[rustc_nounwind]
2541+
#[unstable(feature = "core_intrinsics", issue = "none")]
2542+
#[cfg_attr(not(bootstrap), rustc_intrinsic)]
2543+
pub const fn is_val_statically_known<T: Copy>(_arg: T) -> bool {
2544+
false
25892545
}
25902546

2591-
#[cfg(bootstrap)]
2547+
/// Returns the value of `cfg!(debug_assertions)`, but after monomorphization instead of in
2548+
/// macro expansion.
2549+
///
2550+
/// This always returns `false` in const eval and Miri. The interpreter provides better
2551+
/// diagnostics than the checks that this is used to implement. However, this means
2552+
/// you should only be using this intrinsic to guard requirements that, if violated,
2553+
/// immediately lead to UB. Otherwise, const-eval and Miri will miss out on those
2554+
/// checks entirely.
2555+
///
2556+
/// Since this is evaluated after monomorphization, branching on this value can be used to
2557+
/// implement debug assertions that are included in the precompiled standard library, but can
2558+
/// be optimized out by builds that monomorphize the standard library code with debug
2559+
/// assertions disabled. This intrinsic is primarily used by [`assert_unsafe_precondition`].
25922560
#[rustc_const_unstable(feature = "delayed_debug_assertions", issue = "none")]
2561+
#[unstable(feature = "core_intrinsics", issue = "none")]
2562+
#[cfg_attr(not(bootstrap), rustc_intrinsic)]
25932563
pub(crate) const fn debug_assertions() -> bool {
25942564
cfg!(debug_assertions)
25952565
}
25962566

2567+
/// Allocates a block of memory at compile time.
2568+
/// At runtime, just returns a null pointer.
2569+
///
2570+
/// # Safety
2571+
///
2572+
/// - The `align` argument must be a power of two.
2573+
/// - At compile time, a compile error occurs if this constraint is violated.
2574+
/// - At runtime, it is not checked.
2575+
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
2576+
#[unstable(feature = "core_intrinsics", issue = "none")]
2577+
#[rustc_nounwind]
2578+
#[cfg_attr(not(bootstrap), rustc_intrinsic)]
2579+
pub const unsafe fn const_allocate(_size: usize, _align: usize) -> *mut u8 {
2580+
// const eval overrides this function, but runtime code should always just return null pointers.
2581+
crate::ptr::null_mut()
2582+
}
2583+
2584+
/// Deallocates a memory which allocated by `intrinsics::const_allocate` at compile time.
2585+
/// At runtime, does nothing.
2586+
///
2587+
/// # Safety
2588+
///
2589+
/// - The `align` argument must be a power of two.
2590+
/// - At compile time, a compile error occurs if this constraint is violated.
2591+
/// - At runtime, it is not checked.
2592+
/// - If the `ptr` is created in an another const, this intrinsic doesn't deallocate it.
2593+
/// - If the `ptr` is pointing to a local variable, this intrinsic doesn't deallocate it.
2594+
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
2595+
#[unstable(feature = "core_intrinsics", issue = "none")]
2596+
#[rustc_nounwind]
2597+
#[cfg_attr(not(bootstrap), rustc_intrinsic)]
2598+
pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
2599+
25972600
// Some functions are defined here because they accidentally got made
25982601
// available in this module on stable. See <https://github.com/rust-lang/rust/issues/15702>.
25992602
// (`transmute` also falls into this category, but it cannot be wrapped due to the

0 commit comments

Comments
 (0)