feat(ir/backend): add support for floating-point types and arithmetic

- Introduces F32 and F64 types and Float operand variant to the IR.
- Implements floating-point binary operations (FAdd, FSub, FMul, FDiv, FRem, FCmp) and FNeg unary op.
- Updates IR printer, validator, and builder to handle the new floating-point functionality.
- Extends the constant folding pass to evaluate floating-point expressions at compile time.
- Enhances x86_64 backend with XMM register support and floating-point codegen.
- Implements a fixed-point iteration pass for register type resolution to correctly allocate GPR vs XMM registers.
- Updates the linear scan allocator to manage multiple register classes (GPR, XMM).
- Adds System V ABI compliant handling for floating-point function arguments and return values.
- Includes comprehensive tests for IR validation, constant folding, and assembly generation.
This commit is contained in:
2026-04-27 20:53:44 +02:00
parent e7daccac47
commit 6727dd84e4
10 changed files with 1048 additions and 170 deletions
+113
View File
@@ -0,0 +1,113 @@
use scarlett::{builder::IrModuleBuilder, ir::*, validate::validate_module};
#[test]
fn test_float_ir() {
let mut module_builder = IrModuleBuilder::new();
let f64_ty = Type::F64;
let func_id = module_builder.new_function_id();
{
let f_builder =
module_builder.new_function(func_id, "float_math", vec![&f64_ty, &f64_ty], f64_ty);
let a = f_builder.get_param(0).unwrap();
let b = f_builder.get_param(1).unwrap();
let sum = f_builder.build_fadd(f64_ty, a, b);
let diff = f_builder.build_fsub(f64_ty, sum, a);
let prod = f_builder.build_fmul(f64_ty, diff, b);
let quot = f_builder.build_fdiv(f64_ty, prod, a);
let neg = f_builder.build_fneg(f64_ty, quot);
let is_gt = f_builder.build_fcmp(FCmpOp::Ogt, neg, Operand::Float(0.0));
let then_block = f_builder.create_block();
let else_block = f_builder.create_block();
f_builder.build_branch(is_gt, then_block, else_block);
f_builder.switch_to_block(then_block);
f_builder.build_return(f64_ty, neg);
f_builder.switch_to_block(else_block);
f_builder.build_return(f64_ty, Operand::Float(42.0));
}
module_builder.complete_function();
let module = module_builder.finish();
validate_module(&module).expect("Module validation failed");
let printed = format!("{}", module);
println!("{}", printed);
assert!(printed.contains("f64"));
assert!(printed.contains("fadd"));
assert!(printed.contains("fsub"));
assert!(printed.contains("fmul"));
assert!(printed.contains("fdiv"));
assert!(printed.contains("fneg"));
assert!(printed.contains("fcmp ogt"));
}
#[test]
fn test_float_constant_folding() {
let mut module_builder = IrModuleBuilder::new();
let f64_ty = Type::F64;
let func_id = module_builder.new_function_id();
{
let f_builder = module_builder.new_function(func_id, "fold_me", vec![], f64_ty);
let a = Operand::Float(10.0);
let b = Operand::Float(2.0);
let sum = f_builder.build_fadd(f64_ty, a, b); // 12.0
let prod = f_builder.build_fmul(f64_ty, sum, b); // 24.0
f_builder.build_return(f64_ty, prod);
}
module_builder.complete_function();
let mut module = module_builder.finish();
validate_module(&module).expect("Module validation failed");
scarlett::passes::cfp::fold_constants(&mut module);
let printed = format!("{}", module);
println!("{}", printed);
assert!(printed.contains("$24"));
assert!(!printed.contains("fadd"));
assert!(!printed.contains("fmul"));
}
#[test]
fn test_float_codegen() {
let mut module_builder = IrModuleBuilder::new();
let f64_ty = Type::F64;
let func_id = module_builder.new_function_id();
{
let f_builder =
module_builder.new_function(func_id, "add_floats", vec![&f64_ty, &f64_ty], f64_ty);
let a = f_builder.get_param(0).unwrap();
let b = f_builder.get_param(1).unwrap();
let res = f_builder.build_fadd(f64_ty, a, b);
f_builder.build_return(f64_ty, res);
}
module_builder.complete_function();
let module = module_builder.finish();
let assembly = scarlett::backend::x86_64::X86Backend::new(&module).compile_module();
println!("{}", assembly);
assert!(assembly.contains("addsd"));
assert!(assembly.contains("movsd"));
assert!(assembly.contains("%xmm0"));
assert!(assembly.contains("%xmm1"));
}