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 {
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            Opcode::CallIndirect => self.entries[from.index()].unknown = true,
431            // A template the compiler does not read, and the open half of the intrinsic set, which
432            // is named rather than enumerated so nothing here knows what one does. `crate::purity`
433            // answers the same way about both for the same reason.
434            Opcode::InlineAsm | Opcode::TargetIntrinsic => {
435                self.entries[from.index()].unknown = true;
436            }
437            // The address of a function, handed to whoever wanted it.
438            Opcode::GlobalAddr => {
439                if let Extra::Symbol(name) = data.extra {
440                    self.took_the_address_of(name);
441                }
442            }
443            _ => {}
444        }
445    }
446
447    /// Tarjan, iteratively, filling in the components and which one each node is in.
448    ///
449    /// Iteratively because the recursion depth is the depth of the call graph and a generated C
450    /// file can have a chain of thousands. The order the components come out in is the one
451    /// [`CallGraph::components`] promises and is Tarjan's own, not something sorted afterwards.
452    fn condense(&mut self) {
453        let count = self.entries.len();
454        // `u32::MAX` for a node the walk has not reached, which is a value no real index can be
455        // because the graph would have run out of memory long before.
456        let mut index = vec![u32::MAX; count];
457        let mut low = vec![0u32; count];
458        let mut on_stack = vec![false; count];
459        let mut stack: Vec<u32> = Vec::new();
460        let mut frames: Vec<(u32, usize)> = Vec::new();
461        let mut next = 0u32;
462        self.component_of = vec![u32::MAX; count];
463        for root in 0..count as u32 {
464            if index[root as usize] != u32::MAX {
465                continue;
466            }
467            index[root as usize] = next;
468            low[root as usize] = next;
469            next += 1;
470            stack.push(root);
471            on_stack[root as usize] = true;
472            frames.push((root, 0));
473            while let Some(&(node, at)) = frames.last() {
474                let edges = &self.entries[node as usize].calls;
475                if at < edges.len() {
476                    let to = edges[at].0;
477                    frames.last_mut().expect("the frame just read").1 += 1;
478                    if index[to as usize] == u32::MAX {
479                        index[to as usize] = next;
480                        low[to as usize] = next;
481                        next += 1;
482                        stack.push(to);
483                        on_stack[to as usize] = true;
484                        frames.push((to, 0));
485                    } else if on_stack[to as usize] {
486                        low[node as usize] = low[node as usize].min(index[to as usize]);
487                    }
488                    continue;
489                }
490                frames.pop();
491                if low[node as usize] == index[node as usize] {
492                    let mut part = Vec::new();
493                    while let Some(top) = stack.pop() {
494                        on_stack[top as usize] = false;
495                        part.push(Node(top));
496                        if top == node {
497                            break;
498                        }
499                    }
500                    part.sort_unstable();
501                    let which = self.components.len() as u32;
502                    for member in &part {
503                        self.component_of[member.index()] = which;
504                    }
505                    self.components.push(part);
506                }
507                if let Some(&(above, _)) = frames.last() {
508                    low[above as usize] = low[above as usize].min(low[node as usize]);
509                }
510            }
511        }
512        debug_assert!(
513            self.component_of.iter().all(|&which| which != u32::MAX),
514            "every node is in a component"
515        );
516    }
517}
518
519/// Whether the definition in hand is the one that will run.
520///
521/// The same two questions [`crate::nofree`] asks and the same answers, written here because section
522/// 34.1 makes this the graph's own gate rather than each analysis's. A `weak` or `common` definition
523/// is one the linker may throw away in favour of another object's, so the body read here is one that
524/// may never run. An ordinary external definition can be replaced at load time by `LD_PRELOAD` or by
525/// an earlier object in the search order, which is what `Pic::replaceable` answers, and
526/// `-fno-semantic-interposition` and `-fvisibility=hidden` are the two ways a build says it will not
527/// happen.
528fn trusted(func: &Func, pic: Pic) -> bool {
529    !matches!(func.linkage, Linkage::Weak | Linkage::Common)
530        && !pic.replaceable(func.linkage, func.visibility)
531}
532
533#[cfg(test)]
534mod tests {
535    use rucc_base::Interner;
536    use rucc_ir::{
537        Alias, AliasKind, AsmInfo, BlockCallList, Builder, CallInfo, Datum, Extra, Flags, Func,
538        Global, InstData, Linkage, Module, Opcode, Pic, Reloc, Signature, Type, Visibility,
539    };
540    use rucc_target::{TargetInfo, Triple};
541
542    use super::{CallGraph, Node};
543
544    /// A module with nothing in it yet.
545    fn blank() -> (Interner, Module) {
546        let mut names = Interner::new();
547        let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse::<Triple>().unwrap());
548        let module = Module::new(names.intern("t.c"), &target);
549        (names, module)
550    }
551
552    /// Adds a function of that name whose body calls each of those names once, in order.
553    fn calling(names: &mut Interner, module: &mut Module, name: &str, callees: &[&str]) {
554        let mut func = Func::new(names.intern(name), Signature::new());
555        let block = func.create_block();
556        let mut build = Builder::new(&mut func, block);
557        let signature = build.func().add_signature(Signature::new());
558        for callee in callees {
559            build.call(names.intern(callee), signature, &[]);
560        }
561        build.ret(&[]);
562        module.add_func(func);
563    }
564
565    /// Adds a declaration of that name and nothing else.
566    fn declaring(names: &mut Interner, module: &mut Module, name: &str) {
567        module.add_func(Func::new(names.intern(name), Signature::new()));
568    }
569
570    /// The node for that name, which the test expects to be there.
571    fn node(graph: &CallGraph, names: &mut Interner, name: &str) -> Node {
572        let name = names.intern(name);
573        graph.node(name).unwrap_or_else(|| panic!("no node for {}", names.resolve(name)))
574    }
575
576    /// Every component, spelled, in the order the walk produced them.
577    fn order(graph: &CallGraph, names: &Interner) -> Vec<Vec<String>> {
578        graph
579            .components()
580            .iter()
581            .map(|part| part.iter().map(|&it| names.resolve(graph.name(it)).to_string()).collect())
582            .collect()
583    }
584
585    #[test]
586    fn a_call_is_an_edge_and_the_callee_gets_a_node_of_its_own() {
587        let (mut names, mut module) = blank();
588        calling(&mut names, &mut module, "f", &["g"]);
589        calling(&mut names, &mut module, "g", &[]);
590        let graph = CallGraph::of(&module, Pic::Executable);
591        let (f, g) = (node(&graph, &mut names, "f"), node(&graph, &mut names, "g"));
592        assert_eq!(graph.calls(f), [g]);
593        assert_eq!(graph.calls(g), []);
594    }
595
596    #[test]
597    fn the_same_callee_twice_is_one_edge() {
598        let (mut names, mut module) = blank();
599        calling(&mut names, &mut module, "f", &["g", "h", "g"]);
600        calling(&mut names, &mut module, "g", &[]);
601        calling(&mut names, &mut module, "h", &[]);
602        let graph = CallGraph::of(&module, Pic::Executable);
603        let f = node(&graph, &mut names, "f");
604        let (g, h) = (node(&graph, &mut names, "g"), node(&graph, &mut names, "h"));
605        assert_eq!(graph.calls(f), [g, h], "the order the body calls them, each once");
606    }
607
608    #[test]
609    fn a_name_the_module_never_declared_still_gets_a_node() {
610        let (mut names, mut module) = blank();
611        calling(&mut names, &mut module, "f", &["witness"]);
612        let graph = CallGraph::of(&module, Pic::Executable);
613        let witness = node(&graph, &mut names, "witness");
614        assert_eq!(graph.calls(node(&graph, &mut names, "f")), [witness]);
615        assert_eq!(graph.func(witness), None);
616        assert_eq!(graph.trusted_body(witness), None);
617        assert!(graph.reaches_unknown(witness), "its body is somewhere this graph cannot see");
618    }
619
620    #[test]
621    fn a_declaration_has_a_function_and_no_body_and_reaches_the_unknown() {
622        let (mut names, mut module) = blank();
623        declaring(&mut names, &mut module, "printf");
624        let graph = CallGraph::of(&module, Pic::Executable);
625        let printf = node(&graph, &mut names, "printf");
626        assert!(graph.func(printf).is_some());
627        assert_eq!(graph.trusted_body(printf), None);
628        assert!(graph.reaches_unknown(printf));
629    }
630
631    #[test]
632    fn a_body_this_link_will_keep_is_one_an_analysis_may_read() {
633        let (mut names, mut module) = blank();
634        calling(&mut names, &mut module, "f", &[]);
635        let graph = CallGraph::of(&module, Pic::Executable);
636        let f = node(&graph, &mut names, "f");
637        assert!(graph.trusted_body(f).is_some());
638        assert!(!graph.reaches_unknown(f));
639    }
640
641    #[test]
642    fn a_weak_definition_is_not_a_body_this_analysis_may_read() {
643        let (mut names, mut module) = blank();
644        calling(&mut names, &mut module, "f", &[]);
645        let id = module.funcs().next().expect("the one function");
646        module[id].linkage = Linkage::Weak;
647        let graph = CallGraph::of(&module, Pic::Executable);
648        let f = node(&graph, &mut names, "f");
649        assert!(graph.func(f).is_some(), "the declaration is still there");
650        assert_eq!(graph.trusted_body(f), None, "another object may win over it");
651        assert!(graph.reaches_unknown(f));
652    }
653
654    #[test]
655    fn an_exported_definition_in_a_library_may_be_interposed_and_a_hidden_one_may_not() {
656        let (mut names, mut module) = blank();
657        calling(&mut names, &mut module, "f", &[]);
658        let id = module.funcs().next().expect("the one function");
659        let graph = CallGraph::of(&module, Pic::Library);
660        assert_eq!(graph.trusted_body(node(&graph, &mut names, "f")), None);
661        module[id].visibility = Visibility::Hidden;
662        let graph = CallGraph::of(&module, Pic::Library);
663        assert!(graph.trusted_body(node(&graph, &mut names, "f")).is_some());
664    }
665
666    #[test]
667    fn a_call_through_an_address_is_the_flag_and_not_an_edge() {
668        let (mut names, mut module) = blank();
669        let mut func = Func::new(names.intern("f"), Signature::new());
670        let block = func.create_block();
671        let mut build = Builder::new(&mut func, block);
672        let extra = Extra::Symbol(names.intern("g"));
673        let target =
674            build.value(InstData { extra, ..InstData::new(Opcode::GlobalAddr) }, Type::PTR);
675        let signature = build.func().add_signature(Signature::new());
676        let varargs = build.func().push_abis(&[]);
677        let info = build.func().add_call(CallInfo { callee: None, signature, varargs });
678        let args = build.func().push_values(&[target]);
679        build.inst(
680            InstData { args, extra: Extra::Call(info), ..InstData::new(Opcode::CallIndirect) },
681            &[],
682        );
683        build.ret(&[]);
684        module.add_func(func);
685        calling(&mut names, &mut module, "g", &[]);
686        let graph = CallGraph::of(&module, Pic::Executable);
687        let f = node(&graph, &mut names, "f");
688        assert_eq!(graph.calls(f), [], "nothing here names what is at the other end");
689        assert!(graph.reaches_unknown(f));
690        assert!(graph.address_taken(node(&graph, &mut names, "g")));
691    }
692
693    #[test]
694    fn a_function_named_in_an_image_has_had_its_address_taken() {
695        let (mut names, mut module) = blank();
696        calling(&mut names, &mut module, "handler", &[]);
697        let handler = names.intern("handler");
698        let reloc = module.add_reloc(Reloc { symbol: handler, addend: 0, size: 8 });
699        let mut table = Global::new(names.intern("table"), 8, 8);
700        table.init = Some(module.push_data(&[Datum::Addr(reloc)]));
701        module.add_global(table);
702        let graph = CallGraph::of(&module, Pic::Executable);
703        assert!(graph.address_taken(node(&graph, &mut names, "handler")));
704    }
705
706    #[test]
707    fn taking_the_address_of_a_variable_puts_nothing_in_the_graph() {
708        let (mut names, mut module) = blank();
709        let mut func = Func::new(names.intern("f"), Signature::new());
710        let block = func.create_block();
711        let mut build = Builder::new(&mut func, block);
712        let extra = Extra::Symbol(names.intern("counter"));
713        build.value(InstData { extra, ..InstData::new(Opcode::GlobalAddr) }, Type::PTR);
714        build.ret(&[]);
715        module.add_func(func);
716        module.add_global(Global::new(names.intern("counter"), 4, 4));
717        let graph = CallGraph::of(&module, Pic::Executable);
718        assert_eq!(graph.len(), 1, "the one function and nothing else");
719        assert_eq!(graph.node(names.intern("counter")), None);
720    }
721
722    #[test]
723    fn an_alias_is_an_edge_to_what_it_aliases() {
724        let (mut names, mut module) = blank();
725        calling(&mut names, &mut module, "caller", &["shorthand"]);
726        calling(&mut names, &mut module, "real", &[]);
727        module.add_alias(Alias::new(names.intern("shorthand"), names.intern("real")));
728        let graph = CallGraph::of(&module, Pic::Executable);
729        let shorthand = node(&graph, &mut names, "shorthand");
730        let real = node(&graph, &mut names, "real");
731        assert_eq!(graph.calls(node(&graph, &mut names, "caller")), [shorthand]);
732        assert_eq!(graph.calls(shorthand), [real], "a call to the alias is a call to the body");
733    }
734
735    #[test]
736    fn an_ifunc_reaches_the_unknown_and_its_resolver_has_had_its_address_taken() {
737        let (mut names, mut module) = blank();
738        calling(&mut names, &mut module, "resolve", &[]);
739        let mut alias = Alias::new(names.intern("memcpy"), names.intern("resolve"));
740        alias.kind = AliasKind::IFunc;
741        module.add_alias(alias);
742        let graph = CallGraph::of(&module, Pic::Executable);
743        let memcpy = node(&graph, &mut names, "memcpy");
744        assert_eq!(graph.calls(memcpy), [], "what it resolves to is not a name this module has");
745        assert!(graph.reaches_unknown(memcpy));
746        assert!(graph.address_taken(node(&graph, &mut names, "resolve")));
747        assert!(!graph.address_taken(memcpy));
748    }
749
750    #[test]
751    fn inline_assembly_reaches_the_unknown() {
752        let (mut names, mut module) = blank();
753        let mut func = Func::new(names.intern("f"), Signature::new());
754        let block = func.create_block();
755        let mut build = Builder::new(&mut func, block);
756        build.inline_asm(
757            AsmInfo {
758                template: names.intern("nop"),
759                constraints: names.intern(""),
760                clobbers: names.intern(""),
761                targets: BlockCallList::EMPTY,
762            },
763            &[],
764            &[],
765            Flags::NONE,
766        );
767        build.ret(&[]);
768        module.add_func(func);
769        let graph = CallGraph::of(&module, Pic::Executable);
770        assert!(graph.reaches_unknown(node(&graph, &mut names, "f")));
771    }
772
773    #[test]
774    fn a_target_intrinsic_reaches_the_unknown() {
775        let (mut names, mut module) = blank();
776        let mut func = Func::new(names.intern("f"), Signature::new());
777        let block = func.create_block();
778        let mut build = Builder::new(&mut func, block);
779        let extra = Extra::Symbol(names.intern("x86.pause"));
780        build.inst(InstData { extra, ..InstData::new(Opcode::TargetIntrinsic) }, &[]);
781        build.ret(&[]);
782        module.add_func(func);
783        let graph = CallGraph::of(&module, Pic::Executable);
784        assert!(graph.reaches_unknown(node(&graph, &mut names, "f")));
785    }
786
787    #[test]
788    fn a_chain_of_callers_comes_out_callee_before_caller() {
789        let (mut names, mut module) = blank();
790        calling(&mut names, &mut module, "top", &["middle"]);
791        calling(&mut names, &mut module, "middle", &["bottom"]);
792        calling(&mut names, &mut module, "bottom", &[]);
793        let graph = CallGraph::of(&module, Pic::Executable);
794        assert_eq!(order(&graph, &names), [["bottom"], ["middle"], ["top"]]);
795    }
796
797    #[test]
798    fn a_function_that_calls_itself_is_a_component_of_one_that_is_a_cycle() {
799        let (mut names, mut module) = blank();
800        calling(&mut names, &mut module, "spin", &["spin"]);
801        let graph = CallGraph::of(&module, Pic::Executable);
802        let spin = node(&graph, &mut names, "spin");
803        assert_eq!(graph.calls(spin), [spin]);
804        assert_eq!(order(&graph, &names), [["spin"]]);
805    }
806
807    #[test]
808    fn two_functions_that_call_each_other_are_one_component() {
809        let (mut names, mut module) = blank();
810        calling(&mut names, &mut module, "even", &["odd"]);
811        calling(&mut names, &mut module, "odd", &["even"]);
812        calling(&mut names, &mut module, "main", &["even"]);
813        let graph = CallGraph::of(&module, Pic::Executable);
814        assert_eq!(order(&graph, &names), [vec!["even", "odd"], vec!["main"]]);
815        let (even, odd) = (node(&graph, &mut names, "even"), node(&graph, &mut names, "odd"));
816        assert_eq!(graph.component_of(even), graph.component_of(odd));
817    }
818
819    #[test]
820    fn a_component_holds_its_nodes_in_the_graphs_own_order() {
821        let (mut names, mut module) = blank();
822        // Written so the walk leaves the stack in the opposite order from the one the module has
823        // them in, which is what the sort inside the component is there to undo.
824        calling(&mut names, &mut module, "a", &["c"]);
825        calling(&mut names, &mut module, "b", &["a"]);
826        calling(&mut names, &mut module, "c", &["b"]);
827        let graph = CallGraph::of(&module, Pic::Executable);
828        assert_eq!(order(&graph, &names), [["a", "b", "c"]]);
829        let a = node(&graph, &mut names, "a");
830        assert_eq!(graph.components()[graph.component_of(a)][0], a);
831    }
832
833    #[test]
834    fn the_walk_settles_a_component_before_anything_that_calls_into_it() {
835        let (mut names, mut module) = blank();
836        calling(&mut names, &mut module, "top", &["middle"]);
837        calling(&mut names, &mut module, "middle", &["bottom"]);
838        calling(&mut names, &mut module, "bottom", &[]);
839        let graph = CallGraph::of(&module, Pic::Executable);
840        // The deepest call under each function, which only comes out right if every callee already
841        // has its answer by the time the caller is asked.
842        let depth = graph.solve(
843            |_| 0usize,
844            |node, answers| {
845                graph.calls(node).iter().map(|&it| answers[it.index()] + 1).max().unwrap_or(0)
846            },
847        );
848        assert_eq!(depth[node(&graph, &mut names, "bottom").index()], 0);
849        assert_eq!(depth[node(&graph, &mut names, "middle").index()], 1);
850        assert_eq!(depth[node(&graph, &mut names, "top").index()], 2);
851    }
852
853    #[test]
854    fn a_component_of_one_with_no_edge_to_itself_is_asked_once() {
855        let (mut names, mut module) = blank();
856        calling(&mut names, &mut module, "f", &["g"]);
857        calling(&mut names, &mut module, "g", &[]);
858        let graph = CallGraph::of(&module, Pic::Executable);
859        let mut asked = 0usize;
860        let answers: Vec<bool> = graph.solve(
861            |_| false,
862            |_, _| {
863                asked += 1;
864                true
865            },
866        );
867        assert_eq!(asked, 2, "one question each, with nothing to settle");
868        assert!(answers[node(&graph, &mut names, "f").index()]);
869    }
870
871    #[test]
872    fn a_cycle_is_iterated_until_nothing_moves() {
873        let (mut names, mut module) = blank();
874        calling(&mut names, &mut module, "even", &["odd"]);
875        calling(&mut names, &mut module, "odd", &["even"]);
876        let graph = CallGraph::of(&module, Pic::Executable);
877        // Optimistic and lowered on contradiction, which is the shape section 34.5 asks purity to
878        // have. `odd` is told outright that it is not, and `even` has to find out through the cycle.
879        let odd = node(&graph, &mut names, "odd");
880        let settled = graph.solve(
881            |_| true,
882            |node, answers| node != odd && graph.calls(node).iter().all(|&it| answers[it.index()]),
883        );
884        assert!(!settled[odd.index()]);
885        assert!(!settled[node(&graph, &mut names, "even").index()], "through the cycle");
886    }
887
888    #[test]
889    fn an_empty_module_is_an_empty_graph() {
890        let (_, module) = blank();
891        let graph = CallGraph::of(&module, Pic::Executable);
892        assert!(graph.is_empty());
893        assert_eq!(graph.len(), 0);
894        assert!(graph.components().is_empty());
895        let answers: Vec<usize> = graph.solve(|_| 0, |_, _| 0);
896        assert!(answers.is_empty());
897    }
898
899    #[test]
900    fn the_graph_is_the_same_graph_every_time_it_is_built() {
901        let (mut names, mut module) = blank();
902        for name in ["one", "two", "three", "four", "five"] {
903            calling(&mut names, &mut module, name, &["helper", "one"]);
904        }
905        calling(&mut names, &mut module, "helper", &[]);
906        let first = CallGraph::of(&module, Pic::Executable);
907        let spelling = |graph: &CallGraph| {
908            graph
909                .nodes()
910                .map(|it| {
911                    let calls: Vec<&str> =
912                        graph.calls(it).iter().map(|&to| names.resolve(graph.name(to))).collect();
913                    (names.resolve(graph.name(it)).to_string(), calls.join(" "))
914                })
915                .collect::<Vec<_>>()
916        };
917        for _ in 0..8 {
918            let again = CallGraph::of(&module, Pic::Executable);
919            assert_eq!(spelling(&first), spelling(&again));
920            assert_eq!(order(&first, &names), order(&again, &names));
921        }
922    }
923
924    #[test]
925    fn a_chain_deeper_than_a_recursive_walk_could_manage_still_comes_out_in_order() {
926        let (mut names, mut module) = blank();
927        let deep = 20_000;
928        for at in 0..deep {
929            let next = format!("f{}", at + 1);
930            calling(&mut names, &mut module, &format!("f{at}"), &[next.as_str()]);
931        }
932        let graph = CallGraph::of(&module, Pic::Executable);
933        assert_eq!(graph.components().len(), deep + 1, "the tail name gets one of its own");
934        let top = node(&graph, &mut names, "f0");
935        assert_eq!(graph.component_of(top), deep, "settled last, after everything under it");
936    }
937}