Skip to main content

weir/callgraph/
program.rs

1use std::sync::Arc;
2
3use super::OP_ID;
4use vyre::ir::{BufferAccess, BufferDecl, DataType, Expr, Ident, Node, Program};
5
6/// Build a single-dispatch Program that OR-merges a direct call-edge
7/// bitset with the transitive-closure bitset produced by
8/// [`crate::points_to::andersen_points_to`] into the final
9/// callgraph edge bitset.
10///
11/// `direct_edges_in` and `indirect_sites_in` are read-only bitsets
12/// over `node_count` call-site lanes. `pts_closure_in` is the
13/// points-to closure for each indirect call-site. `callgraph_out` is
14/// the final bitset written lane-by-lane.
15///
16/// `node_count` is the number of call sites (one bit per site).
17#[must_use]
18pub fn callgraph_build(
19    direct_edges_in: &str,
20    indirect_sites_in: &str,
21    pts_closure_in: &str,
22    callgraph_out: &str,
23) -> Program {
24    callgraph_build_with_count(
25        direct_edges_in,
26        indirect_sites_in,
27        pts_closure_in,
28        callgraph_out,
29        4,
30    )
31}
32
33/// Version that takes the number of call-site lanes explicitly.
34#[must_use]
35pub fn callgraph_build_with_count(
36    direct_edges_in: &str,
37    indirect_sites_in: &str,
38    pts_closure_in: &str,
39    callgraph_out: &str,
40    node_count: u32,
41) -> Program {
42    let domain = crate::graph_layout::LinearDomain::new(node_count);
43    let words = domain.bitset_words();
44    let w = Expr::InvocationId { axis: 0 };
45
46    let body = vec![
47        Node::let_bind("direct", Expr::load(direct_edges_in, w.clone())),
48        Node::let_bind(
49            "indirect",
50            Expr::bitand(
51                Expr::load(indirect_sites_in, w.clone()),
52                Expr::load(pts_closure_in, w.clone()),
53            ),
54        ),
55        Node::store(
56            callgraph_out,
57            w.clone(),
58            Expr::bitor(Expr::var("direct"), Expr::var("indirect")),
59        ),
60    ];
61
62    let buffers = vec![
63        BufferDecl::storage(direct_edges_in, 0, BufferAccess::ReadOnly, DataType::U32)
64            .with_count(words),
65        BufferDecl::storage(indirect_sites_in, 1, BufferAccess::ReadOnly, DataType::U32)
66            .with_count(words),
67        BufferDecl::storage(pts_closure_in, 2, BufferAccess::ReadOnly, DataType::U32)
68            .with_count(words),
69        BufferDecl::storage(callgraph_out, 3, BufferAccess::ReadWrite, DataType::U32)
70            .with_count(words),
71    ];
72
73    Program::wrapped(
74        buffers,
75        [256, 1, 1],
76        vec![Node::Region {
77            generator: Ident::from(OP_ID),
78            source_region: None,
79            body: Arc::new(vec![Node::if_then(
80                Expr::lt(w.clone(), Expr::u32(words)),
81                body,
82            )]),
83        }],
84    )
85}