use super::*;
use crate::{IntArithOp, LogicalInstr as L};
#[test]
fn the_builder_folds_identical_instructions_and_pool_entries() {
let mut b = ExprBuilder::new();
let a = b.emit(L::LoadCol { col: 1 });
assert_eq!(b.emit(L::LoadCol { col: 1 }), a);
let c = b.emit(L::LoadCol { col: 2 });
assert_ne!(c, a);
let sum = b.emit(L::IntArith { op: IntArithOp::Add, a, b: c });
assert_eq!(b.emit(L::IntArith { op: IntArithOp::Add, a, b: c }), sum);
let s1 = b.add_const_bytes(b"x");
assert_eq!(b.add_const_bytes(b"x"), s1);
let l1 = b.emit(L::LoadConstStr { const_idx: s1 });
assert_eq!(b.emit(L::LoadConstStr { const_idx: s1 }), l1);
let prog = b.build(vec![Sink::Reg(sum)]).expect("a well-formed program");
assert_eq!(prog.instrs().len(), 4);
assert_eq!(prog.const_strings().len(), 1);
}
#[test]
fn a_lift_over_a_constant_folds_to_a_float_constant() {
for (val, unsigned, want) in [(-7, false, -7.0), (-1, true, u64::MAX as f64)] {
let mut b = ExprBuilder::new();
let c = b.emit(L::LoadConst { val, unsigned });
let lifted = b.emit(L::IntToFloat { a: c });
let prog = b.build(vec![Sink::Reg(lifted)]).expect("a well-formed program");
assert!(
matches!(prog.instrs(), [_, L::LoadConst { val, unsigned: false }] if f64::from_bits(*val as u64) == want),
"{val} unsigned={unsigned}"
);
}
let mut b = ExprBuilder::new();
let col = b.emit(L::LoadCol { col: 1 });
let lifted = b.emit(L::IntToFloat { a: col });
let prog = b.build(vec![Sink::Reg(lifted)]).expect("a well-formed program");
assert!(matches!(prog.instrs(), [L::LoadCol { .. }, L::IntToFloat { .. }]));
}
#[test]
fn a_range_check_over_the_same_range_check_folds() {
use gnitz_wire::FixedInt;
let mut b = ExprBuilder::new();
let col = b.emit(L::LoadCol { col: 1 });
let narrow = b.emit(L::IntCast { a: col, fi: FixedInt::I16 });
assert_eq!(b.emit(L::IntCast { a: narrow, fi: FixedInt::I16 }), narrow);
let narrower = b.emit(L::IntCast { a: narrow, fi: FixedInt::I8 });
assert_ne!(narrower, narrow);
let prog = b.build(vec![Sink::Reg(narrower)]).expect("a well-formed program");
assert_eq!(prog.instrs().len(), 3);
}
#[test]
fn a_to_micros_over_a_constant_folds_unless_it_overflows() {
let to_micros = |days: i64| {
let mut b = ExprBuilder::new();
let c = b.emit(L::LoadConst { val: days, unsigned: false });
let r = b.emit(L::Calendar {
op: crate::CalendarOp::ToMicros,
a: c,
micros: false,
});
b.build(vec![Sink::Reg(r)])
.expect("a well-formed program")
.instrs()
.to_vec()
};
assert!(matches!(
to_micros(2)[..],
[_, L::LoadConst { val: 172_800_000_000, unsigned: false }]
));
assert!(matches!(to_micros(i64::MAX)[..], [_, L::Calendar { .. }]));
}