Skip to content

Commit

Permalink
Fixes to rotate_left and rotate_right 16 bit intrinsics. Rewamped the…
Browse files Browse the repository at this point in the history
… handling of unsized field access.
  • Loading branch information
FractalFir committed Aug 24, 2024
1 parent 0555839 commit 94c9d98
Show file tree
Hide file tree
Showing 14 changed files with 13,573 additions and 6,271 deletions.
114 changes: 1 addition & 113 deletions cargo_tests/build_std/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,119 +1,7 @@
#![feature(float_next_up_down)]
#[test]
fn should_pass() {}
#[test]
#[should_panic]
fn should_panic() {
fn should_fail() {
panic!();
}
#[allow(unused_macros)]
macro_rules! assert_f64_biteq {
($left : expr, $right : expr) => {
let l: &f64 = &$left;
let r: &f64 = &$right;
let lb = l.to_bits();
let rb = r.to_bits();
assert_eq!(
lb, rb,
"float {l} ({lb:#018x}) is not bitequal to {r} ({rb:#018x})"
);
};
}
fn main() {
let nan0 = f64::NAN;
let nan1 = f64::from_bits(f64::NAN.to_bits() ^ NAN_MASK1);
let nan2 = f64::from_bits(f64::NAN.to_bits() ^ NAN_MASK2);
assert_f64_biteq!(next_up(nan0), nan0);
assert_f64_biteq!(next_up(nan1), nan1);
assert_f64_biteq!(next_up(nan2), nan2);
}

#[test]
fn test_next_up() {
let tiny = f64::from_bits(TINY_BITS);
let tiny_up = f64::from_bits(TINY_UP_BITS);
let max_down = f64::from_bits(MAX_DOWN_BITS);
let largest_subnormal = f64::from_bits(LARGEST_SUBNORMAL_BITS);
let smallest_normal = f64::from_bits(SMALLEST_NORMAL_BITS);
assert_f64_biteq!(f64::NEG_INFINITY.next_up(), f64::MIN);
assert_f64_biteq!(f64::MIN.next_up(), -max_down);
assert_f64_biteq!((-1.0 - f64::EPSILON).next_up(), -1.0);
assert_f64_biteq!((-smallest_normal).next_up(), -largest_subnormal);
assert_f64_biteq!((-tiny_up).next_up(), -tiny);
assert_f64_biteq!((-tiny).next_up(), -0.0f64);
assert_f64_biteq!((-0.0f64).next_up(), tiny);
assert_f64_biteq!(0.0f64.next_up(), tiny);
assert_f64_biteq!(tiny.next_up(), tiny_up);
assert_f64_biteq!(largest_subnormal.next_up(), smallest_normal);
assert_f64_biteq!(1.0f64.next_up(), 1.0 + f64::EPSILON);
assert_f64_biteq!(f64::MAX.next_up(), f64::INFINITY);
assert_f64_biteq!(f64::INFINITY.next_up(), f64::INFINITY);

let nan0 = f64::NAN;
let nan1 = f64::from_bits(f64::NAN.to_bits() ^ NAN_MASK1);
let nan2 = f64::from_bits(f64::NAN.to_bits() ^ NAN_MASK2);
assert_f64_biteq!(next_up(nan0), nan0);
assert_f64_biteq!(next_up(nan1), nan1);
assert_f64_biteq!(next_up(nan2), nan2);
}
pub fn next_up(val: f64) -> f64 {
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
// denormals to zero. This is in general unsound and unsupported, but here
// we do our best to still produce the correct result on such targets.
let bits = val.to_bits();
eprintln!("bits:{bits:?}");
if val.is_nan() || bits == f64::INFINITY.to_bits() {
return val;
}

let abs = bits & !SIGN_MASK;
let next_bits = if abs == 0 {
TINY_BITS
} else if bits == abs {
bits + 1
} else {
bits - 1
};
eprintln!("next_bits:{next_bits:?}");
f64::from_bits(next_bits)
}
/// Sign bit
const SIGN_MASK: u64 = 0x8000_0000_0000_0000;

/// Exponent mask
const EXP_MASK: u64 = 0x7ff0_0000_0000_0000;

/// Mantissa mask
const MAN_MASK: u64 = 0x000f_ffff_ffff_ffff;

/// Minimum representable positive value (min subnormal)

/// Minimum representable negative value (min negative subnormal)
const NEG_TINY_BITS: u64 = TINY_BITS | SIGN_MASK;
/// Smallest number
#[allow(dead_code)] // unused on x86
const TINY_BITS: u64 = 0x1;

/// Next smallest number
#[allow(dead_code)] // unused on x86
const TINY_UP_BITS: u64 = 0x2;

/// Exponent = 0b11...10, Sifnificand 0b1111..10. Min val > 0
#[allow(dead_code)] // unused on x86
const MAX_DOWN_BITS: u64 = 0x7fef_ffff_ffff_fffe;

/// Zeroed exponent, full significant
#[allow(dead_code)] // unused on x86
const LARGEST_SUBNORMAL_BITS: u64 = 0x000f_ffff_ffff_ffff;

/// Exponent = 0b1, zeroed significand
#[allow(dead_code)] // unused on x86
const SMALLEST_NORMAL_BITS: u64 = 0x0010_0000_0000_0000;

/// First pattern over the mantissa
#[allow(dead_code)] // unused on x86
const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa;

/// Second pattern over the mantissa
#[allow(dead_code)] // unused on x86
const NAN_MASK2: u64 = 0x0005_5555_5555_5555;
2 changes: 1 addition & 1 deletion cargo_tests/spinacz/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ fn mstring_to_string(mstr: MString) -> String {
.to_owned();
Marshal::static1::<"FreeCoTaskMem", isize, ()>(ptr);
}
pub fn method_sig()
//pub fn method_sig()
enum DType {
Ptr(Box<Self>),
Class(String),
Expand Down
8 changes: 8 additions & 0 deletions cilly/src/dotnet_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ impl DotnetTypeRef {
Self::new(Some("System.Runtime"), "System.SByte")
}
#[must_use]
pub fn uint16() -> Self {
Self::new(Some("System.Runtime"), "System.UInt16")
}
#[must_use]
pub fn int16() -> Self {
Self::new(Some("System.Runtime"), "System.Int16")
}
#[must_use]
pub fn double() -> Self {
Self::new(Some("System.Runtime"), "System.Double").with_valuetype(true)
}
Expand Down
119 changes: 77 additions & 42 deletions cilly/src/v2/cillyir_exporter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,41 +22,50 @@ impl Exporter for CillyIRExpoter {
let name = asm.get_string(def.name());
let escaped_name = escape_class_name(name);
writeln!(il_out, "fn {escaped_name}(asm:&mut Assembly){{",)?;
let extends = if let Some(extends) = def.extends(){
class_ref(asm.class_ref(extends),asm)
}else{
let extends = if let Some(extends) = def.extends() {
class_ref(asm.class_ref(extends), asm)
} else {
"None".into()
};
let fields:String = def.fields().iter().map(|(tpe,name,offset)|{
let tpe = tpe_to(tpe,asm);
let name = asm.get_string(*name);
let offset = if let Some(offset) = offset{
format!("Some(NonZeroU32::new({offset}).unwrap())")
} else{
"None".into()
};
format!("({tpe},{{asm.alloc_string({name:?})}},{offset})")
}).intersperse(",".to_owned()).collect();
let fields: String = def
.fields()
.iter()
.map(|(tpe, name, offset)| {
let tpe = tpe_to(tpe, asm);
let name = asm.get_string(*name);
let offset = if let Some(offset) = offset {
format!("Some(NonZeroU32::new({offset}).unwrap())")
} else {
"None".into()
};
format!("({tpe},{{asm.alloc_string({name:?})}},{offset})")
})
.intersperse(",".to_owned())
.collect();
let fields = format!("vec![{fields}]");
let static_fields:String = def.static_fields().iter().map(|(tpe,name,thread_local)|{
let tpe = tpe_to(tpe,asm);
let name = asm.get_string(*name);
format!("({tpe},{{asm.alloc_string({name:?})}},{thread_local})")
}).intersperse(",".to_owned()).collect();
let static_fields = format!("vec![{static_fields}]");
let static_fields: String = def
.static_fields()
.iter()
.map(|(tpe, name, thread_local)| {
let tpe = tpe_to(tpe, asm);
let name = asm.get_string(*name);
format!("({tpe},{{asm.alloc_string({name:?})}},{thread_local})")
})
.intersperse(",".to_owned())
.collect();
let static_fields = format!("vec![{static_fields}]");
let methods = "vec![]";
let access = "Access::Public";
let explict_size = if let Some(explict_size) = def.explict_size(){
let explict_size = if let Some(explict_size) = def.explict_size() {
format!("Some(NonZeroU32::new({explict_size}).unwrap())")
}else{
} else {
"None".into()
};
writeln!(
il_out,
"let {escaped_name} = ClassDef::new(asm.alloc_string({name:?}),{is_valuetype},{generics},{extends},{fields},{static_fields},{methods},{access},{explict_size});",
is_valuetype = def.is_valuetype(),
generics = def.generics(),

)?;
// let mut class = crate::v2::class::ClassDef::new();
writeln!(il_out, "}}")?;
Expand All @@ -66,36 +75,62 @@ impl Exporter for CillyIRExpoter {
Ok(())
}
}
fn tpe_to(tpe:&Type,asm:&Assembly)->String{
match tpe{
Type::Ptr(inner) =>format!("{{asm.nptr({inner})}}",inner = tpe_to(asm.get_type(*inner), asm)),
Type::Ref(inner) =>format!("{{asm.nref({inner})}}",inner = tpe_to(asm.get_type(*inner), asm)),
Type::ClassRef(cref) =>format!("Type::ClassRef({{asm.alloc_class_ref({cref})}})",cref = class_ref(asm.class_ref(*cref), asm)),
fn tpe_to(tpe: &Type, asm: &Assembly) -> String {
match tpe {
Type::Ptr(inner) => format!(
"{{asm.nptr({inner})}}",
inner = tpe_to(asm.get_type(*inner), asm)
),
Type::Ref(inner) => format!(
"{{asm.nref({inner})}}",
inner = tpe_to(asm.get_type(*inner), asm)
),
Type::ClassRef(cref) => format!(
"Type::ClassRef({{asm.alloc_class_ref({cref})}})",
cref = class_ref(asm.class_ref(*cref), asm)
),
Type::PlatformGeneric(_, _) => todo!(),
Type::PlatformString|
Type::PlatformChar|
Type::PlatformObject |
Type::Float(_) | Type::Int(_) |
Type::Bool|
Type::Void => format!("{tpe:?}"),
Type::PlatformString
| Type::PlatformChar
| Type::PlatformObject
| Type::Float(_)
| Type::Int(_)
| Type::Bool
| Type::Void => format!("{tpe:?}"),
Type::PlatformArray { elem, dims } => todo!(),
Type::FnPtr(sig) => format!("Type::FnPtr({sig})",sig = sig_to(asm.get_sig(*sig).clone(),asm)),
Type::FnPtr(sig) => format!(
"Type::FnPtr({sig})",
sig = sig_to(asm.get_sig(*sig).clone(), asm)
),
}
}
fn sig_to(sig:FnSig,asm:&Assembly)->String{
let inputs:String = sig.inputs().iter().map(|input|tpe_to(input, asm)).intersperse(",".into()).collect();
format!("{{asm.sig([{inputs}],{output})}}",output = tpe_to(sig.output(), asm))
fn sig_to(sig: FnSig, asm: &Assembly) -> String {
let inputs: String = sig
.inputs()
.iter()
.map(|input| tpe_to(input, asm))
.intersperse(",".into())
.collect();
format!(
"{{asm.sig([{inputs}],{output})}}",
output = tpe_to(sig.output(), asm)
)
}
fn escape_class_name(name: &str) -> String {
name.replace(".", "dot")
}
fn class_ref(cref:&ClassRef,asm:&Assembly)->String{
fn class_ref(cref: &ClassRef, asm: &Assembly) -> String {
let name = asm.get_string(cref.name());
let ref_asm = if let Some(ref_asm) = cref.asm(){
format!("Some(asm.alloc_string({:?}))",asm.get_string(ref_asm))
}else{
let ref_asm = if let Some(ref_asm) = cref.asm() {
format!("Some(asm.alloc_string({:?}))", asm.get_string(ref_asm))
} else {
"None".into()
};
let generics:String = cref.generics().iter().map(|tpe|{tpe_to(tpe,asm)}).intersperse(",".into()).collect::<String>();
let generics: String = cref
.generics()
.iter()
.map(|tpe| tpe_to(tpe, asm))
.intersperse(",".into())
.collect::<String>();
format!("{{let name = asm.alloc_string({name:?}); let ref_asm = {ref_asm};let generics = vec![{generics}].into(); let cref = ClassRef::new(name,ref_asm,{is_valuetype},generics);}}",is_valuetype = cref.is_valuetype())
}
Loading

0 comments on commit 94c9d98

Please sign in to comment.