use super::prepared::{
solve_prepared_borrowed_many_with_scratch_via, solve_prepared_borrowed_via,
solve_prepared_borrowed_with_scratch_via,
};
use crate::dispatch_input_cache::OwnedDispatchInputs;
use crate::ifds_csr_prepare::{
prepare_ifds_csr_borrowed_via, prepare_ifds_csr_borrowed_with_scratch_via,
};
use crate::ifds_gpu::validate_ifds_problem;
use crate::ifds_resident_types::IfdsBorrowedSolveScratch;
use vyre_foundation::ir::Program;
#[allow(clippy::too_many_arguments)]
pub fn solve_via<F>(
dispatch: &F,
num_procs: u32,
blocks_per_proc: u32,
facts_per_proc: u32,
intra_edges: &[(u32, u32, u32)],
inter_edges: &[(u32, u32, u32, u32)],
flow_gen: &[(u32, u32, u32)],
flow_kill: &[(u32, u32, u32)],
seed_facts: &[(u32, u32, u32)],
max_iterations: u32,
) -> Result<Vec<u32>, String>
where
F: Fn(&Program, &[Vec<u8>], Option<[u32; 3]>) -> Result<Vec<Vec<u8>>, String>,
{
let owned_inputs = OwnedDispatchInputs::new();
let dispatch_borrowed = |program: &Program,
inputs: &[&[u8]],
grid_override: Option<[u32; 3]>| {
owned_inputs.dispatch_refreshing_slots(program, inputs, grid_override, &[5, 6], dispatch)
};
solve_borrowed_via(
&dispatch_borrowed,
num_procs,
blocks_per_proc,
facts_per_proc,
intra_edges,
inter_edges,
flow_gen,
flow_kill,
seed_facts,
max_iterations,
)
}
#[allow(clippy::too_many_arguments)]
pub fn solve_borrowed_via<F>(
dispatch: &F,
num_procs: u32,
blocks_per_proc: u32,
facts_per_proc: u32,
intra_edges: &[(u32, u32, u32)],
inter_edges: &[(u32, u32, u32, u32)],
flow_gen: &[(u32, u32, u32)],
flow_kill: &[(u32, u32, u32)],
seed_facts: &[(u32, u32, u32)],
max_iterations: u32,
) -> Result<Vec<u32>, String>
where
F: Fn(&Program, &[&[u8]], Option<[u32; 3]>) -> Result<Vec<Vec<u8>>, String>,
{
crate::dispatch_decode::require_positive_iterations("weir IFDS GPU solve", max_iterations)?;
if seed_facts.is_empty() {
return Ok(Vec::new());
}
validate_ifds_problem(
"weir IFDS GPU solve",
num_procs,
blocks_per_proc,
facts_per_proc,
intra_edges,
inter_edges,
flow_gen,
flow_kill,
seed_facts,
)?;
let prepared = prepare_ifds_csr_borrowed_via(
dispatch,
num_procs,
blocks_per_proc,
facts_per_proc,
intra_edges,
inter_edges,
flow_gen,
flow_kill,
)?;
let reached = solve_prepared_borrowed_via(dispatch, &prepared, seed_facts, max_iterations)?;
for &node in &reached {
let (proc_id, block_id, fact_id) = vyre_primitives::graph::exploded::decode_node(node);
if proc_id >= prepared.shape.num_procs
|| block_id >= prepared.shape.blocks_per_proc
|| fact_id >= prepared.shape.facts_per_proc
{
return Err(format!(
"ifds solve_via output encoded node {node} decodes out of domain: proc={proc_id}, block={block_id}, fact={fact_id}. Fix: reject GPU frontier tail bits before returning solver output."
));
}
}
Ok(reached)
}
#[allow(clippy::too_many_arguments)]
pub fn solve_borrowed_with_scratch_via<F>(
dispatch: &F,
num_procs: u32,
blocks_per_proc: u32,
facts_per_proc: u32,
intra_edges: &[(u32, u32, u32)],
inter_edges: &[(u32, u32, u32, u32)],
flow_gen: &[(u32, u32, u32)],
flow_kill: &[(u32, u32, u32)],
seed_facts: &[(u32, u32, u32)],
max_iterations: u32,
scratch: &mut IfdsBorrowedSolveScratch,
) -> Result<Vec<u32>, String>
where
F: Fn(&Program, &[&[u8]], Option<[u32; 3]>, &mut Vec<Vec<u8>>) -> Result<(), String>,
{
crate::dispatch_decode::require_positive_iterations("weir IFDS GPU solve", max_iterations)?;
if seed_facts.is_empty() {
return Ok(Vec::new());
}
validate_ifds_problem(
"weir IFDS GPU solve",
num_procs,
blocks_per_proc,
facts_per_proc,
intra_edges,
inter_edges,
flow_gen,
flow_kill,
seed_facts,
)?;
let prepared = prepare_ifds_csr_borrowed_with_scratch_via(
dispatch,
num_procs,
blocks_per_proc,
facts_per_proc,
intra_edges,
inter_edges,
flow_gen,
flow_kill,
&mut scratch.prepare,
)?;
solve_prepared_borrowed_with_scratch_via(
dispatch,
&prepared,
seed_facts,
max_iterations,
&mut scratch.solve,
)
}
#[allow(clippy::too_many_arguments)]
pub fn solve_borrowed_many_with_scratch_via<F>(
dispatch: &F,
num_procs: u32,
blocks_per_proc: u32,
facts_per_proc: u32,
intra_edges: &[(u32, u32, u32)],
inter_edges: &[(u32, u32, u32, u32)],
flow_gen: &[(u32, u32, u32)],
flow_kill: &[(u32, u32, u32)],
seed_sets: &[&[(u32, u32, u32)]],
max_iterations: u32,
scratch: &mut IfdsBorrowedSolveScratch,
) -> Result<Vec<Vec<u32>>, String>
where
F: Fn(&Program, &[&[u8]], Option<[u32; 3]>, &mut Vec<Vec<u8>>) -> Result<(), String>,
{
if seed_sets.is_empty() {
return Ok(Vec::new());
}
crate::dispatch_decode::require_positive_iterations(
"weir IFDS GPU many solve",
max_iterations,
)?;
if seed_sets.iter().all(|seed_facts| seed_facts.is_empty()) {
validate_ifds_problem(
"weir IFDS GPU many solve",
num_procs,
blocks_per_proc,
facts_per_proc,
intra_edges,
inter_edges,
flow_gen,
flow_kill,
&[],
)?;
return crate::staging_reserve::reserved_result_rows(
seed_sets.len(),
"borrowed IFDS empty result row",
);
}
validate_ifds_problem(
"weir IFDS GPU many solve",
num_procs,
blocks_per_proc,
facts_per_proc,
intra_edges,
inter_edges,
flow_gen,
flow_kill,
&[],
)?;
let prepared = prepare_ifds_csr_borrowed_with_scratch_via(
dispatch,
num_procs,
blocks_per_proc,
facts_per_proc,
intra_edges,
inter_edges,
flow_gen,
flow_kill,
&mut scratch.prepare,
)?;
solve_prepared_borrowed_many_with_scratch_via(
dispatch,
&prepared,
seed_sets,
max_iterations,
&mut scratch.solve,
)
}
#[allow(clippy::too_many_arguments)]
pub fn solve_borrowed_many_via<F>(
dispatch: &F,
num_procs: u32,
blocks_per_proc: u32,
facts_per_proc: u32,
intra_edges: &[(u32, u32, u32)],
inter_edges: &[(u32, u32, u32, u32)],
flow_gen: &[(u32, u32, u32)],
flow_kill: &[(u32, u32, u32)],
seed_sets: &[&[(u32, u32, u32)]],
max_iterations: u32,
) -> Result<Vec<Vec<u32>>, String>
where
F: Fn(&Program, &[&[u8]], Option<[u32; 3]>) -> Result<Vec<Vec<u8>>, String>,
{
let mut scratch = IfdsBorrowedSolveScratch::default();
solve_borrowed_many_with_scratch_via(
&|program, inputs, grid, outputs| {
let result = dispatch(program, inputs, grid)?;
crate::output_scratch::replace_outputs_preserving_slots(outputs, result);
Ok(())
},
num_procs,
blocks_per_proc,
facts_per_proc,
intra_edges,
inter_edges,
flow_gen,
flow_kill,
seed_sets,
max_iterations,
&mut scratch,
)
}