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

Add tests for more intrinsics #45

Open
FractalFir opened this issue Jun 3, 2024 · 0 comments
Open

Add tests for more intrinsics #45

FractalFir opened this issue Jun 3, 2024 · 0 comments
Labels
enhancement New feature or request good first issue Good for newcomers

Comments

@FractalFir
Copy link
Owner

FractalFir commented Jun 3, 2024

This is an issue tracking the progress of adding tests for each intrinsic.

The Rust language has many intrinsic functions . In order for the codegen to function propely, it has to support all of them. While many of them are already implemented, they lack tests.

How to add tests?

To add a new test to the harness, simply create a new file, named after your intrinsic, in the test/intrinsics directory(eg. test/intrinsics/addr_of.rs). Then, add a like this:

run_test! {intrinsics,addr_of,stable}

to src/compile_tests.rs.

All tests run in a special, #[no_std] enviroment, where even certain core functions are not avalible. So, each test should look like this:

#![feature(lang_items,adt_const_params,associated_type_defaults,core_intrinsics,start)]
#![allow(internal_features,incomplete_features,unused_variables,dead_code)]
#![no_std]
// Starts the test, includes some debug/test code
include!("../common.rs");
fn main(){
   // test code here
}

Tests can't use assert!, assert_eq! or assert_ne!. Instead, they should use test!, test_eq!, and test_ne! macros. Those macros behave exactly like assert, but they can work in the stripped-down test env. They also aid debugging, by seting .NET breakpoints, printing values using .NET builitns, etc.

In order to test an intrinisc, learn what it does from its documntation, and/or check its results in the Rust playground.

Then, use the test! macro to check if the intrisnic gets compiled propely.

REMEMBER TO USE core::hint::black_box TO PREVENT THE COMPILER FORM OPTIMIZING OUT THE INTRINSIC CALL!

// bad!
test_eq!(4,core::intrinsics::wrapping_add(2,2));
// ok!
test_eq!(4,core::intrinsics::wrapping_add(2,core::hint::black_box(2)));

List of intrinsics

  • copy_nonoverlapping
    Copies count * size_of::() bytes from src to dst. The source and destination may overlap.
  • drop_in_place
    Copies count * size_of::() bytes from src to dst. The source and destination must not overlap.
  • transmute
    Reinterprets the bits of a value of one type as another type.
  • write_bytes
    Sets count * size_of::() bytes of memory starting at dst to val.
  • abort
    Aborts the execution of the process.
  • add_with_overflow
    Performs checked integer addition.
  • arith_offset
    Calculates the offset from a pointer, potentially wrapping.
  • assert_inhabited
    A guard for unsafe functions that cannot ever be executed if T is uninhabited: This will statically either panic, or do nothing.
  • assert_mem_uninitialized_valid
    A guard for std::mem::uninitialized. This will statically either panic, or do nothing.
  • assert_zero_valid
    A guard for unsafe functions that cannot ever be executed if T does not permit zero-initialization: This will statically either panic, or do nothing.
  • assume
    Informs the optimizer that a condition is always true. If the condition is false, the behavior is undefined.
  • atomic_and_acqrel
    Bitwise and with the current value, returning the previous value.
  • atomic_and_acquire
    Bitwise and with the current value, returning the previous value.
  • atomic_and_relaxed
    Bitwise and with the current value, returning the previous value.
  • atomic_and_release
    Bitwise and with the current value, returning the previous value.
  • atomic_and_seqcst
    Bitwise and with the current value, returning the previous value.
  • atomic_cxchg_acqrel_acquire
    Stores a value if the current value is the same as the old value.
  • atomic_cxchg_acqrel_relaxed
    Stores a value if the current value is the same as the old value.
  • atomic_cxchg_acqrel_seqcst
    Stores a value if the current value is the same as the old value.
  • atomic_cxchg_acquire_acquire
    Stores a value if the current value is the same as the old value.
  • atomic_cxchg_acquire_relaxed
    Stores a value if the current value is the same as the old value.
  • atomic_cxchg_acquire_seqcst
    Stores a value if the current value is the same as the old value.
  • atomic_cxchg_relaxed_acquire
    Stores a value if the current value is the same as the old value.
  • atomic_cxchg_relaxed_relaxed
    Stores a value if the current value is the same as the old value.
  • atomic_cxchg_relaxed_seqcst
    Stores a value if the current value is the same as the old value.
  • atomic_cxchg_release_acquire
    Stores a value if the current value is the same as the old value.
  • atomic_cxchg_release_relaxed
    Stores a value if the current value is the same as the old value.
  • atomic_cxchg_release_seqcst
    Stores a value if the current value is the same as the old value.
  • atomic_cxchg_seqcst_acquire
    Stores a value if the current value is the same as the old value.
  • atomic_cxchg_seqcst_relaxed
    Stores a value if the current value is the same as the old value.
  • atomic_cxchg_seqcst_seqcst
    Stores a value if the current value is the same as the old value.
  • atomic_cxchgweak_acqrel_acquire
    Stores a value if the current value is the same as the old value.
  • atomic_cxchgweak_acqrel_relaxed
    Stores a value if the current value is the same as the old value.
  • atomic_cxchgweak_acqrel_seqcst
    Stores a value if the current value is the same as the old value.
  • atomic_cxchgweak_acquire_acquire
    Stores a value if the current value is the same as the old value.
  • atomic_cxchgweak_acquire_relaxed
    Stores a value if the current value is the same as the old value.
  • atomic_cxchgweak_acquire_seqcst
    Stores a value if the current value is the same as the old value.
  • atomic_cxchgweak_relaxed_acquire
    Stores a value if the current value is the same as the old value.
  • atomic_cxchgweak_relaxed_relaxed
    Stores a value if the current value is the same as the old value.
  • atomic_cxchgweak_relaxed_seqcst
    Stores a value if the current value is the same as the old value.
  • atomic_cxchgweak_release_acquire
    Stores a value if the current value is the same as the old value.
  • atomic_cxchgweak_release_relaxed
    Stores a value if the current value is the same as the old value.
  • atomic_cxchgweak_release_seqcst
    Stores a value if the current value is the same as the old value.
  • atomic_cxchgweak_seqcst_acquire
    Stores a value if the current value is the same as the old value.
  • atomic_cxchgweak_seqcst_relaxed
    Stores a value if the current value is the same as the old value.
  • atomic_cxchgweak_seqcst_seqcst
    Stores a value if the current value is the same as the old value.
  • atomic_fence_acqrel
    An atomic fence.
  • atomic_fence_acquire
    An atomic fence.
  • atomic_fence_release
    An atomic fence.
  • atomic_fence_seqcst
    An atomic fence.
  • atomic_load_acquire
    Loads the current value of the pointer.
  • atomic_load_relaxed
    Loads the current value of the pointer.
  • atomic_load_seqcst
    Loads the current value of the pointer.
  • atomic_load_unordered
    Do NOT use this intrinsic; “unordered” operations do not exist in our memory model! In terms of the Rust Abstract Machine, this operation is equivalent to src.read(), i.e., it performs a non-atomic read.
  • atomic_max_acqrel
    Maximum with the current value using a signed comparison.
  • atomic_max_acquire
    Maximum with the current value using a signed comparison.
  • atomic_max_relaxed
    Maximum with the current value.
  • atomic_max_release
    Maximum with the current value using a signed comparison.
  • atomic_max_seqcst
    Maximum with the current value using a signed comparison.
  • atomic_min_acqrel
    Minimum with the current value using a signed comparison.
  • atomic_min_acquire
    Minimum with the current value using a signed comparison.
  • atomic_min_relaxed
    Minimum with the current value using a signed comparison.
  • atomic_min_release
    Minimum with the current value using a signed comparison.
  • atomic_min_seqcst
    Minimum with the current value using a signed comparison.
  • atomic_nand_acqrel
    Bitwise nand with the current value, returning the previous value.
  • atomic_nand_acquire
    Bitwise nand with the current value, returning the previous value.
  • atomic_nand_relaxed
    Bitwise nand with the current value, returning the previous value.
  • atomic_nand_release
    Bitwise nand with the current value, returning the previous value.
  • atomic_nand_seqcst
    Bitwise nand with the current value, returning the previous value.
  • atomic_or_acqrel
    Bitwise or with the current value, returning the previous value.
  • atomic_or_acquire
    Bitwise or with the current value, returning the previous value.
  • atomic_or_relaxed
    Bitwise or with the current value, returning the previous value.
  • atomic_or_release
    Bitwise or with the current value, returning the previous value.
  • atomic_or_seqcst
    Bitwise or with the current value, returning the previous value.
  • atomic_singlethreadfence_acqrel
    A compiler-only memory barrier.
  • atomic_singlethreadfence_acquire
    A compiler-only memory barrier.
  • atomic_singlethreadfence_release
    A compiler-only memory barrier.
  • atomic_singlethreadfence_seqcst
    A compiler-only memory barrier.
  • atomic_store_relaxed
    Stores the value at the specified memory location.
  • atomic_store_release
    Stores the value at the specified memory location.
  • atomic_store_seqcst
    Stores the value at the specified memory location.
  • atomic_store_unordered
    Do NOT use this intrinsic; “unordered” operations do not exist in our memory model! In terms of the Rust Abstract Machine, this operation is equivalent to dst.write(val), i.e., it performs a non-atomic write.
  • atomic_umax_acqrel
    Maximum with the current value using an unsigned comparison.
  • atomic_umax_acquire
    Maximum with the current value using an unsigned comparison.
  • atomic_umax_relaxed
    Maximum with the current value using an unsigned comparison.
  • atomic_umax_release
    Maximum with the current value using an unsigned comparison.
  • atomic_umax_seqcst
    Maximum with the current value using an unsigned comparison.
  • atomic_umin_acqrel
    Minimum with the current value using an unsigned comparison.
  • atomic_umin_acquire
    Minimum with the current value using an unsigned comparison.
  • atomic_umin_relaxed
    Minimum with the current value using an unsigned comparison.
  • atomic_umin_release
    Minimum with the current value using an unsigned comparison.
  • atomic_umin_seqcst
    Minimum with the current value using an unsigned comparison.
  • atomic_xadd_acqrel
    Adds to the current value, returning the previous value.
  • atomic_xadd_acquire
    Adds to the current value, returning the previous value.
  • atomic_xadd_relaxed
    Adds to the current value, returning the previous value.
  • atomic_xadd_release
    Adds to the current value, returning the previous value.
  • atomic_xadd_seqcst
    Adds to the current value, returning the previous value.
  • atomic_xchg_acqrel
    Stores the value at the specified memory location, returning the old value.
  • atomic_xchg_acquire
    Stores the value at the specified memory location, returning the old value.
  • atomic_xchg_relaxed
    Stores the value at the specified memory location, returning the old value.
  • atomic_xchg_release
    Stores the value at the specified memory location, returning the old value.
  • atomic_xchg_seqcst
    Stores the value at the specified memory location, returning the old value.
  • atomic_xor_acqrel
    Bitwise xor with the current value, returning the previous value.
  • atomic_xor_acquire
    Bitwise xor with the current value, returning the previous value.
  • atomic_xor_relaxed
    Bitwise xor with the current value, returning the previous value.
  • atomic_xor_release
    Bitwise xor with the current value, returning the previous value.
  • atomic_xor_seqcst
    Bitwise xor with the current value, returning the previous value.
  • atomic_xsub_acqrel
    Subtract from the current value, returning the previous value.
  • atomic_xsub_acquire
    Subtract from the current value, returning the previous value.
  • atomic_xsub_relaxed
    Subtract from the current value, returning the previous value.
  • atomic_xsub_release
    Subtract from the current value, returning the previous value.
  • atomic_xsub_seqcst
    Subtract from the current value, returning the previous value.
  • bitreverse
    Reverses the bits in an integer type T.
  • black_box
    See documentation of std::hint::black_box for details.
  • breakpoint
    Executes a breakpoint trap, for inspection by a debugger.
  • bswap
    Reverses the bytes in an integer type T.
  • caller_location
    Gets a reference to a static Location indicating where it was called.
  • catch_unwind
    Rust’s “try catch” construct for unwinding. Invokes the function pointer try_fn with the data pointer data, and calls catch_fn if unwinding occurs while try_fn runs.
  • ceilf32
    Returns the smallest integer greater than or equal to an f32.
  • ceilf64
    Returns the smallest integer greater than or equal to an f64.
  • compare_bytes
    Lexicographically compare [left, left + bytes) and [right, right + bytes) as unsigned bytes, returning negative if left is less, zero if all the bytes match, or positive if right is greater.
  • const_allocate
    Allocates a block of memory at compile time. At runtime, just returns a null pointer.
  • const_deallocate
    Deallocates a memory which allocated by intrinsics::const_allocate at compile time. At runtime, does nothing.
  • const_eval_select
    Selects which function to call depending on the context.
  • copysignf32
    Copies the sign from y to x for f32 values.
  • copysignf64
    Copies the sign from y to x for f64 values.
  • cosf32
    Returns the cosine of an f32.
  • cosf64
    Returns the cosine of an f64.
  • ctlz
    Returns the number of leading unset bits (zeroes) in an integer type T.
  • ctlz_nonzero
    Like ctlz, but extra-unsafe as it returns undef when given an x with value 0.
  • ctpop
    Returns the number of bits set in an integer type T
  • cttz
    Returns the number of trailing unset bits (zeroes) in an integer type T.
  • cttz_nonzero
    Like cttz, but extra-unsafe as it returns undef when given an x with value 0.
  • discriminant_value
    Returns the value of the discriminant for the variant in ‘v’; if T has no discriminant, returns 0.
  • exact_div
    Performs an exact division, resulting in undefined behavior where x % y != 0 or y == 0 or x == T::MIN && y == -1
  • exp2f32
    Returns 2 raised to the power of an f32.
  • exp2f64
    Returns 2 raised to the power of an f64.
  • expf32
    Returns the exponential of an f32.
  • expf64
    Returns the exponential of an f64.
  • fabsf32
    Returns the absolute value of an f32.
  • fabsf64
    Returns the absolute value of an f64.
  • fadd_algebraic
    Float addition that allows optimizations based on algebraic rules.
  • fadd_fast
    Float addition that allows optimizations based on algebraic rules. May assume inputs are finite.
  • fdiv_algebraic
    Float division that allows optimizations based on algebraic rules.
  • fdiv_fast
    Float division that allows optimizations based on algebraic rules. May assume inputs are finite.
  • float_to_int_unchecked
    Convert with LLVM’s fptoui/fptosi, which may return undef for values out of range (floating point to integer casts can cause undefined behaviour rust-lang/rust#10184)
  • floorf32
    Returns the largest integer less than or equal to an f32.
  • floorf64
    Returns the largest integer less than or equal to an f64.
  • fmaf32
    Returns a * b + c for f32 values.
  • fmaf64
    Returns a * b + c for f64 values.
  • fmul_algebraic
    Float multiplication that allows optimizations based on algebraic rules.
  • fmul_fast
    Float multiplication that allows optimizations based on algebraic rules. May assume inputs are finite.
  • forget
    Moves a value out of scope without running drop glue.
  • frem_algebraic
    Float remainder that allows optimizations based on algebraic rules.
  • frem_fast
    Float remainder that allows optimizations based on algebraic rules. May assume inputs are finite.
  • fsub_algebraic
    Float subtraction that allows optimizations based on algebraic rules.
  • fsub_fast
    Float subtraction that allows optimizations based on algebraic rules. May assume inputs are finite.
  • is_val_statically_known
    Returns whether the argument’s value is statically known at compile-time.
  • likely
    Hints to the compiler that branch condition is likely to be true. Returns the value passed to it.
  • log2f32
    Returns the base 2 logarithm of an f32.
  • log2f64
    Returns the base 2 logarithm of an f64.
  • log10f32
    Returns the base 10 logarithm of an f32.
  • log10f64
    Returns the base 10 logarithm of an f64.
  • logf32
    Returns the natural logarithm of an f32.
  • logf64
    Returns the natural logarithm of an f64.
  • maxnumf32
    Returns the maximum of two f32 values.
  • maxnumf64
    Returns the maximum of two f64 values.
  • min_align_of
    The minimum alignment of a type.
  • min_align_of_val
    The required alignment of the referenced value.
  • minnumf32
    Returns the minimum of two f32 values.
  • minnumf64
    Returns the minimum of two f64 values.
  • mul_with_overflow
    Performs checked integer multiplication
  • nearbyintf32
    Returns the nearest integer to an f32. Changing the rounding mode is not possible in Rust, so this rounds half-way cases to the number with an even least significant digit.
  • nearbyintf64
    Returns the nearest integer to an f64. Changing the rounding mode is not possible in Rust, so this rounds half-way cases to the number with an even least significant digit.
  • needs_drop
    Returns true if the actual type given as T requires drop glue; returns false if the actual type provided for T implements Copy.
  • nontemporal_store
    Emits a !nontemporal store according to LLVM (see their docs). Probably will never become stable.
  • offset
    Calculates the offset from a pointer.
  • powf32
    Raises an f32 to an f32 power.
  • powf64
    Raises an f64 to an f64 power.
  • powif32
    Raises an f32 to an integer power.
  • powif64
    Raises an f64 to an integer power.
  • pref_align_of
    The preferred alignment of a type.
  • prefetch_read_data
    The prefetch intrinsic is a hint to the code generator to insert a prefetch instruction if supported; otherwise, it is a no-op. Prefetches have no effect on the behavior of the program but can change its performance characteristics.
  • prefetch_read_instruction
    The prefetch intrinsic is a hint to the code generator to insert a prefetch instruction if supported; otherwise, it is a no-op. Prefetches have no effect on the behavior of the program but can change its performance characteristics.
  • prefetch_write_data
    The prefetch intrinsic is a hint to the code generator to insert a prefetch instruction if supported; otherwise, it is a no-op. Prefetches have no effect on the behavior of the program but can change its performance characteristics.
  • prefetch_write_instruction
    The prefetch intrinsic is a hint to the code generator to insert a prefetch instruction if supported; otherwise, it is a no-op. Prefetches have no effect on the behavior of the program but can change its performance characteristics.
  • ptr_guaranteed_cmp
    See documentation of <*const T>::guaranteed_eq for details. Returns 2 if the result is unknown. Returns 1 if the pointers are guaranteed equal Returns 0 if the pointers are guaranteed inequal
  • ptr_mask
    Masks out bits of the pointer according to a mask.
  • ptr_offset_from
    See documentation of <*const T>::offset_from for details.
  • ptr_offset_from_unsigned
    See documentation of <*const T>::sub_ptr for details.
  • raw_eq
    Determines whether the raw bytes of the two values are equal.
  • read_via_copy
    This is an implementation detail of crate::ptr::read and should not be used anywhere else. See its comments for why this exists.
  • retag_box_to_raw
    Retag a box pointer as part of casting it to a raw pointer. This is the Box equivalent of (x: &mut T) as *mut T. The input pointer must be the pointer of a Box (passed as raw pointer to avoid all questions around move semantics and custom allocators), and A must be the Box’s allocator.
  • rintf32
    Returns the nearest integer to an f32. Changing the rounding mode is not possible in Rust, so this rounds half-way cases to the number with an even least significant digit.
  • rintf64
    Returns the nearest integer to an f64. Changing the rounding mode is not possible in Rust, so this rounds half-way cases to the number with an even least significant digit.
  • rotate_left
    Performs rotate left.
  • rotate_right
    Performs rotate right.
  • roundevenf32
    Returns the nearest integer to an f32. Rounds half-way cases to the number with an even least significant digit.
  • roundevenf64
    Returns the nearest integer to an f64. Rounds half-way cases to the number with an even least significant digit.
  • roundf32
    Returns the nearest integer to an f32. Rounds half-way cases away from zero.
  • roundf64
    Returns the nearest integer to an f64. Rounds half-way cases away from zero.
  • rustc_peek
    Magic intrinsic that derives its meaning from attributes attached to the function.
  • saturating_add
    Computes a + b, saturating at numeric bounds.
  • saturating_sub
    Computes a - b, saturating at numeric bounds.
  • sinf32
    Returns the sine of an f32.
  • sinf64
    Returns the sine of an f64.
  • size_of
    The size of a type in bytes.
  • size_of_val
    The size of the referenced value in bytes.
  • sqrtf32
    Returns the square root of an f32
  • sqrtf64
    Returns the square root of an f64
  • sub_with_overflow
    Performs checked integer subtraction
  • transmute_unchecked
    Like transmute, but even less checked at compile-time: rather than giving an error for size_of::() != size_of::(), it’s Undefined Behaviour at runtime.
  • truncf32
    Returns the integer part of an f32.
  • truncf64
    Returns the integer part of an f64.
  • type_id
    Gets an identifier which is globally unique to the specified type. This function will return the same value for a type regardless of whichever crate it is invoked in.
  • type_name
    Gets a static string slice containing the name of a type.
  • unaligned_volatile_load
    Performs a volatile load from the src pointer The pointer is not required to be aligned.
  • unaligned_volatile_store
    Performs a volatile store to the dst pointer. The pointer is not required to be aligned.
  • unchecked_add
    Returns the result of an unchecked addition, resulting in undefined behavior when x + y > T::MAX or x + y < T::MIN.
  • unchecked_div
    Performs an unchecked division, resulting in undefined behavior where y == 0 or x == T::MIN && y == -1
  • unchecked_mul
    Returns the result of an unchecked multiplication, resulting in undefined behavior when x * y > T::MAX or x * y < T::MIN.
  • unchecked_rem
    Returns the remainder of an unchecked division, resulting in undefined behavior when y == 0 or x == T::MIN && y == -1
  • unchecked_shl
    Performs an unchecked left shift, resulting in undefined behavior when y < 0 or y >= N, where N is the width of T in bits.
  • unchecked_shr
    Performs an unchecked right shift, resulting in undefined behavior when y < 0 or y >= N, where N is the width of T in bits.
  • unchecked_sub
    Returns the result of an unchecked subtraction, resulting in undefined behavior when x - y > T::MAX or x - y < T::MIN.
  • unlikely
    Hints to the compiler that branch condition is likely to be false. Returns the value passed to it.
  • unreachable
    Informs the optimizer that this point in the code is not reachable, enabling further optimizations.
  • variant_count
    Returns the number of variants of the type T cast to a usize; if T has no variants, returns 0. Uninhabited variants will be counted.
  • volatile_copy_memory
    Equivalent to the appropriate llvm.memmove.p0i8.0i8.* intrinsic, with a size of count * size_of::() and an alignment of min_align_of::()
  • volatile_copy_nonoverlapping_memory
    Equivalent to the appropriate llvm.memcpy.p0i8.0i8.* intrinsic, with a size of count * size_of::() and an alignment of min_align_of::()
  • volatile_load
    Performs a volatile load from the src pointer.
  • volatile_set_memory
    Equivalent to the appropriate llvm.memset.p0i8.* intrinsic, with a size of count * size_of::() and an alignment of min_align_of::().
  • volatile_store
    Performs a volatile store to the dst pointer.
  • vtable_align
    ptr must point to a vtable. The intrinsic will return the alignment stored in that vtable.
  • vtable_size
    ptr must point to a vtable. The intrinsic will return the size stored in that vtable.
  • wrapping_add
    Returns (a + b) mod 2N, where N is the width of T in bits.
  • wrapping_mul
    Returns (a * b) mod 2N, where N is the width of T in bits.
  • wrapping_sub
    Returns (a - b) mod 2N, where N is the width of T in bits.
  • write_via_move
    This is an implementation detail of crate::ptr::write and should not be used anywhere else. See its comments for why this exists.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

1 participant