floats iter 4.3: codegen Float comparison arms (fcmp olt/ole/ogt/oge/UNE) + lower_eq Float
This commit is contained in:
@@ -2320,6 +2320,13 @@ impl<'a> Emitter<'a> {
|
||||
let _ = b;
|
||||
Ok(("true".into(), "i1".into()))
|
||||
}
|
||||
"Float" => {
|
||||
let dst = self.fresh_ssa();
|
||||
self.body.push_str(&format!(
|
||||
" {dst} = fcmp oeq double {a}, {b}\n"
|
||||
));
|
||||
Ok((dst, "i1".into()))
|
||||
}
|
||||
other => Err(CodegenError::Internal(format!(
|
||||
"`==` not supported for type `{other}` \
|
||||
(ADT and user-defined types lack a structural-equality scheme)"
|
||||
@@ -3003,4 +3010,70 @@ mod tests {
|
||||
"Float arithmetic missing (no `fadd double` in IR): {ir}"
|
||||
);
|
||||
}
|
||||
|
||||
/// Floats iter 4.3 RED: `(< 1.5 2.5)` lowers as `fcmp olt double`;
|
||||
/// `(!= 1.5 1.5)` lowers as `fcmp UNE double` (NOT `one`); `(== 1.5
|
||||
/// 1.5)` lowers as `fcmp oeq double`. Int regressions still emit
|
||||
/// `icmp slt i64` / `icmp ne i64` / `icmp eq i64`.
|
||||
#[test]
|
||||
fn lowers_float_comparison_dispatched() {
|
||||
use ailang_core::ast::*;
|
||||
fn fn_def(name: &str, body: Term) -> Def {
|
||||
Def::Fn(FnDef {
|
||||
name: name.into(),
|
||||
ty: Type::Fn {
|
||||
params: vec![],
|
||||
ret: Box::new(Type::bool_()),
|
||||
effects: vec![],
|
||||
param_modes: vec![],
|
||||
ret_mode: ParamMode::Implicit,
|
||||
},
|
||||
params: vec![],
|
||||
body,
|
||||
suppress: vec![],
|
||||
doc: None,
|
||||
})
|
||||
}
|
||||
fn cmp(op: &str, a: Term, b: Term) -> Term {
|
||||
Term::App {
|
||||
callee: Box::new(Term::Var { name: op.into() }),
|
||||
args: vec![a, b],
|
||||
tail: false,
|
||||
}
|
||||
}
|
||||
let f1 = Term::Lit { lit: Literal::Float { bits: 0x3ff8_0000_0000_0000u64 } };
|
||||
let f2 = Term::Lit { lit: Literal::Float { bits: 0x4004_0000_0000_0000u64 } };
|
||||
let i1 = Term::Lit { lit: Literal::Int { value: 1 } };
|
||||
let i2 = Term::Lit { lit: Literal::Int { value: 2 } };
|
||||
let main_def = 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 m = Module {
|
||||
schema: ailang_core::SCHEMA.to_string(),
|
||||
name: "t".into(),
|
||||
imports: vec![],
|
||||
defs: vec![
|
||||
fn_def("flt_f", cmp("<", f1.clone(), f2.clone())),
|
||||
fn_def("fne_f", cmp("!=", f1.clone(), f1.clone())),
|
||||
fn_def("feq_f", cmp("==", f1.clone(), f1.clone())),
|
||||
fn_def("flt_i", cmp("<", i1.clone(), i2.clone())),
|
||||
fn_def("fne_i", cmp("!=", i1.clone(), i2.clone())),
|
||||
fn_def("feq_i", cmp("==", i1.clone(), i2.clone())),
|
||||
main_def,
|
||||
],
|
||||
};
|
||||
let ir = emit_ir(&m).unwrap();
|
||||
assert!(ir.contains("fcmp olt double"), "missing `fcmp olt double`: {ir}");
|
||||
assert!(ir.contains("fcmp une double"), "missing `fcmp une double` (note: `une` not `one`): {ir}");
|
||||
assert!(ir.contains("fcmp oeq double"), "missing `fcmp oeq double`: {ir}");
|
||||
assert!(ir.contains("icmp slt i64"), "Int `<` regressed: {ir}");
|
||||
assert!(ir.contains("icmp ne i64"), "Int `!=` regressed: {ir}");
|
||||
assert!(ir.contains("icmp eq i64"), "Int `==` regressed: {ir}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,6 +281,15 @@ pub(crate) fn builtin_binop_typed(
|
||||
("<=", true, _) => Some(("icmp sle", "i64", "i1")),
|
||||
(">", true, _) => Some(("icmp sgt", "i64", "i1")),
|
||||
(">=", true, _) => Some(("icmp sge", "i64", "i1")),
|
||||
// Float comparison arms (Floats iter 4.3). Note: `!=` Float
|
||||
// uses `fcmp une` ("unordered or not equal") — NOT `one`
|
||||
// ("ordered and not equal"), which would return `false` for
|
||||
// `nan != nan` and violate IEEE / spec A5.
|
||||
("!=", _, true) => Some(("fcmp une", "double", "i1")),
|
||||
("<", _, true) => Some(("fcmp olt", "double", "i1")),
|
||||
("<=", _, true) => Some(("fcmp ole", "double", "i1")),
|
||||
(">", _, true) => Some(("fcmp ogt", "double", "i1")),
|
||||
(">=", _, true) => Some(("fcmp oge", "double", "i1")),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user