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:
@@ -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"));
|
||||
}
|
||||
Reference in New Issue
Block a user