use crate::exec::compute::fpu;
use crate::exec::compute::fpu::nan_handling::box_f32;
use crate::isa::fp::RoundingMode;
use crate::isa::op::AluOp;
fn fadd_f32_rm(a: f32, b: f32, rm: RoundingMode) -> f32 {
let ba = box_f32(a);
let bb = box_f32(b);
let result = fpu::execute_full_rm(AluOp::FAdd, ba, bb, 0, false, true, rm).0;
f32::from_bits(result as u32)
}
#[test]
fn test_rounding_rne() {
let result = fadd_f32_rm(1.0, 2.0, RoundingMode::Rne);
assert_eq!(result, 3.0);
let result = fadd_f32_rm(1.0e30, 1.0e30, RoundingMode::Rne);
assert_eq!(result, 2.0e30);
}
#[test]
fn test_rounding_rtz() {
let result = fadd_f32_rm(1.0, 2.0, RoundingMode::Rtz);
assert_eq!(result, 3.0);
let rtz_result = fadd_f32_rm(1.0e-38, 1.0e-38, RoundingMode::Rtz);
let rne_result = fadd_f32_rm(1.0e-38, 1.0e-38, RoundingMode::Rne);
assert!(rtz_result <= rne_result, "RTZ should produce result <= RNE for positive values");
assert!(rtz_result >= 0.0, "RTZ of positive inputs should be non-negative");
}
#[test]
fn test_rounding_rdn() {
let result = fadd_f32_rm(1.0, 2.0, RoundingMode::Rdn);
assert_eq!(result, 3.0);
let rdn_result = fadd_f32_rm(1.0e-38, 1.0e-38, RoundingMode::Rdn);
let rup_result = fadd_f32_rm(1.0e-38, 1.0e-38, RoundingMode::Rup);
assert!(rdn_result <= rup_result, "RDN result should be <= RUP result");
}
#[test]
fn test_rounding_rup() {
let result = fadd_f32_rm(1.0, 2.0, RoundingMode::Rup);
assert_eq!(result, 3.0);
let rup_result = fadd_f32_rm(1.0e-38, 1.0e-38, RoundingMode::Rup);
let rdn_result = fadd_f32_rm(1.0e-38, 1.0e-38, RoundingMode::Rdn);
assert!(rup_result >= rdn_result, "RUP result should be >= RDN result");
}
#[test]
fn test_rounding_rmm() {
let result = fadd_f32_rm(1.0, 2.0, RoundingMode::Rmm);
assert_eq!(result, 3.0);
let rmm_result = fadd_f32_rm(1.0e10, 1.0, RoundingMode::Rmm);
let rne_result = fadd_f32_rm(1.0e10, 1.0, RoundingMode::Rne);
assert_eq!(rmm_result, rne_result, "RMM and RNE should agree for non-ties");
}
#[test]
fn rounding_mode_from_bits_valid() {
assert_eq!(RoundingMode::from_bits(0b000), Some(RoundingMode::Rne));
assert_eq!(RoundingMode::from_bits(0b001), Some(RoundingMode::Rtz));
assert_eq!(RoundingMode::from_bits(0b010), Some(RoundingMode::Rdn));
assert_eq!(RoundingMode::from_bits(0b011), Some(RoundingMode::Rup));
assert_eq!(RoundingMode::from_bits(0b100), Some(RoundingMode::Rmm));
}
#[test]
fn rounding_mode_from_bits_reserved() {
assert_eq!(RoundingMode::from_bits(0b101), None);
assert_eq!(RoundingMode::from_bits(0b110), None);
}
#[test]
fn rounding_mode_from_bits_dynamic() {
assert_eq!(RoundingMode::from_bits(0b111), None);
}
#[test]
fn rounding_mode_irrelevant_for_comparisons() {
let a = box_f32(1.0);
let b = box_f32(2.0);
for rm in [
RoundingMode::Rne,
RoundingMode::Rtz,
RoundingMode::Rdn,
RoundingMode::Rup,
RoundingMode::Rmm,
] {
let result = fpu::execute_full_rm(AluOp::FEq, a, b, 0, false, true, rm).0;
assert_eq!(result, 0, "FEq(1.0, 2.0) should be 0 for all rounding modes");
}
}
#[test]
fn rounding_mode_irrelevant_for_sign_injection() {
#[allow(clippy::approx_constant)]
let pos = box_f32(3.14);
let neg = box_f32(-1.0);
for rm in [
RoundingMode::Rne,
RoundingMode::Rtz,
RoundingMode::Rdn,
RoundingMode::Rup,
RoundingMode::Rmm,
] {
let result = fpu::execute_full_rm(AluOp::FSgnJ, pos, neg, 0, false, true, rm).0;
let res_f32 = f32::from_bits(result as u32);
assert!(res_f32.is_sign_negative(), "FSgnJ(+, -) should produce negative");
#[allow(clippy::approx_constant)]
{
assert!((res_f32.abs() - 3.14f32).abs() < 1e-6);
}
}
}