diff --git a/cilly/src/bin/linker/patch.rs b/cilly/src/bin/linker/patch.rs index bd7b872..68ffede 100644 --- a/cilly/src/bin/linker/patch.rs +++ b/cilly/src/bin/linker/patch.rs @@ -60,7 +60,7 @@ pub fn call_alias( asm.alloc_node(CILNode::IntCast { input: src, target:*int, extend:cilly::cilnode::ExtendKind::ZeroExtend }) }, ( - Type::Ptr(dst) , + Type::Ptr(dst), Type::Ptr(_) | Type::Int(Int::ISize | Int::USize) | Type::FnPtr(_) , )=>{ let arg = asm.alloc_node(CILNode::LdArg(arg as u32)); diff --git a/cilly/src/lib.rs b/cilly/src/lib.rs index 0d54ee1..e54838e 100644 --- a/cilly/src/lib.rs +++ b/cilly/src/lib.rs @@ -86,6 +86,20 @@ macro_rules! config { .unwrap_or($default) }); }; + ($name:ident,$tpe:ty,$default:expr) => { + pub static $name: std::sync::LazyLock<$tpe> = std::sync::LazyLock::new(|| { + std::env::vars() + .find_map(|(key, value)| { + if key == stringify!($name) { + Some(value) + } else { + None + } + }) + .map(|value| value.parse().unwrap()) + .unwrap_or($default) + }); + }; } config! {DEAD_CODE_ELIMINATION,bool,true} diff --git a/cilly/src/v2/asm.rs b/cilly/src/v2/asm.rs index 559da90..641a371 100644 --- a/cilly/src/v2/asm.rs +++ b/cilly/src/v2/asm.rs @@ -12,7 +12,7 @@ use crate::{config, IString}; use fxhash::{hash64, FxHashMap, FxHashSet}; use serde::{Deserialize, Serialize}; -use std::{any::type_name, collections::HashSet, ops::Index}; +use std::{any::type_name, collections::HashSet, num::NonZero, ops::Index}; pub type MissingMethodPatcher = FxHashMap MethodImpl>>; @@ -522,10 +522,61 @@ impl Assembly { vec![].into(), )) } - pub fn has_cctor(&mut self) -> bool { - let cctor = self.cctor_mref(); + pub fn has_cctor(&self) -> bool { + let Some(main_module) = self.get_prealllocated_string(MAIN_MODULE) else { + return false; + }; + let class_def = ClassDef::new( + main_module, + false, + 0, + None, + vec![], + vec![], + Access::Public, + None, + None, + ); + + let Some(cref) = self.get_prealllocated_class_ref(class_def.ref_to()) else { + return false; + }; + // Check if that definition already exists + let main_module = if self.class_defs.contains_key(&ClassDefIdx(cref)) { + ClassDefIdx(cref) + } else { + return false; + }; + + let Some(user_init) = self.get_prealllocated_string(CCTOR) else { + return false; + }; + let input = []; + let output = Type::Void; + let Some(ctor_sig) = self.get_prealllocated_sig(FnSig::new(input.into(), output)) else { + return false; + }; + let Some(cctor) = self.get_prealllocated_methodref(MethodRef::new( + *main_module, + user_init, + ctor_sig, + MethodKind::Static, + vec![].into(), + )) else { + return false; + }; + self.method_ref_to_def(cctor).is_some() } + pub fn get_prealllocated_class_ref(&self, cref: ClassRef) -> Option { + self.class_refs.1.get(&(cref.into())).copied() + } + pub fn get_prealllocated_sig(&self, sig: FnSig) -> Option { + self.sigs.1.get(&(sig.into())).copied() + } + pub fn get_prealllocated_methodref(&self, mref: MethodRef) -> Option { + self.method_refs.1.get(&(mref.into())).copied() + } /// Returns a reference to the static initializer pub fn cctor(&mut self) -> MethodDefIdx { let mref = self.cctor_mref(); @@ -1006,6 +1057,48 @@ impl Assembly { // After removing all statics whose address nor value is not taken, replace any writes to those statics with pops. */ } + pub fn split_to_parts(&self, parts: u32) -> Vec { + let lib_name = StringIdx::from_index(std::num::NonZeroU32::new(1).unwrap()); + let mut part_asms = vec![]; + for rem in 0..parts { + let mut part = self.clone(); + part.method_defs.iter_mut().for_each(|(idx, def)| { + if idx.as_bimap_index().get()%parts != rem{ + /*if let MethodImpl::MethodBody { + blocks: _, + locals: _, + } = def.resolved_implementation(self).clone() + { + *def.implementation_mut() = MethodImpl::Extern { + lib: lib_name, + preserve_errno: false, + } + }*/ + *def.implementation_mut() = MethodImpl::Extern { + lib: lib_name, + preserve_errno: false, + } + } + }); + part.eliminate_dead_types(); + part = part.link_gc(); + part_asms.push(part); + } + part_asms + } + pub fn only_statics(&self) -> Self { + let lib_name = StringIdx::from_index(std::num::NonZeroU32::new(1).unwrap()); + let mut empty = self.clone(); + empty.method_defs.iter_mut().for_each(|(_, def)| { + *def.implementation_mut() = MethodImpl::Extern { + lib: lib_name, + preserve_errno: false, + } + }); + empty.eliminate_dead_types(); + empty = empty.link_gc(); + empty + } pub fn fix_aligement(&mut self) { let method_def_idxs: Box<[_]> = self.method_defs.keys().copied().collect(); for method in method_def_idxs { @@ -1055,6 +1148,12 @@ impl Assembly { } }) } + + fn link_gc(self) -> Self { + let mut clone = self.clone(); + clone = clone.link(self); + clone + } } /// An initializer, which runs before everything else. By convention, it is used to initialize static / const data. Should not execute any user code pub const CCTOR: &str = ".cctor"; @@ -1109,6 +1208,20 @@ pub fn ilasm_path() -> &'static str { ILASM_PATH.as_str() } +fn chunked_range(top: u32, parts: u32) -> impl Iterator> { + let chunk_size = top.div_ceil(parts); // Ceiling of n / m + + assert!(parts < top); + (0..top).filter_map(move |i| { + let start = i * chunk_size; + let end = std::cmp::min(start + chunk_size, top); + if start < top { + Some(start..end) + } else { + None + } + }) +} #[doc = "Specifies the path to the IL assembler."] pub static ILASM_PATH: std::sync::LazyLock = std::sync::LazyLock::new(|| { std::env::vars() @@ -1128,6 +1241,25 @@ fn get_default_ilasm() -> String { "ilasm".into() } #[test] +fn test_chunked_range() { + for count in 1..100 { + for parts in 1..count { + let range = chunked_range(count, parts); + assert_eq!( + range.flatten().max().unwrap(), + count - 1, + "count:{count},parts:{parts},range:" + ); + let range = chunked_range(count, parts); + assert_eq!( + range.flatten().count(), + count.try_into().unwrap(), + "count:{count},parts:{parts},range:" + ); + } + } +} +#[test] fn test_get_default_ilasm() { assert!(get_default_ilasm().contains("ilasm")); } diff --git a/cilly/src/v2/c_exporter/c_header.h b/cilly/src/v2/c_exporter/c_header.h index 30791ca..72d0253 100644 --- a/cilly/src/v2/c_exporter/c_header.h +++ b/cilly/src/v2/c_exporter/c_header.h @@ -28,7 +28,7 @@ int execvp(void *file, void *argv); #define System_Runtime_InteropServices_NativeMemory_AlignedAllocususpv(size, align) aligned_alloc(align, size) #define System_Runtime_InteropServices_NativeMemory_AlignedFreepvv free -void *System_Runtime_InteropServices_NativeMemory_AlignedReallocpvususpv(void *ptr, uintptr_t size, uintptr_t align) +static inline void *System_Runtime_InteropServices_NativeMemory_AlignedReallocpvususpv(void *ptr, uintptr_t size, uintptr_t align) { void *new_buff = aligned_alloc(align, size); memcpy(new_buff, ptr, size); @@ -149,8 +149,9 @@ void *System_Runtime_InteropServices_NativeMemory_AlignedReallocpvususpv(void *p #define System_Numerics_BitOperations_TrailingZeroCountusi4(val) (int32_t) __builtin_ctzl((uint64_t)val) #define System_Numerics_BitOperations_TrailingZeroCountu4i4(val) (int32_t) __builtin_ctzl((uint64_t)val) #define System_Numerics_BitOperations_TrailingZeroCountu8i4(val) (int32_t) __builtin_ctzl((uint64_t)val) -int32_t System_Numerics_BitOperations_LeadingZeroCountu8i4(uint64_t val) { return __builtin_clzl(val); } -int32_t System_Numerics_BitOperations_LeadingZeroCountusi4(uintptr_t val) { return __builtin_clzl((uint64_t)val); } +static inline int32_t System_Numerics_BitOperations_LeadingZeroCountu8i4(uint64_t val) { return __builtin_clzl(val); } +static inline int32_t System_Numerics_BitOperations_LeadingZeroCountusi4(uintptr_t val) { return __builtin_clzl((uint64_t)val); } +__uint128_t __builtin_bswap128(__uint128_t val); #define System_Numerics_BitOperations_PopCountusi4(val) __builtin_popcountl((uint64_t)val) #define System_Numerics_BitOperations_PopCountu4i4(val) __builtin_popcountl((uint32_t)val) @@ -160,19 +161,16 @@ int32_t System_Numerics_BitOperations_LeadingZeroCountusi4(uintptr_t val) { retu #define System_String_Concatststst(a, b) a b #define System_String_Concatstststst(a, b, c) a b c #define System_String_Concatststststst(a, b, c, d) a b c d -void System_Console_WriteLineu8v(uint64_t arg) +static inline void System_Console_WriteLineu8v(uint64_t arg) { printf("%lu\n", arg); } -void System_Console_WriteLinei8v(int64_t arg) +static inline void System_Console_WriteLinei8v(int64_t arg) { printf("%ld\n", arg); } -void System_Console_WriteLineu4v(uint32_t arg) -{ - printf("%u\n", arg); -} -void System_Console_WriteLinei4v(int32_t arg) +#define System_Console_WriteLineu4v(arg) printf("%u\n", arg) +static inline void System_Console_WriteLinei4v(int32_t arg) { printf("%u\n", arg); } @@ -186,17 +184,17 @@ void System_Console_WriteLinei4v(int32_t arg) #define System_Exception__ctor14System_Runtime16System_Exceptionsv #define System_Exception__ctorp14System_Runtime16System_Exceptionsv #define System_Exception__ctorp14System_Runtime16System_Exceptionstv -float System_Single_Clampf4f4f4f4(float d, float min, float max) +static inline float System_Single_Clampf4f4f4f4(float d, float min, float max) { const float t = d < min ? min : d; return t > max ? max : t; } -double System_Double_Clampf8f8f8f8(double d, double min, double max) +static inline double System_Double_Clampf8f8f8f8(double d, double min, double max) { const double t = d < min ? min : d; return t > max ? max : t; } -double System_Double_FusedMultiplyAddf8f8f8f8(double left, double right, double addend) +static inline double System_Double_FusedMultiplyAddf8f8f8f8(double left, double right, double addend) { return left * right + addend; } @@ -204,39 +202,39 @@ double System_Double_FusedMultiplyAddf8f8f8f8(double left, double right, double #define System_Type_GetTypeFromHandlep14System_Runtime24System_RuntimeTypeHandle14System_Runtime11System_Type #define System_Object_GetHashCode14System_Runtime11System_Typei4 #define System_Object_GetHashCodep14System_Runtime11System_Typei4 -float System_Single_MaxNumberf4f4f4(float a, float b) +static inline float System_Single_MaxNumberf4f4f4(float a, float b) { if (a > b) return a; else return b; } -double System_Double_MaxNumberf8f8f8(double a, double b) +static inline double System_Double_MaxNumberf8f8f8(double a, double b) { if (a > b) return a; else return b; } -float System_Single_MinNumberf4f4f4(float a, float b) +static inline float System_Single_MinNumberf4f4f4(float a, float b) { if (a < b) return a; else return b; } -double System_Double_MinNumberf8f8f8(double a, double b) +static inline double System_Double_MinNumberf8f8f8(double a, double b) { if (a < b) return a; else return b; } -float System_Single_FusedMultiplyAddf4f4f4f4(float left, float right, float addend) +static inline float System_Single_FusedMultiplyAddf4f4f4f4(float left, float right, float addend) { return left * right + addend; } -float System_Single_CopySignf4f4f4(float mag, float sign) +static inline float System_Single_CopySignf4f4f4(float mag, float sign) { if (sign > 0) { @@ -253,7 +251,7 @@ float System_Single_CopySignf4f4f4(float mag, float sign) return mag; } } -double System_Double_CopySignf8f8f8(double mag, double sign) +static inline double System_Double_CopySignf8f8f8(double mag, double sign) { if (sign > 0) { @@ -270,7 +268,7 @@ double System_Double_CopySignf8f8f8(double mag, double sign) return mag; } } -float System_MathF_Truncatef4f4(float val) +static inline float System_MathF_Truncatef4f4(float val) { fprintf(stderr, "Can't System_MathF_Truncatef4f4 yet.\n"); abort(); @@ -299,7 +297,7 @@ typedef struct TSWData void *arg; } TSWData; void _tcctor(); -void *thread_start_wrapper(TSWData *data) +static inline void *thread_start_wrapper(TSWData *data) { _tcctor(); void *(*start_routine)(void *) = (void *)data->start_routine; @@ -311,7 +309,7 @@ int32_t pthread_create(void *thread, void *attr, void *(*start_routine)(void *), void *threadarg); -int32_t pthread_create_wrapper(void *thread, +static inline int32_t pthread_create_wrapper(void *thread, void *attr, void *start_routine, void *arg) @@ -323,25 +321,25 @@ int32_t pthread_create_wrapper(void *thread, return pthread_create(thread, attr, (void *)thread_start_wrapper, data); } #define pthread_create pthread_create_alias -float System_Single_Exp2f4f4(float input) +static inline float System_Single_Exp2f4f4(float input) { fprintf(stderr, "Can't System_Single_Exp2f4f4 yet.\n"); abort(); return 0.0f; } -float System_Single_Logf4f4(float input) +static inline float System_Single_Logf4f4(float input) { fprintf(stderr, "Can't System_Single_Logf4f4 yet.\n"); abort(); return 0.0f; } -float System_Single_Log2f4f4(float input) +static inline float System_Single_Log2f4f4(float input) { fprintf(stderr, "Can't System_Single_Log2f4f4 yet.\n"); abort(); return 0.0f; } -float System_Single_Log10f4f4(float input) +static inline float System_Single_Log10f4f4(float input) { fprintf(stderr, "Can't System_Single_Log10f4f4 yet.\n"); abort(); @@ -350,35 +348,35 @@ float System_Single_Log10f4f4(float input) #define System_Math_Floorf8f8(input) floor(input) #define System_Math_Sqrtf8f8(input) sqrt(input) -double System_Double_Log10f8f8(double input) +static inline double System_Double_Log10f8f8(double input) { fprintf(stderr, "Can't System_Double_Log10f8f8 yet.\n"); abort(); return 0.0f; } -#define System_Math_Ceilingf8f8(input) celi(input) +#define System_Math_Ceilingf8f8(input) ceil(input) #define System_Math_Truncatef8f8(input) trunc(input) -uint32_t System_UInt32_RotateRightu4i4u4(uint32_t val, int32_t ammount) +static inline uint32_t System_UInt32_RotateRightu4i4u4(uint32_t val, int32_t ammount) { fprintf(stderr, "Can't System_UInt32_RotateRightu4i4u4 yet.\n"); abort(); return 0; } -uintptr_t System_UIntPtr_RotateRightusi4us(uintptr_t val, uintptr_t ammount) +static inline uintptr_t System_UIntPtr_RotateRightusi4us(uintptr_t val, uintptr_t ammount) { fprintf(stderr, "Can't System_UIntPtr_RotateRightusi4us yet.\n"); abort(); return 0; } -uint8_t System_Byte_RotateRightu1i4u1(uint8_t val, int32_t ammount) +static inline uint8_t System_Byte_RotateRightu1i4u1(uint8_t val, int32_t ammount) { fprintf(stderr, "Can't System_Byte_RotateRightu1i4u1 yet.\n"); abort(); return 0; } -uint32_t System_Threading_Interlocked_CompareExchangeru4u4u4u4(uint32_t *addr, uint32_t value, uint32_t comparand) +static inline uint32_t System_Threading_Interlocked_CompareExchangeru4u4u4u4(uint32_t *addr, uint32_t value, uint32_t comparand) { uint32_t res = 0; if (__atomic_compare_exchange_n(addr, &comparand, value, true, 5, 5)) @@ -391,7 +389,7 @@ uint32_t System_Threading_Interlocked_CompareExchangeru4u4u4u4(uint32_t *addr, u return comparand; } } -uint64_t System_Threading_Interlocked_CompareExchangeru8u8u8u8(uint64_t *addr, uint64_t value, uint64_t comparand) +static inline uint64_t System_Threading_Interlocked_CompareExchangeru8u8u8u8(uint64_t *addr, uint64_t value, uint64_t comparand) { uint64_t res = 0; if (__atomic_compare_exchange_n(addr, &comparand, value, true, 5, 5)) @@ -404,7 +402,7 @@ uint64_t System_Threading_Interlocked_CompareExchangeru8u8u8u8(uint64_t *addr, u return comparand; } } -uintptr_t System_Threading_Interlocked_CompareExchangerusususus(uintptr_t *addr, uintptr_t value, uintptr_t comparand) +static inline uintptr_t System_Threading_Interlocked_CompareExchangerusususus(uintptr_t *addr, uintptr_t value, uintptr_t comparand) { uintptr_t res = 0; if (__atomic_compare_exchange_n(addr, &comparand, value, true, 5, 5)) @@ -417,7 +415,7 @@ uintptr_t System_Threading_Interlocked_CompareExchangerusususus(uintptr_t *addr, return comparand; } } -intptr_t System_Threading_Interlocked_CompareExchangerisisisis(intptr_t *addr, intptr_t value, intptr_t comparand) +static inline intptr_t System_Threading_Interlocked_CompareExchangerisisisis(intptr_t *addr, intptr_t value, intptr_t comparand) { intptr_t res = 0; if (__atomic_compare_exchange_n(addr, &comparand, value, true, 5, 5)) @@ -431,85 +429,86 @@ intptr_t System_Threading_Interlocked_CompareExchangerisisisis(intptr_t *addr, i } } -uint32_t System_Threading_Interlocked_Exchangeru4u4u4(uint32_t *addr, uint32_t val) +static inline uint32_t System_Threading_Interlocked_Exchangeru4u4u4(uint32_t *addr, uint32_t val) { uint32_t ret; __atomic_exchange(addr, &val, &ret, 5); return ret; } -uintptr_t System_Threading_Interlocked_Exchangerususus(uintptr_t *addr, uintptr_t val) +static inline uintptr_t System_Threading_Interlocked_Exchangerususus(uintptr_t *addr, uintptr_t val) { uintptr_t ret; __atomic_exchange(addr, &val, &ret, 5); return ret; } - -uint32_t System_Threading_Interlocked_Addru4u4u4(uint32_t *addr, uint32_t addend) +static inline uint32_t System_Threading_Interlocked_Addru4u4u4(uint32_t *addr, uint32_t addend) { fprintf(stderr, "Can't System_Threading_Interlocked_Addru4u4u4 yet.\n"); abort(); } -uint32_t System_UInt32_RotateLeftu4i4u4(uint32_t val, int32_t ammount) +static inline uint32_t System_UInt32_RotateLeftu4i4u4(uint32_t val, int32_t ammount) { fprintf(stderr, "Can't System_UInt32_RotateLeftu4i4u4 yet.\n"); abort(); } -uint16_t System_UInt16_RotateRightu2i4u2(uint16_t val, int32_t ammount) +static inline uintptr_t System_UIntPtr_RotateLeftusi4us(uintptr_t val, uintptr_t ammount) +{ + fprintf(stderr, "Can't System_UIntPtr_RotateLeftusi4us yet.\n"); + abort(); +} + +static inline uint16_t System_UInt16_RotateRightu2i4u2(uint16_t val, int32_t ammount) { fprintf(stderr, "Can't System_UInt16_RotateRightu2i4u2 yet.\n"); abort(); } -uint16_t System_UInt16_RotateLeftu2i4u2(uint16_t val, int32_t ammount) +static inline uint16_t System_UInt16_RotateLeftu2i4u2(uint16_t val, int32_t ammount) { fprintf(stderr, "Can't System_UInt16_RotateLeftu2i4u2 yet.\n"); abort(); } -uint64_t System_UInt64_RotateRightu8i4u8(uint64_t val, int32_t ammount) +static inline uint64_t System_UInt64_RotateRightu8i4u8(uint64_t val, int32_t ammount) { fprintf(stderr, "Can't System_UInt64_RotateRightu8i4u8 yet.\n"); abort(); } - -uint16_t System_UInt128_RotateLeftu16i4u16(uint16_t val, int32_t ammount) +static inline uint16_t System_UInt128_RotateLeftu16i4u16(uint16_t val, int32_t ammount) { fprintf(stderr, "Can't System_UInt128_RotateLeftu16i4u16 yet.\n"); abort(); } - -uint64_t System_UInt64_RotateLeftu8i4u8(uint64_t val, int32_t ammount) +static inline uint64_t System_UInt64_RotateLeftu8i4u8(uint64_t val, int32_t ammount) { ammount = ammount % 64; return (val << ammount) | (val >> (64 - ammount)); } -unsigned __int128 System_UInt128_RotateRightu16i4u16(unsigned __int128 val, int32_t amount) +static inline unsigned __int128 System_UInt128_RotateRightu16i4u16(unsigned __int128 val, int32_t amount) { fprintf(stderr, "Can't System_UInt128_RotateRightu16i4u16 yet.\n"); abort(); } - -uint8_t System_Byte_RotateLeftu1i4u1(uint8_t val, int32_t ammount) +static inline uint8_t System_Byte_RotateLeftu1i4u1(uint8_t val, int32_t ammount) { fprintf(stderr, "Can't System_Byte_RotateLeftu1i4u1 yet.\n"); abort(); } -unsigned __int128 System_UInt128_LeadingZeroCountu16u16(unsigned __int128 val) +static inline unsigned __int128 System_UInt128_LeadingZeroCountu16u16(unsigned __int128 val) { fprintf(stderr, "Can't System_UInt128_LeadingZeroCountu16u16 yet.\n"); abort(); } -unsigned __int128 System_UInt128_PopCountu16u16(unsigned __int128 val) +static inline unsigned __int128 System_UInt128_PopCountu16u16(unsigned __int128 val) { fprintf(stderr, "Can't System_UInt128_PopCountu16u16 yet.\n"); abort(); } -unsigned __int128 System_UInt128_TrailingZeroCountu16u16(unsigned __int128 val) +static inline unsigned __int128 System_UInt128_TrailingZeroCountu16u16(unsigned __int128 val) { fprintf(stderr, "Can't System_UInt128_TrailingZeroCountu16u16 yet.\n"); abort(); } - -uint32_t System_Math_Minu4u4u4(uint32_t lhs, uint32_t rhs) +static inline uint32_t System_Math_Minu4u4u4(uint32_t lhs, uint32_t rhs) { if (lhs > rhs) { @@ -520,7 +519,7 @@ uint32_t System_Math_Minu4u4u4(uint32_t lhs, uint32_t rhs) return lhs; } } -int32_t System_Math_Clampi4i4i4i4(int32_t val, int32_t min, int32_t max) +static inline int32_t System_Math_Clampi4i4i4i4(int32_t val, int32_t min, int32_t max) { if (val > max) { @@ -535,7 +534,7 @@ int32_t System_Math_Clampi4i4i4i4(int32_t val, int32_t min, int32_t max) return val; } } -int64_t System_Math_Clampi8i8i8i8(int64_t val, int64_t min, int64_t max) +static inline int64_t System_Math_Clampi8i8i8i8(int64_t val, int64_t min, int64_t max) { if (val > max) { @@ -551,7 +550,7 @@ int64_t System_Math_Clampi8i8i8i8(int64_t val, int64_t min, int64_t max) } } -__int128 System_Int128_Clampi16i16i16i16(__int128 val, __int128 min, __int128 max) +static inline __int128 System_Int128_Clampi16i16i16i16(__int128 val, __int128 min, __int128 max) { if (val > max) { @@ -566,27 +565,27 @@ __int128 System_Int128_Clampi16i16i16i16(__int128 val, __int128 min, __int128 ma return val; } } -__int128 System_Int128_get_MinValuei16() +static inline __int128 System_Int128_get_MinValuei16() { fprintf(stderr, "Can't System_Int128_get_MinValuei16 yet.\n"); abort(); } -__int128 System_Int128_get_MaxValuei16() +static inline __int128 System_Int128_get_MaxValuei16() { fprintf(stderr, "Can't System_Int128_get_MinValuei16 yet.\n"); abort(); } -double System_Double_Exp2f8f8(double val) +static inline double System_Double_Exp2f8f8(double val) { fprintf(stderr, "Can't System_Double_Exp2f8f8 yet.\n"); abort(); } -void System_Threading_Thread_MemoryBarrierv() {} +static inline void System_Threading_Thread_MemoryBarrierv() {} static int argc; static char **argv; -char **System_Environment_GetCommandLineArgsa1st() { return argv; } -uintptr_t ld_len(void *arr) +static inline char **System_Environment_GetCommandLineArgsa1st() { return argv; } +static inline uintptr_t ld_len(void *arr) { void **elem = (void **)arr; uintptr_t len = 0; @@ -597,7 +596,7 @@ uintptr_t ld_len(void *arr) } return len; } -intptr_t System_Runtime_InteropServices_Marshal_StringToCoTaskMemUTF8stis(char *str) +static inline intptr_t System_Runtime_InteropServices_Marshal_StringToCoTaskMemUTF8stis(char *str) { uintptr_t len = strlen(str); char *ptr = (char *)malloc(len + 1); @@ -622,12 +621,25 @@ TYPEDEF_SIMDVECS_TYPE(uint64_t, u8) TYPEDEF_SIMDVECS_TYPE(float, f4) TYPEDEF_SIMDVECS_TYPE(double, f8) -const float inff = 1.0 / 0.0; -const double inf = 1.0 / 0.0; +static const float inff = 1.0 / 0.0; +static const double inf = 1.0 / 0.0; int fcntl(int fd, int op, ...); long syscall(long number, ...); -uint8_t **get_environ() +static inline uint8_t **get_environ() { extern char **environ; return (uint8_t **)environ; } +union System_MidpointRounding{int32_t inner;}; +static inline float System_Math_Roundf814System_Runtime23System_MidpointRoundingf8(float val,union System_MidpointRounding rounding){ + return roundf(val); +} +int ioctl(int fd, unsigned long op, ...); +int pthread_attr_init(void* attr); +int pthread_attr_destroy(void* attr); +int poll(void *fds, uint64_t nfds, int timeout); +int pthread_getattr_np(uint64_t thread, void *attr); +int pthread_attr_getstack(void *attr, + void **stackaddr, size_t *stacksize); +int sched_getaffinity(int32_t pid, size_t cpusetsize, + void *mask); diff --git a/cilly/src/v2/c_exporter/mod.rs b/cilly/src/v2/c_exporter/mod.rs index 7d0085c..09b6a71 100644 --- a/cilly/src/v2/c_exporter/mod.rs +++ b/cilly/src/v2/c_exporter/mod.rs @@ -1,6 +1,6 @@ // This exporter is WIP. #![allow(dead_code, unused_imports, unused_variables, clippy::let_unit_value)] -use std::{collections::HashSet, io::Write}; +use std::{collections::HashSet, io::Write, path::Path}; // Strips debuginfo: `#line [0-9]+ "[a-z/.\-0-9_]+"` use fxhash::{hash64, FxHashSet, FxHasher}; @@ -13,7 +13,7 @@ config!(NO_SFI, bool, false); config!(ANSI_C, bool, false); config!(UB_CHECKS, bool, true); config!(SHORT_TYPENAMES, bool, false); - +config!(PARTS, u32, 1); use super::{ asm::MAIN_MODULE, bimap::IntoBiMapIndex, @@ -58,8 +58,8 @@ fn escape_ident(ident: &str) -> String { // Check if reserved. match escaped.as_str() { "int" | "default" | "float" | "double" | "long" | "short" | "register" | "stderr" - | "environ" | "struct" | "union" | "linux" | "inline" | "asm" | "signed" | "bool" - | "char" | "case" | "switch" | "volatile" => { + | "environ" | "struct" | "union" | "linux" | "inline" | "asm" | "signed" | "unsigned" + | "bool" | "char" | "case" | "switch" | "volatile" | "auto" | "void" | "unix" => { format!("i{}", encode(hash64(&escaped))) } _ => escaped, @@ -928,7 +928,14 @@ impl CExporter { | "syscall" | "fcntl" | "execvp" - | "pthread_create_wrapper" => return Ok(()), + | "pthread_create_wrapper" + | "pthread_getattr_np" + | "ioctl" + | "pthread_attr_destroy" + | "pthread_attr_init" + | "pthread_attr_getstack" + | "sched_getaffinity" + | "poll" => return Ok(()), _ => { let inputs = def .ref_to() @@ -1042,6 +1049,7 @@ impl CExporter { type_defs: &mut impl Write, defined_types: &mut FxHashSet, delayed_defs: &mut FxHashSet, + extrn:bool, ) -> std::io::Result<()> { let class = asm[defid].clone(); // Checks if this def needs to be delayed, if one of its fields is not yet defined @@ -1081,10 +1089,15 @@ impl CExporter { let fname = escape_ident(&asm[*sfname]); let field_tpe = c_tpe(*sfield_tpe, asm); let fname = class_member_name(&class_name, &fname); + let extrn = if extrn { + "extern" + }else{ + "" + }; if *is_thread_local { - writeln!(type_defs, "static _Thread_local {field_tpe} {fname};")?; + writeln!(type_defs, "{extrn} _Thread_local {field_tpe} {fname};")?; } else { - writeln!(type_defs, "static {field_tpe} {fname};")?; + writeln!(type_defs, "{extrn} {field_tpe} {fname};")?; } } for method in class.methods() { @@ -1099,7 +1112,13 @@ impl CExporter { defined_types.insert(defid); Ok(()) } - fn export_to_write(&self, asm: &super::Assembly, out: &mut impl Write) -> std::io::Result<()> { + fn export_to_write( + &self, + asm: &super::Assembly, + out: &mut impl Write, + lib: bool, + extrn:bool, + ) -> std::io::Result<()> { let mut asm = asm.clone(); asm.tcctor(); let mut method_defs = Vec::new(); @@ -1119,6 +1138,7 @@ impl CExporter { &mut type_defs, &mut defined_types, &mut delayed_defs, + extrn )?; } delayed_defs_copy.clear(); @@ -1128,41 +1148,48 @@ impl CExporter { out.write_all(&type_defs)?; out.write_all(&method_decls)?; out.write_all(&method_defs)?; - if !self.is_lib { - let cctor_call = if asm.has_cctor() { "_cctor();" } else { "" }; - writeln!(out,"void main(int argc_input, char** argv_input){{argc = argc_input; argv = argv_input; {cctor_call}entrypoint((void *)0);}}")?; + if !lib { + call_entry(out, &mut asm)?; } Ok(()) } } - -impl Exporter for CExporter { - type Error = std::io::Error; - - fn export(&self, asm: &super::Assembly, target: &std::path::Path) -> Result<(), Self::Error> { - // The IL file should be next to the target - let c_path = target.with_extension("c"); +fn call_entry(out: &mut impl Write, asm: &Assembly) -> Result<(), std::io::Error> { + let cctor_call = if asm.has_cctor() { "_cctor();" } else { "" }; + writeln!(out,"int main(int argc_input, char** argv_input){{argc = argc_input; argv = argv_input; {cctor_call}entrypoint((void *)0); return 0;}}")?; + Ok(()) +} +impl CExporter { + fn export_to_file( + &self, + c_path: &Path, + asm: &Assembly, + target: &Path, + lib: bool, + extrn:bool, + ) -> Result<(), std::io::Error> { let mut c_out = std::io::BufWriter::new(std::fs::File::create(&c_path)?); - self.export_to_write(asm, &mut c_out)?; + self.export_to_write(asm, &mut c_out, lib,extrn)?; // Needed to ensure the IL file is valid! c_out.flush().unwrap(); drop(c_out); - let exe_out = target; let mut cmd = std::process::Command::new(std::env::var("CC").unwrap_or("cc".to_owned())); - cmd.arg(c_path).arg("-o").arg(exe_out).arg("-g"); + cmd.arg(c_path).arg("-o").arg(target).arg("-g"); - if *UB_CHECKS { + if *UB_CHECKS && *PARTS == 1 { cmd.args([ "-fsanitize=undefined,alignment", "-fno-sanitize=leak", - "-fno-sanitize-recover", + "-fno-sanitize-recover", "-O0" ]); } else { cmd.arg("-Ofast"); } - if self.is_lib { + if lib { cmd.arg("-c"); + } else { + cmd.arg("-lm"); } if *ANSI_C { cmd.arg("-std=c89"); @@ -1182,6 +1209,57 @@ impl Exporter for CExporter { Ok(()) } } +impl Exporter for CExporter { + type Error = std::io::Error; + + fn export(&self, asm: &super::Assembly, target: &std::path::Path) -> Result<(), Self::Error> { + if *PARTS == 1 { + // The IL file should be next to the target + let c_path = target.with_extension("c"); + self.export_to_file(&c_path, asm, target, self.is_lib,false) + } else { + let mut parts = vec![]; + for (id, part) in asm.split_to_parts(*PARTS).iter().enumerate() { + let name = target.file_stem().unwrap().to_string_lossy().into_owned(); + let target = target + .with_file_name(format!("{name}_{id}")) + .with_extension("o"); + let c_path = target.with_extension("c"); + self.export_to_file(&c_path, part, &target, true,true)?; + parts.push(target); + } + let mut cmd = + std::process::Command::new(std::env::var("CC").unwrap_or("cc".to_owned())); + cmd.args(parts); + cmd.arg("-o").arg(target).arg("-g").arg("-lm"); + if !self.is_lib { + let c_path = target.with_extension("c"); + let only_statics = asm.only_statics(); + + self.export_to_file(&c_path, &only_statics, target, true,false)?; + let mut option = std::fs::OpenOptions::new(); + option.read(true); + option.append(true); + let mut c_file = option.open(&c_path).unwrap(); + call_entry(&mut c_file, asm).unwrap(); + cmd.arg(c_path); + } + let out = cmd.output().unwrap(); + let stdout = String::from_utf8_lossy(&out.stdout); + let stderr = String::from_utf8_lossy(&out.stderr); + if !*LINKER_RECOVER { + assert!( + !(stderr.contains("error") || stderr.contains("fatal")), + "stdout:{} stderr:{} cmd:{cmd:?}", + stdout, + String::from_utf8_lossy(&out.stderr) + ); + } + + Ok(()) + } + } +} #[must_use] pub fn class_to_mangled(class: &super::ClassRef, asm: &Assembly) -> String {