Skip to main content

rucc_opt/
callgraph.rs

1//! Who calls whom in one translation unit, which components they form, and the order to walk them.
2//!
3//! Design: `spec/optimizer/34-ipa.md` sections 34.1 and 34.6. Section 34.6 puts this first and
4//! prices it at roughly five hundred lines: "A callgraph over the unit's functions, with direct
5//! edges from calls and a flag for indirect ones; visibility computed per symbol per 34.1; the
6//! condensation and its topological order; and an SCC-iterating driver that a pass supplies a
7//! transfer function to." Section 34.1 adds why the order is the one it is: "The traversal order is
8//! the callgraph's condensation in topological order, and every pass in this document is either
9//! callee-to-caller or caller-to-callee over it, with strongly connected components iterated to a
10//! fixpoint."
11//!
12//! Nothing in the pipeline reads this yet. It is here on its own because it is the walk every
13//! interprocedural analysis in document 34 performs, and a walk is much easier to argue about
14//! before there is an analysis sitting on top of it to argue about at the same time.
15//!
16//! # Why the components rather than a loop until nothing changes
17//!
18//! [`crate::nofree`] already does this walk by hand, and what it does is go round every body in the
19//! module until no answer moves. That is correct and it is what a first one of these looks like, and
20//! it costs a round over the whole unit for every step an answer has to travel. A chain of callers a
21//! hundred deep is a hundred rounds over every function in the file, and the SQLite amalgamation has
22//! two and a half thousand of them.
23//!
24//! Over the condensation it is one visit per component in an order that settles each of them before
25//! anything that calls into it, so an answer never has to travel between components twice. The only
26//! iteration left is inside a component, which is exactly where recursion is, and a component is
27//! almost always one function. That is not a micro-optimization, it is the difference between the
28//! analysis being quadratic in the unit and being linear in its edges, which is the thing section
29//! 34.5 warns about under "The analysis is quadratic on a large unit".
30//!
31//! # What a node is
32//!
33//! A node is a name, not a body. Every function the module has, defined or only declared, gets one,
34//! and so does every name some body calls that the module has no function of any kind for. That last
35//! kind exists because `rucc-safety` emits calls to names it interns without adding a function to
36//! hang them on, which is what tamnd/rucc#810 was about, and a graph that only knew about the
37//! functions would have no node to put those calls on and would quietly drop the edge.
38//!
39//! An alias gets a node as well when what it aliases is a function this module has, because a call
40//! to the alias is a call to that body and an analysis walking callee to caller needs the edge to
41//! see it. An ifunc does not get that edge: what it resolves to is chosen at load time and is not
42//! something this module can name, so the ifunc's node reaches the unknown and the resolver it names
43//! is recorded as having had its address taken, because the dynamic linker is going to call it and
44//! no edge here says so.
45//!
46//! # Trusting a body, which is section 34.1's gate
47//!
48//! "Every fact derived from a function body is conditional on the body being the one that runs."
49//! [`CallGraph::trusted_body`] is the only way to reach a body through this graph and it hands one
50//! back only when three things hold: the module has a definition, the linkage is not one the linker
51//! may throw away in favour of another object's, and the symbol is not one the dynamic linker may
52//! interpose. That is the same test [`crate::nofree`] applies and it is the same test for the same
53//! reason, and it is here so that the next analysis does not write it a third time.
54//!
55//! # Reaching the unknown
56//!
57//! [`CallGraph::reaches_unknown`] is one bit per node and it says the node can get to code this
58//! graph has no node for. It is set for a call through an address, for inline assembly, and for a
59//! target intrinsic, which is the "flag for indirect ones" section 34.6 asks for. It is also set for
60//! every node with no trusted body at all, which is the part worth saying out loud: a declaration
61//! calls nothing as far as this graph can see, and an analysis that read the edges alone would
62//! conclude that a call to `printf` reaches nothing and is therefore harmless. Folding that into the
63//! same bit means the safe reading is the one a consumer gets without having to remember anything.
64//!
65//! # Determinism
66//!
67//! Spec 03 requires the same input to give the same output, and this is one of the places where it
68//! is easy to lose by accident. Nodes come out in the order the module has its functions, then its
69//! aliases, then in the order the bodies first mention a name that had no node. Edges come out in
70//! the order the body makes the calls, with a repeat of the same callee dropped. A component's nodes
71//! are sorted by node index, and a component is iterated in that order. Nothing here iterates a hash
72//! map: the one that is here answers "which node is this name" and is never walked.
73//!
74//! # Where this lives
75//!
76//! Section 34.1 names a crate `rucc-ipa` once and document 15's crate table has no such crate, so
77//! there is nothing to be consistent with. Every module-level analysis this compiler has is already
78//! in `rucc-opt`, which is [`crate::nofree`], [`crate::heap`], [`crate::params`],
79//! [`crate::extents`], [`crate::image`] and [`crate::outside`], and the pipeline that would build
80//! this is in `rucc-opt` too. A crate holding one file that only `rucc-opt` calls is a layer
81//! boundary that buys nothing today. [`crate::nofree`] records the same kind of deviation for the
82//! same kind of reason.
83
84use std::collections::HashMap;
85
86use rucc_base::Symbol;
87use rucc_ir::{AliasKind, Datum, Extra, Func, FuncId, Inst, Linkage, Module, Opcode, Pic};
88
89/// One name in a [`CallGraph`].
90///
91/// A name rather than a body, because a call names something and whether this module has the body
92/// behind it is a separate question the graph answers separately.
93#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
94pub struct Node(u32);
95
96impl Node {
97    /// Where this node sits, which is what indexes the answers [`CallGraph::solve`] hands back.
98    #[must_use]
99    pub const fn index(self) -> usize {
100        self.0 as usize
101    }
102}
103
104/// What the graph knows about one name.
105#[derive(Debug, Clone)]
106struct Entry {
107    /// The name itself.
108    name: Symbol,
109    /// The module's function of that name, defined or only declared, and nothing when the name is
110    /// an alias or is something a body calls that the module never declared.
111    func: Option<FuncId>,
112    /// The same function again, and only when its body is the one that will run.
113    body: Option<FuncId>,
114    /// The nodes this one calls, in the order the body makes the calls, each of them once.
115    calls: Vec<Node>,
116    /// Whether this node can reach code the graph has no node for.
117    unknown: bool,
118    /// Whether anything other than a call in this unit can reach this function.
119    address_taken: bool,
120}
121
122/// The unit's call graph, its condensation, and the order to walk it in.
123///
124/// Built once from the module, for the reason every module-level analysis here is built once: the
125/// answer belongs to the callee and a pass is handed one function.
126#[derive(Debug, Clone, Default)]
127pub struct CallGraph {
128    /// One per name, in the order described under "Determinism" in the module comment.
129    entries: Vec<Entry>,
130    /// Which node a name is. Asked, never walked.
131    by_name: HashMap<Symbol, Node>,
132    /// The strongly connected components, callees before callers, each sorted by node index.
133    components: Vec<Vec<Node>>,
134    /// Which component each node landed in, indexed by node.
135    component_of: Vec<u32>,
136}
137
138impl CallGraph {
139    /// Builds the graph over everything the module can name.
140    ///
141    /// The `pic` argument is what the link is going to be, and it decides which definitions may be
142    /// interposed. See [`CallGraph::trusted_body`].
143    #[must_use]
144    pub fn of(module: &Module, pic: Pic) -> Self {
145        let mut graph = Self::default();
146        for id in module.funcs() {
147            let func = &module[id];
148            let body = (!func.is_declaration() && trusted(func, pic)).then_some(id);
149            let node = graph.intern(func.name);
150            let at = node.index();
151            graph.entries[at].func = Some(id);
152            graph.entries[at].body = body;
153            // A declaration reaches whatever the definition somewhere else reaches, and so does a
154            // definition this link is allowed to replace. Both are the unknown.
155            graph.entries[at].unknown = body.is_none();
156        }
157        // Aliases next, and before the bodies are read, so that a call to an alias finds the node
158        // rather than making a second one for the same name.
159        for id in module.aliases() {
160            let alias = &module[id];
161            let node = graph.intern(alias.name);
162            match alias.kind {
163                // A second name for a body this module may have. The edge is the whole point: a
164                // caller of the alias is a caller of what it aliases.
165                AliasKind::Alias => {
166                    let to = graph.intern(alias.target);
167                    graph.entries[node.index()].calls.push(to);
168                    // An alias of a name this module has no function for reaches the unknown
169                    // through it, which the target node's own bit already says.
170                }
171                // What an ifunc resolves to is decided when the program is loaded and is not a name
172                // this module has. The resolver is called by the dynamic linker rather than by
173                // anything here, so its address is taken in the only sense that matters.
174                AliasKind::IFunc => {
175                    graph.entries[node.index()].unknown = true;
176                    let resolver = graph.intern(alias.target);
177                    graph.entries[resolver.index()].address_taken = true;
178                }
179            }
180        }
181        // The bodies, which is where the edges come from and where a name with no function of any
182        // kind first turns up.
183        for id in module.funcs() {
184            let func = &module[id];
185            if func.is_declaration() {
186                continue;
187            }
188            let from = graph.by_name[&func.name];
189            for block in func.blocks() {
190                for inst in func.insts(block) {
191                    graph.read(func, inst, from);
192                }
193            }
194        }
195        // And the addresses written into the images, which is how a table of function pointers puts
196        // a body somewhere an indirect call can find it.
197        for id in module.globals() {
198            let init = module[id].init.map(|list| &module[list]).unwrap_or_default();
199            for datum in init {
200                if let Datum::Addr(reloc) | Datum::Away(reloc) = *datum {
201                    graph.took_the_address_of(module[reloc].symbol);
202                }
203            }
204        }
205        graph.condense();
206        graph
207    }
208
209    /// Every node, in the graph's order.
210    pub fn nodes(&self) -> impl Iterator<Item = Node> + use<> {
211        (0..self.entries.len() as u32).map(Node)
212    }
213
214    /// How many nodes there are.
215    #[must_use]
216    pub fn len(&self) -> usize {
217        self.entries.len()
218    }
219
220    /// Whether the module named nothing at all.
221    #[must_use]
222    pub fn is_empty(&self) -> bool {
223        self.entries.is_empty()
224    }
225
226    /// The node for that name, if the graph has one.
227    #[must_use]
228    pub fn node(&self, name: Symbol) -> Option<Node> {
229        self.by_name.get(&name).copied()
230    }
231
232    /// The name this node is.
233    #[must_use]
234    pub fn name(&self, node: Node) -> Symbol {
235        self.entries[node.index()].name
236    }
237
238    /// The module's function of this name, whether or not it has a body and whether or not the body
239    /// may be read.
240    ///
241    /// For the attributes and the signature, which are what the declaration is there to say. To read
242    /// the body use [`CallGraph::trusted_body`] instead.
243    #[must_use]
244    pub fn func(&self, node: Node) -> Option<FuncId> {
245        self.entries[node.index()].func
246    }
247
248    /// The body an analysis may derive facts from, and nothing when there is not one.
249    ///
250    /// Section 34.1's gate. Three things have to hold. The module has to define the function rather
251    /// than only declare it. The linkage has to be one the linker will keep, which rules out `weak`
252    /// and `common`, because either of those is a definition another object is allowed to win over.
253    /// And the symbol has to be one the dynamic linker cannot interpose, which under `-fPIC` means
254    /// hidden, protected or internal, unless the build promised `-fno-semantic-interposition`.
255    #[must_use]
256    pub fn trusted_body(&self, node: Node) -> Option<FuncId> {
257        self.entries[node.index()].body
258    }
259
260    /// The nodes this one calls directly, each once, in the order the body calls them.
261    #[must_use]
262    pub fn calls(&self, node: Node) -> &[Node] {
263        &self.entries[node.index()].calls
264    }
265
266    /// Whether this node can reach code the graph has no node for.
267    ///
268    /// True for a body with a call through an address, inline assembly or a target intrinsic in it,
269    /// true for an ifunc, and true for every node with no trusted body, since a declaration's edges
270    /// are not in this unit. An analysis that ignores this and reads only [`CallGraph::calls`] will
271    /// decide that a call to `printf` reaches nothing.
272    #[must_use]
273    pub fn reaches_unknown(&self, node: Node) -> bool {
274        self.entries[node.index()].unknown
275    }
276
277    /// Whether anything other than a direct call in this unit can reach this function.
278    ///
279    /// A `global_addr` naming it in some body, a relocation naming it in some global's image, or an
280    /// ifunc resolving through it. What it is for is the exclusion section 34.5 states for parameter
281    /// removal, "which is why a function whose address escapes is excluded", and the same question
282    /// the inliner asks before it considers a function to have no callers left.
283    ///
284    /// It is not a statement about who calls it. A `static` function whose address is never taken
285    /// and whose callers are all in this unit is the case every caller-to-callee analysis wants, and
286    /// that is this being false together with the linkage being internal.
287    #[must_use]
288    pub fn address_taken(&self, node: Node) -> bool {
289        self.entries[node.index()].address_taken
290    }
291
292    /// The strongly connected components, callees before callers.
293    ///
294    /// Tarjan gives them in that order already, because it closes a component only once everything
295    /// reachable from it has been closed, and the edges here point from a caller to a callee. A
296    /// component of one node is the usual case and a component of more than one is recursion, either
297    /// a function calling itself or a cycle of them calling each other.
298    #[must_use]
299    pub fn components(&self) -> &[Vec<Node>] {
300        &self.components
301    }
302
303    /// Which component this node landed in, as an index into [`CallGraph::components`].
304    #[must_use]
305    pub fn component_of(&self, node: Node) -> usize {
306        self.component_of[node.index()] as usize
307    }
308
309    /// Walks the condensation callee before caller, settling each component before moving on.
310    ///
311    /// `start` gives each node the value the walk begins at and `transfer` works out a node's value
312    /// from everything already known. The slice `transfer` is handed is indexed by
313    /// [`Node::index`] and holds the current value of every node, which for a callee outside this
314    /// component is its settled answer and for a callee inside it is wherever it has got to.
315    ///
316    /// Inside a component the nodes are visited in ascending index and the round repeats until no
317    /// value changes. A component of one node with no edge back to itself is not a cycle, so it is
318    /// evaluated once and not checked again, which is the shape of almost every component in a real
319    /// unit.
320    ///
321    /// `transfer` has to be monotone over a lattice of finite height, in the sense that a value it
322    /// produces from larger inputs is not smaller. That is what makes the round terminate, and it is
323    /// the consumer's to get right: section 34.5 is specific that the optimistic start this enables
324    /// "is only sound after the fixpoint, so nothing may read the lattice mid-flight".
325    ///
326    /// # Panics
327    ///
328    /// In a checked build, if a component has not settled after a number of rounds far past what any
329    /// lattice this is for could need. That is a transfer function that is not monotone rather than
330    /// anything about the graph.
331    pub fn solve<T, S, F>(&self, start: S, mut transfer: F) -> Vec<T>
332    where
333        T: Clone + PartialEq,
334        S: Fn(Node) -> T,
335        F: FnMut(Node, &[T]) -> T,
336    {
337        let mut answers: Vec<T> = self.nodes().map(&start).collect();
338        for part in &self.components {
339            if let [only] = part[..] {
340                if !self.entries[only.index()].calls.contains(&only) {
341                    answers[only.index()] = transfer(only, &answers);
342                    continue;
343                }
344            }
345            // Far more rounds than a lattice of finite height could need over a component this
346            // size. Nothing is decided by the number and no code is any different either side of
347            // it: a walk that reaches it has been handed a transfer function that is not monotone,
348            // which is a bug in the caller rather than a component that wanted more rounds.
349            let ceiling = 1000 + part.len() * 64;
350            let mut rounds = 0usize;
351            loop {
352                let mut settled = true;
353                for &node in part {
354                    let now = transfer(node, &answers);
355                    if now != answers[node.index()] {
356                        answers[node.index()] = now;
357                        settled = false;
358                    }
359                }
360                if settled {
361                    break;
362                }
363                rounds += 1;
364                debug_assert!(rounds < ceiling, "the transfer function is not monotone");
365            }
366        }
367        answers
368    }
369
370    /// The node for that name, made if it is not there yet.
371    fn intern(&mut self, name: Symbol) -> Node {
372        if let Some(&node) = self.by_name.get(&name) {
373            return node;
374        }
375        let node = Node(self.entries.len() as u32);
376        // A name that arrived without a function of its own is a name whose body is somewhere else,
377        // so it starts out reaching the unknown. The loop over the module's functions clears it for
378        // the ones it can read.
379        self.entries.push(Entry {
380            name,
381            func: None,
382            body: None,
383            calls: Vec::new(),
384            unknown: true,
385            address_taken: false,
386        });
387        self.by_name.insert(name, node);
388        node
389    }
390
391    /// Records that something other than a call got hold of that name, if it is one of ours.
392    ///
393    /// A lookup rather than an [`CallGraph::intern`], and that is the whole of the difference
394    /// between this and the rest. `global_addr` is how any name at all becomes a value and a
395    /// relocation in an image is the same, so most of what arrives here is a global variable rather
396    /// than a function. Interning those would have been harmless and it would also have put two
397    /// thousand nodes that are not functions into the graph over the SQLite amalgamation, which is a
398    /// third of it. Every function whose address this unit can take has to be declared in this unit
399    /// for the source to have named it, so a name that has no node by the time this is asked is not
400    /// a function.
401    fn took_the_address_of(&mut self, name: Symbol) {
402        if let Some(&node) = self.by_name.get(&name) {
403            self.entries[node.index()].address_taken = true;
404        }
405    }
406
407    /// Records what one instruction of a body does to the graph.
408    fn read(&mut self, func: &Func, inst: Inst, from: Node) {
409        let data = &func[inst];
410        match data.opcode {
411            Opcode::Call | Opcode::TailCall => {
412                let name = match data.extra {
413                    Extra::Call(at) => func[at].callee,
414                    _ => None,
415                };
416                // A direct call with no name on it should not happen and is treated the way a call
417                // through an address is, which is the conservative of the two.
418                let Some(name) = name else {
419                    self.entries[from.index()].unknown = true;
420                    return;
421                };
422                let to = self.intern(name);
423                let calls = &mut self.entries[from.index()].calls;
424                if !calls.contains(&to) {
425                    calls.push(to);
426                }
427            }
428            // The flag section 34.6 asks for. What is at the other end could be anything with a
429            // body, including something this unit never saw.
430            // A call built from a block of saved arguments is a call through an address as well.
431            Opcode::CallIndirect | Opcode::Apply => self.entries[from.index()].unknown = true,
432            // A template the compiler does not read, and the open half of the intrinsic set, which
433            // is named rather than enumerated so nothing here knows what one does. `crate::purity`
434            // answers the same way about both for the same reason.
435            Opcode::InlineAsm | Opcode::TargetIntrinsic => {
436                self.entries[from.index()].unknown = true;
437            }
438            // The address of a function, handed to whoever wanted it.
439            Opcode::GlobalAddr => {
440                if let Extra::Symbol(name) = data.extra {
441                    self.took_the_address_of(name);
442                }
443            }
444            _ => {}
445        }
446    }
447
448    /// Tarjan, iteratively, filling in the components and which one each node is in.
449    ///
450    /// Iteratively because the recursion depth is the depth of the call graph and a generated C
451    /// file can have a chain of thousands. The order the components come out in is the one
452    /// [`CallGraph::components`] promises and is Tarjan's own, not something sorted afterwards.
453    fn condense(&mut self) {
454        let count = self.entries.len();
455        // `u32::MAX` for a node the walk has not reached, which is a value no real index can be
456        // because the graph would have run out of memory long before.
457        let mut index = vec![u32::MAX; count];
458        let mut low = vec![0u32; count];
459        let mut on_stack = vec![false; count];
460        let mut stack: Vec<u32> = Vec::new();
461        let mut frames: Vec<(u32, usize)> = Vec::new();
462        let mut next = 0u32;
463        self.component_of = vec![u32::MAX; count];
464        for root in 0..count as u32 {
465            if index[root as usize] != u32::MAX {
466                continue;
467            }
468            index[root as usize] = next;
469            low[root as usize] = next;
470            next += 1;
471            stack.push(root);
472            on_stack[root as usize] = true;
473            frames.push((root, 0));
474            while let Some(&(node, at)) = frames.last() {
475                let edges = &self.entries[node as usize].calls;
476                if at < edges.len() {
477                    let to = edges[at].0;
478                    frames.last_mut().expect("the frame just read").1 += 1;
479                    if index[to as usize] == u32::MAX {
480                        index[to as usize] = next;
481                        low[to as usize] = next;
482                        next += 1;
483                        stack.push(to);
484                        on_stack[to as usize] = true;
485                        frames.push((to, 0));
486                    } else if on_stack[to as usize] {
487                        low[node as usize] = low[node as usize].min(index[to as usize]);
488                    }
489                    continue;
490                }
491                frames.pop();
492                if low[node as usize] == index[node as usize] {
493                    let mut part = Vec::new();
494                    while let Some(top) = stack.pop() {
495                        on_stack[top as usize] = false;
496                        part.push(Node(top));
497                        if top == node {
498                            break;
499                        }
500                    }
501                    part.sort_unstable();
502                    let which = self.components.len() as u32;
503                    for member in &part {
504                        self.component_of[member.index()] = which;
505                    }
506                    self.components.push(part);
507                }
508                if let Some(&(above, _)) = frames.last() {
509                    low[above as usize] = low[above as usize].min(low[node as usize]);
510                }
511            }
512        }
513        debug_assert!(
514            self.component_of.iter().all(|&which| which != u32::MAX),
515            "every node is in a component"
516        );
517    }
518}
519
520/// Whether the definition in hand is the one that will run.
521///
522/// The same two questions [`crate::nofree`] asks and the same answers, written here because section
523/// 34.1 makes this the graph's own gate rather than each analysis's. A `weak` or `common` definition
524/// is one the linker may throw away in favour of another object's, so the body read here is one that
525/// may never run. An ordinary external definition can be replaced at load time by `LD_PRELOAD` or by
526/// an earlier object in the search order, which is what `Pic::replaceable` answers, and
527/// `-fno-semantic-interposition` and `-fvisibility=hidden` are the two ways a build says it will not
528/// happen.
529fn trusted(func: &Func, pic: Pic) -> bool {
530    !matches!(func.linkage, Linkage::Weak | Linkage::Common)
531        && !pic.replaceable(func.linkage, func.visibility)
532}
533
534#[cfg(test)]
535mod tests {
536    use rucc_base::Interner;
537    use rucc_ir::{
538        Alias, AliasKind, AsmInfo, BlockCallList, Builder, CallInfo, Datum, Extra, Flags, Func,
539        Global, InstData, Linkage, Module, Opcode, Pic, Reloc, Signature, Type, Visibility,
540    };
541    use rucc_target::{TargetInfo, Triple};
542
543    use super::{CallGraph, Node};
544
545    /// A module with nothing in it yet.
546    fn blank() -> (Interner, Module) {
547        let mut names = Interner::new();
548        let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse::<Triple>().unwrap());
549        let module = Module::new(names.intern("t.c"), &target);
550        (names, module)
551    }
552
553    /// Adds a function of that name whose body calls each of those names once, in order.
554    fn calling(names: &mut Interner, module: &mut Module, name: &str, callees: &[&str]) {
555        let mut func = Func::new(names.intern(name), Signature::new());
556        let block = func.create_block();
557        let mut build = Builder::new(&mut func, block);
558        let signature = build.func().add_signature(Signature::new());
559        for callee in callees {
560            build.call(names.intern(callee), signature, &[]);
561        }
562        build.ret(&[]);
563        module.add_func(func);
564    }
565
566    /// Adds a declaration of that name and nothing else.
567    fn declaring(names: &mut Interner, module: &mut Module, name: &str) {
568        module.add_func(Func::new(names.intern(name), Signature::new()));
569    }
570
571    /// The node for that name, which the test expects to be there.
572    fn node(graph: &CallGraph, names: &mut Interner, name: &str) -> Node {
573        let name = names.intern(name);
574        graph.node(name).unwrap_or_else(|| panic!("no node for {}", names.resolve(name)))
575    }
576
577    /// Every component, spelled, in the order the walk produced them.
578    fn order(graph: &CallGraph, names: &Interner) -> Vec<Vec<String>> {
579        graph
580            .components()
581            .iter()
582            .map(|part| part.iter().map(|&it| names.resolve(graph.name(it)).to_string()).collect())
583            .collect()
584    }
585
586    #[test]
587    fn a_call_is_an_edge_and_the_callee_gets_a_node_of_its_own() {
588        let (mut names, mut module) = blank();
589        calling(&mut names, &mut module, "f", &["g"]);
590        calling(&mut names, &mut module, "g", &[]);
591        let graph = CallGraph::of(&module, Pic::Executable);
592        let (f, g) = (node(&graph, &mut names, "f"), node(&graph, &mut names, "g"));
593        assert_eq!(graph.calls(f), [g]);
594        assert_eq!(graph.calls(g), []);
595    }
596
597    #[test]
598    fn the_same_callee_twice_is_one_edge() {
599        let (mut names, mut module) = blank();
600        calling(&mut names, &mut module, "f", &["g", "h", "g"]);
601        calling(&mut names, &mut module, "g", &[]);
602        calling(&mut names, &mut module, "h", &[]);
603        let graph = CallGraph::of(&module, Pic::Executable);
604        let f = node(&graph, &mut names, "f");
605        let (g, h) = (node(&graph, &mut names, "g"), node(&graph, &mut names, "h"));
606        assert_eq!(graph.calls(f), [g, h], "the order the body calls them, each once");
607    }
608
609    #[test]
610    fn a_name_the_module_never_declared_still_gets_a_node() {
611        let (mut names, mut module) = blank();
612        calling(&mut names, &mut module, "f", &["witness"]);
613        let graph = CallGraph::of(&module, Pic::Executable);
614        let witness = node(&graph, &mut names, "witness");
615        assert_eq!(graph.calls(node(&graph, &mut names, "f")), [witness]);
616        assert_eq!(graph.func(witness), None);
617        assert_eq!(graph.trusted_body(witness), None);
618        assert!(graph.reaches_unknown(witness), "its body is somewhere this graph cannot see");
619    }
620
621    #[test]
622    fn a_declaration_has_a_function_and_no_body_and_reaches_the_unknown() {
623        let (mut names, mut module) = blank();
624        declaring(&mut names, &mut module, "printf");
625        let graph = CallGraph::of(&module, Pic::Executable);
626        let printf = node(&graph, &mut names, "printf");
627        assert!(graph.func(printf).is_some());
628        assert_eq!(graph.trusted_body(printf), None);
629        assert!(graph.reaches_unknown(printf));
630    }
631
632    #[test]
633    fn a_body_this_link_will_keep_is_one_an_analysis_may_read() {
634        let (mut names, mut module) = blank();
635        calling(&mut names, &mut module, "f", &[]);
636        let graph = CallGraph::of(&module, Pic::Executable);
637        let f = node(&graph, &mut names, "f");
638        assert!(graph.trusted_body(f).is_some());
639        assert!(!graph.reaches_unknown(f));
640    }
641
642    #[test]
643    fn a_weak_definition_is_not_a_body_this_analysis_may_read() {
644        let (mut names, mut module) = blank();
645        calling(&mut names, &mut module, "f", &[]);
646        let id = module.funcs().next().expect("the one function");
647        module[id].linkage = Linkage::Weak;
648        let graph = CallGraph::of(&module, Pic::Executable);
649        let f = node(&graph, &mut names, "f");
650        assert!(graph.func(f).is_some(), "the declaration is still there");
651        assert_eq!(graph.trusted_body(f), None, "another object may win over it");
652        assert!(graph.reaches_unknown(f));
653    }
654
655    #[test]
656    fn an_exported_definition_in_a_library_may_be_interposed_and_a_hidden_one_may_not() {
657        let (mut names, mut module) = blank();
658        calling(&mut names, &mut module, "f", &[]);
659        let id = module.funcs().next().expect("the one function");
660        let graph = CallGraph::of(&module, Pic::Library);
661        assert_eq!(graph.trusted_body(node(&graph, &mut names, "f")), None);
662        module[id].visibility = Visibility::Hidden;
663        let graph = CallGraph::of(&module, Pic::Library);
664        assert!(graph.trusted_body(node(&graph, &mut names, "f")).is_some());
665    }
666
667    #[test]
668    fn a_call_through_an_address_is_the_flag_and_not_an_edge() {
669        let (mut names, mut module) = blank();
670        let mut func = Func::new(names.intern("f"), Signature::new());
671        let block = func.create_block();
672        let mut build = Builder::new(&mut func, block);
673        let extra = Extra::Symbol(names.intern("g"));
674        let target =
675            build.value(InstData { extra, ..InstData::new(Opcode::GlobalAddr) }, Type::PTR);
676        let signature = build.func().add_signature(Signature::new());
677        let varargs = build.func().push_abis(&[]);
678        let info = build.func().add_call(CallInfo { callee: None, signature, varargs });
679        let args = build.func().push_values(&[target]);
680        build.inst(
681            InstData { args, extra: Extra::Call(info), ..InstData::new(Opcode::CallIndirect) },
682            &[],
683        );
684        build.ret(&[]);
685        module.add_func(func);
686        calling(&mut names, &mut module, "g", &[]);
687        let graph = CallGraph::of(&module, Pic::Executable);
688        let f = node(&graph, &mut names, "f");
689        assert_eq!(graph.calls(f), [], "nothing here names what is at the other end");
690        assert!(graph.reaches_unknown(f));
691        assert!(graph.address_taken(node(&graph, &mut names, "g")));
692    }
693
694    #[test]
695    fn a_function_named_in_an_image_has_had_its_address_taken() {
696        let (mut names, mut module) = blank();
697        calling(&mut names, &mut module, "handler", &[]);
698        let handler = names.intern("handler");
699        let reloc = module.add_reloc(Reloc { symbol: handler, addend: 0, size: 8 });
700        let mut table = Global::new(names.intern("table"), 8, 8);
701        table.init = Some(module.push_data(&[Datum::Addr(reloc)]));
702        module.add_global(table);
703        let graph = CallGraph::of(&module, Pic::Executable);
704        assert!(graph.address_taken(node(&graph, &mut names, "handler")));
705    }
706
707    #[test]
708    fn taking_the_address_of_a_variable_puts_nothing_in_the_graph() {
709        let (mut names, mut module) = blank();
710        let mut func = Func::new(names.intern("f"), Signature::new());
711        let block = func.create_block();
712        let mut build = Builder::new(&mut func, block);
713        let extra = Extra::Symbol(names.intern("counter"));
714        build.value(InstData { extra, ..InstData::new(Opcode::GlobalAddr) }, Type::PTR);
715        build.ret(&[]);
716        module.add_func(func);
717        module.add_global(Global::new(names.intern("counter"), 4, 4));
718        let graph = CallGraph::of(&module, Pic::Executable);
719        assert_eq!(graph.len(), 1, "the one function and nothing else");
720        assert_eq!(graph.node(names.intern("counter")), None);
721    }
722
723    #[test]
724    fn an_alias_is_an_edge_to_what_it_aliases() {
725        let (mut names, mut module) = blank();
726        calling(&mut names, &mut module, "caller", &["shorthand"]);
727        calling(&mut names, &mut module, "real", &[]);
728        module.add_alias(Alias::new(names.intern("shorthand"), names.intern("real")));
729        let graph = CallGraph::of(&module, Pic::Executable);
730        let shorthand = node(&graph, &mut names, "shorthand");
731        let real = node(&graph, &mut names, "real");
732        assert_eq!(graph.calls(node(&graph, &mut names, "caller")), [shorthand]);
733        assert_eq!(graph.calls(shorthand), [real], "a call to the alias is a call to the body");
734    }
735
736    #[test]
737    fn an_ifunc_reaches_the_unknown_and_its_resolver_has_had_its_address_taken() {
738        let (mut names, mut module) = blank();
739        calling(&mut names, &mut module, "resolve", &[]);
740        let mut alias = Alias::new(names.intern("memcpy"), names.intern("resolve"));
741        alias.kind = AliasKind::IFunc;
742        module.add_alias(alias);
743        let graph = CallGraph::of(&module, Pic::Executable);
744        let memcpy = node(&graph, &mut names, "memcpy");
745        assert_eq!(graph.calls(memcpy), [], "what it resolves to is not a name this module has");
746        assert!(graph.reaches_unknown(memcpy));
747        assert!(graph.address_taken(node(&graph, &mut names, "resolve")));
748        assert!(!graph.address_taken(memcpy));
749    }
750
751    #[test]
752    fn inline_assembly_reaches_the_unknown() {
753        let (mut names, mut module) = blank();
754        let mut func = Func::new(names.intern("f"), Signature::new());
755        let block = func.create_block();
756        let mut build = Builder::new(&mut func, block);
757        build.inline_asm(
758            AsmInfo {
759                template: names.intern("nop"),
760                constraints: names.intern(""),
761                clobbers: names.intern(""),
762                targets: BlockCallList::EMPTY,
763            },
764            &[],
765            &[],
766            Flags::NONE,
767        );
768        build.ret(&[]);
769        module.add_func(func);
770        let graph = CallGraph::of(&module, Pic::Executable);
771        assert!(graph.reaches_unknown(node(&graph, &mut names, "f")));
772    }
773
774    #[test]
775    fn a_target_intrinsic_reaches_the_unknown() {
776        let (mut names, mut module) = blank();
777        let mut func = Func::new(names.intern("f"), Signature::new());
778        let block = func.create_block();
779        let mut build = Builder::new(&mut func, block);
780        let extra = Extra::Symbol(names.intern("x86.pause"));
781        build.inst(InstData { extra, ..InstData::new(Opcode::TargetIntrinsic) }, &[]);
782        build.ret(&[]);
783        module.add_func(func);
784        let graph = CallGraph::of(&module, Pic::Executable);
785        assert!(graph.reaches_unknown(node(&graph, &mut names, "f")));
786    }
787
788    #[test]
789    fn a_chain_of_callers_comes_out_callee_before_caller() {
790        let (mut names, mut module) = blank();
791        calling(&mut names, &mut module, "top", &["middle"]);
792        calling(&mut names, &mut module, "middle", &["bottom"]);
793        calling(&mut names, &mut module, "bottom", &[]);
794        let graph = CallGraph::of(&module, Pic::Executable);
795        assert_eq!(order(&graph, &names), [["bottom"], ["middle"], ["top"]]);
796    }
797
798    #[test]
799    fn a_function_that_calls_itself_is_a_component_of_one_that_is_a_cycle() {
800        let (mut names, mut module) = blank();
801        calling(&mut names, &mut module, "spin", &["spin"]);
802        let graph = CallGraph::of(&module, Pic::Executable);
803        let spin = node(&graph, &mut names, "spin");
804        assert_eq!(graph.calls(spin), [spin]);
805        assert_eq!(order(&graph, &names), [["spin"]]);
806    }
807
808    #[test]
809    fn two_functions_that_call_each_other_are_one_component() {
810        let (mut names, mut module) = blank();
811        calling(&mut names, &mut module, "even", &["odd"]);
812        calling(&mut names, &mut module, "odd", &["even"]);
813        calling(&mut names, &mut module, "main", &["even"]);
814        let graph = CallGraph::of(&module, Pic::Executable);
815        assert_eq!(order(&graph, &names), [vec!["even", "odd"], vec!["main"]]);
816        let (even, odd) = (node(&graph, &mut names, "even"), node(&graph, &mut names, "odd"));
817        assert_eq!(graph.component_of(even), graph.component_of(odd));
818    }
819
820    #[test]
821    fn a_component_holds_its_nodes_in_the_graphs_own_order() {
822        let (mut names, mut module) = blank();
823        // Written so the walk leaves the stack in the opposite order from the one the module has
824        // them in, which is what the sort inside the component is there to undo.
825        calling(&mut names, &mut module, "a", &["c"]);
826        calling(&mut names, &mut module, "b", &["a"]);
827        calling(&mut names, &mut module, "c", &["b"]);
828        let graph = CallGraph::of(&module, Pic::Executable);
829        assert_eq!(order(&graph, &names), [["a", "b", "c"]]);
830        let a = node(&graph, &mut names, "a");
831        assert_eq!(graph.components()[graph.component_of(a)][0], a);
832    }
833
834    #[test]
835    fn the_walk_settles_a_component_before_anything_that_calls_into_it() {
836        let (mut names, mut module) = blank();
837        calling(&mut names, &mut module, "top", &["middle"]);
838        calling(&mut names, &mut module, "middle", &["bottom"]);
839        calling(&mut names, &mut module, "bottom", &[]);
840        let graph = CallGraph::of(&module, Pic::Executable);
841        // The deepest call under each function, which only comes out right if every callee already
842        // has its answer by the time the caller is asked.
843        let depth = graph.solve(
844            |_| 0usize,
845            |node, answers| {
846                graph.calls(node).iter().map(|&it| answers[it.index()] + 1).max().unwrap_or(0)
847            },
848        );
849        assert_eq!(depth[node(&graph, &mut names, "bottom").index()], 0);
850        assert_eq!(depth[node(&graph, &mut names, "middle").index()], 1);
851        assert_eq!(depth[node(&graph, &mut names, "top").index()], 2);
852    }
853
854    #[test]
855    fn a_component_of_one_with_no_edge_to_itself_is_asked_once() {
856        let (mut names, mut module) = blank();
857        calling(&mut names, &mut module, "f", &["g"]);
858        calling(&mut names, &mut module, "g", &[]);
859        let graph = CallGraph::of(&module, Pic::Executable);
860        let mut asked = 0usize;
861        let answers: Vec<bool> = graph.solve(
862            |_| false,
863            |_, _| {
864                asked += 1;
865                true
866            },
867        );
868        assert_eq!(asked, 2, "one question each, with nothing to settle");
869        assert!(answers[node(&graph, &mut names, "f").index()]);
870    }
871
872    #[test]
873    fn a_cycle_is_iterated_until_nothing_moves() {
874        let (mut names, mut module) = blank();
875        calling(&mut names, &mut module, "even", &["odd"]);
876        calling(&mut names, &mut module, "odd", &["even"]);
877        let graph = CallGraph::of(&module, Pic::Executable);
878        // Optimistic and lowered on contradiction, which is the shape section 34.5 asks purity to
879        // have. `odd` is told outright that it is not, and `even` has to find out through the cycle.
880        let odd = node(&graph, &mut names, "odd");
881        let settled = graph.solve(
882            |_| true,
883            |node, answers| node != odd && graph.calls(node).iter().all(|&it| answers[it.index()]),
884        );
885        assert!(!settled[odd.index()]);
886        assert!(!settled[node(&graph, &mut names, "even").index()], "through the cycle");
887    }
888
889    #[test]
890    fn an_empty_module_is_an_empty_graph() {
891        let (_, module) = blank();
892        let graph = CallGraph::of(&module, Pic::Executable);
893        assert!(graph.is_empty());
894        assert_eq!(graph.len(), 0);
895        assert!(graph.components().is_empty());
896        let answers: Vec<usize> = graph.solve(|_| 0, |_, _| 0);
897        assert!(answers.is_empty());
898    }
899
900    #[test]
901    fn the_graph_is_the_same_graph_every_time_it_is_built() {
902        let (mut names, mut module) = blank();
903        for name in ["one", "two", "three", "four", "five"] {
904            calling(&mut names, &mut module, name, &["helper", "one"]);
905        }
906        calling(&mut names, &mut module, "helper", &[]);
907        let first = CallGraph::of(&module, Pic::Executable);
908        let spelling = |graph: &CallGraph| {
909            graph
910                .nodes()
911                .map(|it| {
912                    let calls: Vec<&str> =
913                        graph.calls(it).iter().map(|&to| names.resolve(graph.name(to))).collect();
914                    (names.resolve(graph.name(it)).to_string(), calls.join(" "))
915                })
916                .collect::<Vec<_>>()
917        };
918        for _ in 0..8 {
919            let again = CallGraph::of(&module, Pic::Executable);
920            assert_eq!(spelling(&first), spelling(&again));
921            assert_eq!(order(&first, &names), order(&again, &names));
922        }
923    }
924
925    #[test]
926    fn a_chain_deeper_than_a_recursive_walk_could_manage_still_comes_out_in_order() {
927        let (mut names, mut module) = blank();
928        let deep = 20_000;
929        for at in 0..deep {
930            let next = format!("f{}", at + 1);
931            calling(&mut names, &mut module, &format!("f{at}"), &[next.as_str()]);
932        }
933        let graph = CallGraph::of(&module, Pic::Executable);
934        assert_eq!(graph.components().len(), deep + 1, "the tail name gets one of its own");
935        let top = node(&graph, &mut names, "f0");
936        assert_eq!(graph.component_of(top), deep, "settled last, after everything under it");
937    }
938}