weirflow 0.1.0

GPU-first dataflow analysis primitives for Vyre and Santh compiler pipelines.
Documentation
#![allow(clippy::too_many_arguments)]

use crate::fixed_point_batch::FixedPointBatch;

impl<'a, F> FixedPointBatch<'a, F>
where
    F: Fn(&vyre::ir::Program, &[&[u8]], Option<[u32; 3]>, &mut Vec<Vec<u8>>) -> Result<(), String>,
{
    /// Prepare IFDS CSR buffers for repeated batch solves.
    pub fn prepare_ifds(
        &mut self,
        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)],
    ) -> Result<crate::ifds_gpu::PreparedIfdsCsr, String> {
        crate::ifds_gpu::prepare_ifds_csr_borrowed_with_scratch_via(
            self.dispatch,
            num_procs,
            blocks_per_proc,
            facts_per_proc,
            intra_edges,
            inter_edges,
            flow_gen,
            flow_kill,
            &mut self.ifds_prepare_scratch,
        )
    }

    /// Run IFDS reachability while reusing retained batch preparation and solve scratch.
    #[allow(clippy::too_many_arguments)]
    pub fn ifds(
        &mut self,
        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> {
        if seed_facts.is_empty() {
            crate::dispatch_decode::require_positive_iterations(
                "weir fixed-point batch IFDS solve",
                max_iterations,
            )?;
            return Ok(Vec::new());
        }
        let prepared = crate::ifds_gpu::prepare_ifds_csr_borrowed_with_scratch_via(
            self.dispatch,
            num_procs,
            blocks_per_proc,
            facts_per_proc,
            intra_edges,
            inter_edges,
            flow_gen,
            flow_kill,
            &mut self.ifds_prepare_scratch,
        )?;
        crate::ifds_gpu::solve_prepared_borrowed_with_scratch_via(
            self.dispatch,
            &prepared,
            seed_facts,
            max_iterations,
            &mut self.ifds_scratch,
        )
    }

    /// Run IFDS reachability into caller-owned result storage while reusing
    /// retained batch preparation and solve scratch.
    #[allow(clippy::too_many_arguments)]
    pub fn ifds_into(
        &mut self,
        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: &mut Vec<u32>,
    ) -> Result<(), String> {
        if seed_facts.is_empty() {
            crate::dispatch_decode::require_positive_iterations(
                "weir fixed-point batch IFDS solve into",
                max_iterations,
            )?;
            result.clear();
            return Ok(());
        }
        let prepared = crate::ifds_gpu::prepare_ifds_csr_borrowed_with_scratch_via(
            self.dispatch,
            num_procs,
            blocks_per_proc,
            facts_per_proc,
            intra_edges,
            inter_edges,
            flow_gen,
            flow_kill,
            &mut self.ifds_prepare_scratch,
        )?;
        crate::ifds_gpu::solve_prepared_borrowed_with_scratch_into_via(
            self.dispatch,
            &prepared,
            seed_facts,
            max_iterations,
            &mut self.ifds_scratch,
            result,
        )
    }

    /// Run several IFDS reachability queries while preparing the IFDS CSR once
    /// and reusing retained batch scratch across every seed set.
    #[allow(clippy::too_many_arguments)]
    pub fn ifds_many(
        &mut self,
        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> {
        if seed_sets.is_empty() {
            return Ok(Vec::new());
        }
        if seed_sets.iter().all(|seed_facts| seed_facts.is_empty()) {
            crate::dispatch_decode::require_positive_iterations(
                "weir fixed-point batch many IFDS solve",
                max_iterations,
            )?;
            return crate::staging_reserve::reserved_result_rows(
                seed_sets.len(),
                "fixed-point batch empty IFDS result row",
            );
        }
        let prepared = self.prepare_ifds(
            num_procs,
            blocks_per_proc,
            facts_per_proc,
            intra_edges,
            inter_edges,
            flow_gen,
            flow_kill,
        )?;
        self.ifds_prepared_many(&prepared, seed_sets, max_iterations)
    }

    /// Run several IFDS reachability queries while preparing the IFDS CSR once
    /// and writing into caller-owned result rows.
    #[allow(clippy::too_many_arguments)]
    pub fn ifds_many_into(
        &mut self,
        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,
        results: &mut Vec<Vec<u32>>,
    ) -> Result<(), String> {
        if seed_sets.is_empty() {
            results.clear();
            return Ok(());
        }
        if seed_sets.iter().all(|seed_facts| seed_facts.is_empty()) {
            crate::dispatch_decode::require_positive_iterations(
                "weir fixed-point batch many IFDS solve into",
                max_iterations,
            )?;
            crate::staging_reserve::resize_result_rows(
                results,
                seed_sets.len(),
                "fixed-point batch IFDS result row",
            )?;
            crate::staging_reserve::clear_result_rows(results);
            return Ok(());
        }
        let prepared = self.prepare_ifds(
            num_procs,
            blocks_per_proc,
            facts_per_proc,
            intra_edges,
            inter_edges,
            flow_gen,
            flow_kill,
        )?;
        self.ifds_prepared_many_into(&prepared, seed_sets, max_iterations, results)
    }
}