From ac5e17e5410e971f9a1bd21921b0991400efddb6 Mon Sep 17 00:00:00 2001 From: Brummel Date: Sun, 10 May 2026 15:54:20 +0200 Subject: [PATCH] floats iter 4.1: codegen primitive registration + Float literal hex-double lowering --- crates/ailang-codegen/src/lib.rs | 45 ++++++++++++++++++++++++++++-- crates/ailang-codegen/src/synth.rs | 2 ++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/crates/ailang-codegen/src/lib.rs b/crates/ailang-codegen/src/lib.rs index e62843b..0e46f1e 100644 --- a/crates/ailang-codegen/src/lib.rs +++ b/crates/ailang-codegen/src/lib.rs @@ -925,7 +925,7 @@ impl<'a> Emitter<'a> { let g = self.intern_string("str", value); ("ptr".to_string(), format!("@{g}")) } - Literal::Float { .. } => unimplemented!("Floats milestone iter 4: codegen"), + Literal::Float { bits } => ("double".to_string(), format!("0x{:016X}", bits)), }; if val_ty != lty { return Err(CodegenError::Internal(format!( @@ -1225,7 +1225,7 @@ impl<'a> Emitter<'a> { (format!("@{g}"), "ptr".into()) } Literal::Unit => ("0".into(), "i8".into()), - Literal::Float { .. } => unimplemented!("Floats milestone iter 4: codegen"), + Literal::Float { bits } => (format!("0x{:016X}", bits), "double".into()), }), Term::Var { name } => { // Iter 16d: `__unreachable__` is a polymorphic bottom @@ -2877,4 +2877,45 @@ mod tests { "gc IR should not declare/define any per-type drop fn. IR was:\n{ir_gc}" ); } + + /// Floats iter 4.1 RED: a `Literal::Float { bits: 0x3ff8_0000_0000_0000 }` + /// (= `1.5_f64`) lowers in a `Const` definition as an LLVM hex-float + /// `double` SSA constant. The exact IR snippet pinned: `@ail_t_k = + /// constant double 0x3FF8000000000000`. + #[test] + fn lowers_float_const_to_hex_double() { + use ailang_core::ast::*; + let m = Module { + schema: ailang_core::SCHEMA.to_string(), + name: "t".into(), + imports: vec![], + defs: vec![ + Def::Const(ConstDef { + name: "k".into(), + ty: Type::float(), + value: Term::Lit { lit: Literal::Float { bits: 0x3ff8_0000_0000_0000u64 } }, + doc: None, + }), + Def::Fn(FnDef { + name: "main".into(), + ty: Type::Fn { + params: vec![], + ret: Box::new(Type::unit()), + effects: vec![], + param_modes: vec![], + ret_mode: ParamMode::Implicit, + }, + params: vec![], + body: Term::Lit { lit: Literal::Unit }, + suppress: vec![], + doc: None, + }), + ], + }; + let ir = emit_ir(&m).unwrap(); + assert!( + ir.contains("@ail_t_k = constant double 0x3FF8000000000000"), + "ir missing the Float literal lowering: {ir}" + ); + } } diff --git a/crates/ailang-codegen/src/synth.rs b/crates/ailang-codegen/src/synth.rs index 2ef9618..cf82811 100644 --- a/crates/ailang-codegen/src/synth.rs +++ b/crates/ailang-codegen/src/synth.rs @@ -18,6 +18,7 @@ pub(crate) fn llvm_type(t: &Type) -> Result { "Bool" => Ok("i1".into()), "Unit" => Ok("i8".into()), "Str" => Ok("ptr".into()), + "Float" => Ok("double".into()), // All other type names are treated as ADT (boxed). // If the typechecker didn't reject this earlier, it's // intentional — otherwise `ptr` would mask a wrong value. @@ -207,6 +208,7 @@ pub(crate) fn type_descriptor(t: &Type) -> String { "Bool" => "B".into(), "Unit" => "U".into(), "Str" => "S".into(), + "Float" => "Fl".into(), other => format!("F{other}"), }; if args.is_empty() {