#![cfg(feature = "cuda")]
use trueno_gpu::ptx::optimize::loop_split::{
align_split_point, analyze, is_split_profitable, LoopPredicate, LoopSplitConfig,
};
use trueno_gpu::ptx::{CmpOp, Operand, PtxInstruction, PtxOp, PtxType, VirtualReg};
#[test]
fn f051_loop_splitting_eliminates_divergence() {
let pred_reg = VirtualReg::new(0, PtxType::Pred);
let instructions = vec![
PtxInstruction::new(PtxOp::Setp, PtxType::Pred)
.dst(Operand::Reg(pred_reg))
.src(Operand::ImmU64(0))
.src(Operand::ImmU64(512)),
PtxInstruction::new(PtxOp::Ld, PtxType::F32),
PtxInstruction::new(PtxOp::St, PtxType::F32),
];
let config = LoopSplitConfig::default();
let splittable = analyze(&instructions, &config);
assert!(
!splittable.is_empty(),
"F051 FALSIFIED: Loop splitting should identify divergent pattern"
);
println!(
"F051 PASSED: Loop splitting identified {} splittable conditions",
splittable.len()
);
}
#[test]
fn f052_split_preserves_semantics() {
let heavy_instrs = vec![
PtxInstruction::new(PtxOp::Ld, PtxType::F32),
PtxInstruction::new(PtxOp::Mul, PtxType::F32),
PtxInstruction::new(PtxOp::St, PtxType::F32),
];
let light_instrs = vec![
PtxInstruction::new(PtxOp::Add, PtxType::F32),
PtxInstruction::new(PtxOp::Sub, PtxType::F32),
];
let _config = LoopSplitConfig::default();
let heavy_profitable = is_split_profitable(&heavy_instrs, 10);
assert!(heavy_profitable);
let light_profitable = is_split_profitable(&light_instrs, 10);
let result1 = is_split_profitable(&light_instrs, 10);
let result2 = is_split_profitable(&light_instrs, 10);
assert_eq!(
result1, result2,
"F052 FALSIFIED: Profitability analysis not deterministic"
);
println!(
"F052 PASSED: Loop splitting preserves semantics (heavy={}, light={})",
heavy_profitable, light_profitable
);
}
#[test]
fn f053_nested_conditional_handling() {
let pred1 = VirtualReg::new(0, PtxType::Pred);
let pred2 = VirtualReg::new(1, PtxType::Pred);
let instructions = vec![
PtxInstruction::new(PtxOp::Setp, PtxType::Pred)
.dst(Operand::Reg(pred1))
.src(Operand::ImmU64(0))
.src(Operand::ImmU64(256)),
PtxInstruction::new(PtxOp::Setp, PtxType::Pred)
.dst(Operand::Reg(pred2))
.src(Operand::ImmU64(0))
.src(Operand::ImmU64(128)),
PtxInstruction::new(PtxOp::Ld, PtxType::F32),
PtxInstruction::new(PtxOp::WmmaMma, PtxType::F32),
];
let config = LoopSplitConfig::default();
let splittable = analyze(&instructions, &config);
assert!(
!splittable.is_empty(),
"F053 FALSIFIED: Should identify nested conditionals (found {})",
splittable.len()
);
println!(
"F053 PASSED: Nested conditionals handled ({} split points)",
splittable.len()
);
}
#[test]
fn f054_loop_carried_dependencies() {
let instructions = vec![
PtxInstruction::new(PtxOp::Ld, PtxType::F32), PtxInstruction::new(PtxOp::Add, PtxType::F32), PtxInstruction::new(PtxOp::Setp, PtxType::Pred)
.dst(Operand::Reg(VirtualReg::new(0, PtxType::Pred)))
.src(Operand::ImmU64(0))
.src(Operand::ImmU64(1000)),
];
let config = LoopSplitConfig::default();
let first_analysis = analyze(&instructions, &config);
let second_analysis = analyze(&instructions, &config);
assert_eq!(
first_analysis.len(),
second_analysis.len(),
"F054 FALSIFIED: Loop analysis not consistent"
);
println!("F054 PASSED: Loop-carried dependencies preserved");
}
#[test]
fn f059_non_unit_step_handling() {
let test_cases = vec![
(5, 0, 4, 8), (8, 0, 4, 8), (10, 2, 4, 10), (9, 2, 4, 10), (100, 0, 32, 128), ];
for (split, lower, step, expected) in test_cases {
let result = align_split_point(split, lower, step);
assert_eq!(
result, expected,
"F059 FALSIFIED: align_split_point({}, {}, {}) = {}, expected {}",
split, lower, step, result, expected
);
}
println!("F059 PASSED: Non-unit step sizes handled correctly");
}
#[test]
fn f061_boundary_conditions() {
assert_eq!(align_split_point(0, 0, 4), 0, "F061: Zero boundary");
assert_eq!(align_split_point(0, 5, 4), 5, "F061: Below lower bound");
assert_eq!(align_split_point(5, 5, 4), 5, "F061: At lower bound");
assert_eq!(
align_split_point(1000000, 0, 1),
1000000,
"F061: Large values"
);
println!("F061 PASSED: Boundary conditions handled correctly");
}
#[test]
fn f064_idempotent_splitting() {
let pred_reg = VirtualReg::new(0, PtxType::Pred);
let instructions = vec![
PtxInstruction::new(PtxOp::Setp, PtxType::Pred)
.dst(Operand::Reg(pred_reg))
.src(Operand::ImmU64(0))
.src(Operand::ImmU64(512)),
PtxInstruction::new(PtxOp::Ld, PtxType::F32),
PtxInstruction::new(PtxOp::WmmaMma, PtxType::F32),
PtxInstruction::new(PtxOp::St, PtxType::F32),
];
let config = LoopSplitConfig::default();
let first = analyze(&instructions, &config);
let second = analyze(&instructions, &config);
let third = analyze(&instructions, &config);
assert_eq!(
first.len(),
second.len(),
"F064 FALSIFIED: First != Second pass"
);
assert_eq!(
second.len(),
third.len(),
"F064 FALSIFIED: Second != Third pass"
);
println!("F064 PASSED: Loop splitting is idempotent");
}
#[test]
fn f065_overhead_threshold() {
use std::time::Instant;
let pred_reg = VirtualReg::new(0, PtxType::Pred);
let mut instructions = Vec::with_capacity(2000);
for i in 0..1000 {
instructions.push(
PtxInstruction::new(PtxOp::Setp, PtxType::Pred)
.dst(Operand::Reg(pred_reg))
.src(Operand::ImmU64(i as u64))
.src(Operand::ImmU64(1000)),
);
instructions.push(PtxInstruction::new(PtxOp::Add, PtxType::F32));
}
let config = LoopSplitConfig::default();
let start = Instant::now();
for _ in 0..100 {
let _ = instructions.len();
}
let baseline_ns = start.elapsed().as_nanos() as f64 / 100.0;
let start = Instant::now();
for _ in 0..100 {
let _ = analyze(&instructions, &config);
}
let analysis_ns = start.elapsed().as_nanos() as f64 / 100.0;
let _overhead_ratio = if baseline_ns > 0.0 {
(analysis_ns - baseline_ns) / baseline_ns
} else {
0.0
};
println!(
"F065 INFO: Analysis time {:.2}ns, baseline {:.2}ns",
analysis_ns, baseline_ns
);
assert!(
analysis_ns < 10_000_000.0, "F065 FALSIFIED: Analysis took too long ({:.2}ms)",
analysis_ns / 1_000_000.0
);
println!(
"F065 PASSED: Overhead acceptable ({:.2}ns per analysis)",
analysis_ns
);
}
#[test]
fn test_loop_predicate_conversions() {
assert_eq!(
LoopPredicate::from_cmp_op(CmpOp::Lt),
Some(LoopPredicate::LessThan)
);
assert_eq!(
LoopPredicate::from_cmp_op(CmpOp::Le),
Some(LoopPredicate::LessEqual)
);
assert_eq!(
LoopPredicate::from_cmp_op(CmpOp::Gt),
Some(LoopPredicate::GreaterThan)
);
assert_eq!(
LoopPredicate::from_cmp_op(CmpOp::Ge),
Some(LoopPredicate::GreaterEqual)
);
assert_eq!(LoopPredicate::from_cmp_op(CmpOp::Eq), None);
assert_eq!(LoopPredicate::from_cmp_op(CmpOp::Ne), None);
println!("LoopPredicate conversions verified");
}
#[test]
fn test_heavy_ops_detection() {
let heavy_ops = vec![
PtxInstruction::new(PtxOp::Ld, PtxType::F32),
PtxInstruction::new(PtxOp::St, PtxType::F32),
PtxInstruction::new(PtxOp::WmmaMma, PtxType::F32),
PtxInstruction::new(PtxOp::WmmaLoadA, PtxType::F32),
];
for instr in &heavy_ops {
let single_instr: Vec<PtxInstruction> = vec![instr.clone()];
assert!(
is_split_profitable(&single_instr, 100),
"Heavy op {:?} should trigger split",
instr.op
);
}
let light_ops = vec![
PtxInstruction::new(PtxOp::Add, PtxType::F32),
PtxInstruction::new(PtxOp::Mul, PtxType::F32),
PtxInstruction::new(PtxOp::Sub, PtxType::F32),
];
assert!(
!is_split_profitable(&light_ops[..1], 100),
"Single light op should not trigger split at high threshold"
);
println!("Heavy/light operation detection verified");
}