#pragma once #include #include #include #include #include #ifdef _MSC_VER // For __popcnt #include #endif #include "krml/internal/target.h" #include "krml/lowstar_endianness.h" // C++ HELPERS #if defined(__cplusplus) #ifndef KRML_HOST_EPRINTF #define KRML_HOST_EPRINTF(...) fprintf(stderr, __VA_ARGS__) #endif #include #ifndef __cpp_lib_type_identity template struct type_identity { using type = T; }; template using type_identity_t = typename type_identity::type; #else using std::type_identity_t; #endif #define KRML_UNION_CONSTRUCTOR(T) \ template \ constexpr T(int t, V U::*m, type_identity_t v) : tag(t) { \ val.*m = std::move(v); \ } \ T() = default; #endif // GENERAL-PURPOSE STUFF #define LowStar_Ignore_ignore(e, t, _ret_t) ((void)e) #define EURYDICE_ASSERT(test, msg) \ do { \ if (!(test)) { \ fprintf(stderr, "assertion \"%s\" failed: file \"%s\", line %d\n", msg, \ __FILE__, __LINE__); \ exit(255); \ } \ } while (0) // SIZEOF, ALIGNOF #define Eurydice_sizeof(t) sizeof(t) #define Eurydice_alignof(t) alignof(t) // SLICES, ARRAYS, ETC. // For convenience, we give these common slice types, below, a distinguished // status and rather than emit them in the client code, we skip their // code-generation in Cleanup3.ml and write them by hand here. This makes it // easy to write interop code that brings those definitions in scope. // &[u8] typedef struct Eurydice_borrow_slice_u8_s { const uint8_t *ptr; size_t meta; } Eurydice_borrow_slice_u8; // &[u16] typedef struct Eurydice_borrow_slice_i16_s { const int16_t *ptr; size_t meta; } Eurydice_borrow_slice_i16; // &mut [u8] typedef struct Eurydice_mut_borrow_slice_u8_s { uint8_t *ptr; size_t meta; } Eurydice_mut_borrow_slice_u8; // &mut [u16] typedef struct Eurydice_mut_borrow_slice_i16_s { int16_t *ptr; size_t meta; } Eurydice_mut_borrow_slice_i16; #if defined(__cplusplus) #define KRML_CLITERAL(type) type #else #define KRML_CLITERAL(type) (type) #endif #if defined(__cplusplus) && defined(__cpp_designated_initializers) || \ !(defined(__cplusplus)) #define EURYDICE_CFIELD(X) X #else #define EURYDICE_CFIELD(X) #endif #define Eurydice_array_repeat(dst, len, init, t) \ ERROR "should've been desugared" // Copy a slice with memcopy #define Eurydice_slice_copy(dst, src, t) \ memcpy(dst.ptr, src.ptr, dst.meta * sizeof(t)) #define core_array___T__N___as_slice(len_, ptr_, t, ret_t) \ (KRML_CLITERAL(ret_t){EURYDICE_CFIELD(.ptr =)(ptr_)->data, \ EURYDICE_CFIELD(.meta =) len_}) #define core_array__core__clone__Clone_for__T__N___clone(len, src, elem_type, \ _ret_t) \ (*(src)) #define core_array__impl_core__clone__Clone_for__T__N___clone(len, src, \ elem_type, \ _ret_t) \ (*(src)) #define TryFromSliceError uint8_t #define core_array_TryFromSliceError uint8_t // Distinguished support for some PartialEq trait implementations // // core::cmp::PartialEq<@Array> for @Array #define Eurydice_array_eq(sz, a1, a2, t) \ (memcmp((a1)->data, (a2)->data, sz * sizeof(t)) == 0) // core::cmp::PartialEq<&0 (@Slice)> for @Array #define Eurydice_array_eq_slice_shared(sz, a1, s2, t, _) \ (memcmp((a1)->data, (s2)->ptr, sz * sizeof(t)) == 0) #define Eurydice_array_eq_slice_mut(sz, a1, s2, t, _) \ Eurydice_array_eq_slice_shared(sz, a1, s2, t, _) // DEPRECATED -- should no longer be generated #define core_array_equality__core__cmp__PartialEq__Array_U__N___for__Array_T__N___eq( \ sz, a1, a2, t, _, _ret_t) \ Eurydice_array_eq(sz, a1, a2, t) #define core_array_equality__core__cmp__PartialEq__0___Slice_U____for__Array_T__N___eq( \ sz, a1, a2, t, _, _ret_t) \ Eurydice_array_eq(sz, a1, ((a2)->ptr), t) #define core_cmp_impls__core__cmp__PartialEq__0_mut__B___for__1_mut__A___eq( \ _m0, _m1, src1, src2, _0, _1, T) \ Eurydice_slice_eq(src1, src2, _, _, T, _) #define Eurydice_slice_split_at(slice, mid, element_type, ret_t) \ KRML_CLITERAL(ret_t) { \ EURYDICE_CFIELD(.fst =){EURYDICE_CFIELD(.ptr =)((slice).ptr), \ EURYDICE_CFIELD(.meta =) mid}, \ EURYDICE_CFIELD(.snd =) { \ EURYDICE_CFIELD(.ptr =) \ ((slice).ptr + mid), EURYDICE_CFIELD(.meta =)((slice).meta - mid) \ } \ } #define Eurydice_slice_split_at_mut(slice, mid, element_type, ret_t) \ KRML_CLITERAL(ret_t) { \ EURYDICE_CFIELD(.fst =){EURYDICE_CFIELD(.ptr =)((slice).ptr), \ EURYDICE_CFIELD(.meta =) mid}, \ EURYDICE_CFIELD(.snd =) { \ EURYDICE_CFIELD(.ptr =) \ ((slice).ptr + mid), EURYDICE_CFIELD(.meta =)((slice).meta - mid) \ } \ } // Conversion of slice to an array, rewritten (by Eurydice) to name the // destination array, since arrays are not values in C. // N.B.: see note in karamel/lib/Inlining.ml if you change this. #define Eurydice_slice_to_ref_array2(len_, src, arr_ptr, t_ptr, t_arr, t_err, \ t_res) \ (src.meta >= len_ \ ? ((t_res){.tag = core_result_Ok, .val = {.case_Ok = arr_ptr}}) \ : ((t_res){.tag = core_result_Err, .val = {.case_Err = 0}})) // CORE STUFF (conversions, endianness, ...) // We slap extern "C" on declarations that intend to implement a prototype // generated by Eurydice, because Eurydice prototypes are always emitted within // an extern "C" block, UNLESS you use -fcxx17-compat, in which case, you must // pass -DKRML_CXX17_COMPAT="" to your C++ compiler. #if defined(__cplusplus) && !defined(KRML_CXX17_COMPAT) extern "C" { #endif #define core_hint_black_box(X, _0, _1) (X) // [ u8; 2 ] typedef struct Eurydice_array_u8x2_s { uint8_t data[2]; } Eurydice_array_u8x2; // [ u8; 4 ] typedef struct Eurydice_array_u8x4_s { uint8_t data[4]; } Eurydice_array_u8x4; // [ u8; 8 ] typedef struct Eurydice_array_u8x8_s { uint8_t data[8]; } Eurydice_array_u8x8; static inline uint16_t core_num__u16__from_le_bytes(Eurydice_array_u8x2 buf) { return load16_le(buf.data); } static inline Eurydice_array_u8x4 core_num__u32__to_be_bytes(uint32_t src) { // TODO: why not store32_be? Eurydice_array_u8x4 a; uint32_t x = htobe32(src); memcpy(a.data, &x, 4); return a; } static inline Eurydice_array_u8x4 core_num__u32__to_le_bytes(uint32_t src) { Eurydice_array_u8x4 a; store32_le(a.data, src); return a; } static inline uint32_t core_num__u32__from_le_bytes(Eurydice_array_u8x4 buf) { return load32_le(buf.data); } static inline Eurydice_array_u8x8 core_num__u64__to_le_bytes(uint64_t v) { Eurydice_array_u8x8 a; store64_le(a.data, v); return a; } static inline uint64_t core_num__u64__from_le_bytes(Eurydice_array_u8x8 buf) { return load64_le(buf.data); } static inline int64_t core_convert_num__core__convert__From_i32__for_i64__from( int32_t x) { return x; } static inline uint64_t core_convert_num__core__convert__From_u8__for_u64__from( uint8_t x) { return x; } static inline uint64_t core_convert_num__core__convert__From_u16__for_u64__from( uint16_t x) { return x; } static inline size_t core_convert_num__core__convert__From_u16__for_usize__from( uint16_t x) { return x; } static inline uint32_t core_num__u8__count_ones(uint8_t x0) { #ifdef _MSC_VER return __popcnt(x0); #else return __builtin_popcount(x0); #endif } static inline uint32_t core_num__u32__count_ones(uint32_t x0) { #ifdef _MSC_VER return __popcnt(x0); #else return __builtin_popcount(x0); #endif } static inline uint32_t core_num__i32__count_ones(int32_t x0) { #ifdef _MSC_VER return __popcnt(x0); #else return __builtin_popcount(x0); #endif } static inline size_t core_cmp_impls__core__cmp__Ord_for_usize__min(size_t a, size_t b) { if (a <= b) return a; else return b; } // unsigned overflow wraparound semantics in C static inline uint8_t core_num__u8__wrapping_sub(uint8_t x, uint8_t y) { return x - y; } static inline uint8_t core_num__u8__wrapping_add(uint8_t x, uint8_t y) { return x + y; } static inline uint8_t core_num__u8__wrapping_mul(uint8_t x, uint8_t y) { return x * y; } static inline uint16_t core_num__u16__wrapping_sub(uint16_t x, uint16_t y) { return x - y; } static inline uint16_t core_num__u16__wrapping_add(uint16_t x, uint16_t y) { return x + y; } static inline uint16_t core_num__u16__wrapping_mul(uint16_t x, uint16_t y) { return x * y; } static inline uint32_t core_num__u32__wrapping_sub(uint32_t x, uint32_t y) { return x - y; } static inline uint32_t core_num__u32__wrapping_add(uint32_t x, uint32_t y) { return x + y; } static inline uint32_t core_num__u32__wrapping_mul(uint32_t x, uint32_t y) { return x * y; } static inline uint64_t core_num__u64__wrapping_sub(uint64_t x, uint64_t y) { return x - y; } static inline uint64_t core_num__u64__wrapping_add(uint64_t x, uint64_t y) { return x + y; } static inline uint64_t core_num__u64__wrapping_mul(uint64_t x, uint64_t y) { return x * y; } static inline size_t core_num__usize__wrapping_sub(size_t x, size_t y) { return x - y; } static inline size_t core_num__usize__wrapping_add(size_t x, size_t y) { return x + y; } static inline size_t core_num__usize__wrapping_mul(size_t x, size_t y) { return x * y; } static inline int8_t core_num__i8__wrapping_add(int8_t x, int8_t y) { return (int8_t)((uint8_t)x + (uint8_t)y); } static inline int8_t core_num__i8__wrapping_sub(int8_t x, int8_t y) { return (int8_t)((uint8_t)x - (uint8_t)y); } static inline int8_t core_num__i8__wrapping_mul(int8_t x, int8_t y) { return (int8_t)((uint8_t)x * (uint8_t)y); } static inline int16_t core_num__i16__wrapping_add(int16_t x, int16_t y) { return (int16_t)((uint16_t)x + (uint16_t)y); } static inline int16_t core_num__i16__wrapping_sub(int16_t x, int16_t y) { return (int16_t)((uint16_t)x - (uint16_t)y); } static inline int16_t core_num__i16__wrapping_mul(int16_t x, int16_t y) { return (int16_t)((uint16_t)x * (uint16_t)y); } static inline int32_t core_num__i32__wrapping_add(int32_t x, int32_t y) { return (int32_t)((uint32_t)x + (uint32_t)y); } static inline int32_t core_num__i32__wrapping_sub(int32_t x, int32_t y) { return (int32_t)((uint32_t)x - (uint32_t)y); } static inline int32_t core_num__i32__wrapping_mul(int32_t x, int32_t y) { return (int32_t)((uint32_t)x * (uint32_t)y); } static inline int64_t core_num__i64__wrapping_add(int64_t x, int64_t y) { return (int64_t)((uint64_t)x + (uint64_t)y); } static inline int64_t core_num__i64__wrapping_sub(int64_t x, int64_t y) { return (int64_t)((uint64_t)x - (uint64_t)y); } static inline int64_t core_num__i64__wrapping_mul(int64_t x, int64_t y) { return (int64_t)((uint64_t)x * (uint64_t)y); } static inline int8_t core_num__i8__wrapping_neg(int8_t x) { return (int8_t)(-(uint8_t)x); } static inline int16_t core_num__i16__wrapping_neg(int16_t x) { return (int16_t)(-(uint16_t)x); } static inline int32_t core_num__i32__wrapping_neg(int32_t x) { return (int32_t)(-(uint32_t)x); } static inline int64_t core_num__i64__wrapping_neg(int64_t x) { return (int64_t)(-(uint64_t)x); } static inline uint64_t core_num__u64__rotate_left(uint64_t x0, uint32_t x1) { return (x0 << x1) | (x0 >> ((-x1) & 63)); } static inline void core_ops_arith__i32__add_assign(int32_t *x0, int32_t *x1) { *x0 = *x0 + *x1; } static inline uint8_t Eurydice_bitand_pv_u8(const uint8_t *p, uint8_t v) { return (*p) & v; } static inline uint8_t Eurydice_shr_pv_u8(const uint8_t *p, int32_t v) { return (*p) >> v; } static inline uint32_t Eurydice_min_u32(uint32_t x, uint32_t y) { return x < y ? x : y; } static inline uint8_t core_ops_bit__core__ops__bit__BitAnd_u8__u8__for__0__u8___bitand( const uint8_t *x0, uint8_t x1) { return Eurydice_bitand_pv_u8(x0, x1); } #define core_ops_bit__impl_core__ops__bit__BitAnd_u8__u8__for____0_u8__bitand \ core_ops_bit__core__ops__bit__BitAnd_u8__u8__for__0__u8___bitand static inline uint8_t core_ops_bit__core__ops__bit__Shr_i32__u8__for__0__u8___shr(const uint8_t *x0, int32_t x1) { return Eurydice_shr_pv_u8(x0, x1); } #define core_ops_bit__impl_core__ops__bit__Shr_i32__u8__for____0_u8__shr \ core_ops_bit__core__ops__bit__Shr_i32__u8__for__0__u8___shr #define core_num_nonzero_private_NonZeroUsizeInner size_t static inline core_num_nonzero_private_NonZeroUsizeInner core_num_nonzero_private___core__clone__Clone_for_core__num__nonzero__private__NonZeroUsizeInner___clone( core_num_nonzero_private_NonZeroUsizeInner *x0) { return *x0; } #if defined(__cplusplus) && !defined(KRML_CXX17_COMPAT) } #endif // ITERATORS #define Eurydice_range_iter_next(iter_ptr, t, ret_t) \ (((iter_ptr)->start >= (iter_ptr)->end) \ ? (KRML_CLITERAL(ret_t){EURYDICE_CFIELD(.tag =) 0, \ EURYDICE_CFIELD(.f0 =) 0}) \ : (KRML_CLITERAL(ret_t){EURYDICE_CFIELD(.tag =) 1, \ EURYDICE_CFIELD(.f0 =)(iter_ptr)->start++})) #define core_iter_range__core__iter__traits__iterator__Iterator_A__for_core__ops__range__Range_A__TraitClause_0___next \ Eurydice_range_iter_next // See note in karamel/lib/Inlining.ml if you change this #define Eurydice_into_iter(x, t, _ret_t, _) (x) #define core_iter_traits_collect__core__iter__traits__collect__IntoIterator_Clause1_Item__I__for_I__into_iter \ Eurydice_into_iter // STRINGS typedef char Eurydice_c_char_t; typedef const Eurydice_c_char_t *Prims_string; typedef void Eurydice_c_void_t; // UNSAFE CODE #define core_slice___Slice_T___as_mut_ptr(x, t, _) (x.ptr) #define core_mem_size_of(t, _) (sizeof(t)) #define core_slice_raw_from_raw_parts_mut(ptr, len, _0, _1) \ (KRML_CLITERAL(Eurydice_slice){(void *)(ptr), len}) #define core_slice_raw_from_raw_parts(ptr, len, _0, _1) \ (KRML_CLITERAL(Eurydice_slice){(void *)(ptr), len}) // FIXME: add dedicated extraction to extract NonNull as T* #define core_ptr_non_null_NonNull void * // PRINTING // // This is temporary. Ultimately we want to be able to extract all of this. typedef void *core_fmt_Formatter; #define core_fmt_rt__core__fmt__rt__Argument__a___new_display(x1, x2, x3, x4) \ NULL // BOXES #ifndef EURYDICE_MALLOC #define EURYDICE_MALLOC malloc #endif #ifndef EURYDICE_REALLOC #define EURYDICE_REALLOC realloc #endif static inline char *malloc_and_init(size_t sz, char *init) { char *ptr = (char *)EURYDICE_MALLOC(sz); if (ptr != NULL) memcpy(ptr, init, sz); return ptr; } #define Eurydice_box_new(init, t, t_dst) \ ((t_dst)(malloc_and_init(sizeof(t), (char *)(&init)))) // Initializer for array of size zero #define Eurydice_empty_array(dummy, t, t_dst) ((t_dst){.data = {}}) #define Eurydice_box_new_array(len, ptr, t, t_dst) \ ((t_dst)(malloc_and_init(len * sizeof(t), (char *)(ptr)))) // FIXME this needs to handle allocation failure errors, but this seems hard to // do without evaluating malloc_and_init twice... #define alloc_boxed__alloc__boxed__Box_T___try_new(init, t, t_ret) \ ((t_ret){.tag = core_result_Ok, \ .f0 = (t *)malloc_and_init(sizeof(t), (char *)(&init))}) // OPTIONS #define core_option__core__option__Option_T__TraitClause_0___is_some( \ x, _of_type, _) \ x->tag #define core_option__core__option__Option_T___TraitClause0___is_some \ core_option__core__option__Option_T__TraitClause_0___is_some