gbf_core/decompiler/ast/phi.rs
1#![deny(missing_docs)]
2
3use gbf_macros::AstNodeTransform;
4use serde::{Deserialize, Serialize};
5
6use crate::decompiler::structure_analysis::{ControlFlowEdgeType, region::RegionId};
7
8use super::{AstKind, AstVisitable, expr::ExprKind, ptr::P, visitors::AstVisitor};
9
10/// Represents a Phi node in SSA form.
11///
12/// Phi nodes are used to merge values coming from different control-flow paths.
13/// Initially, the phi node has no arguments (i.e. no predecessor regions), but you
14/// can add them later using the [`add_region`] method.
15#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, AstNodeTransform)]
16#[convert_to(AstKind::Expression, ExprKind::Phi)]
17pub struct PhiNode {
18 resolved: bool,
19 region_ids: Vec<(RegionId, ControlFlowEdgeType)>,
20 idx: usize,
21}
22
23impl PhiNode {
24 /// Creates a new unresolved `PhiNode`
25 ///
26 /// # Returns
27 ///
28 /// A new phi node with no predecessor regions.
29 pub fn new(idx: usize) -> Self {
30 Self {
31 idx,
32 resolved: false,
33 region_ids: Vec::new(),
34 }
35 }
36
37 /// Returns the index of the phi node.
38 pub fn idx(&self) -> usize {
39 self.idx
40 }
41
42 /// Adds a predecessor `RegionId` to this phi node.
43 ///
44 /// This method allows the phi node to record a region (i.e. a basic block ID)
45 /// from which a value is coming.
46 ///
47 /// # Arguments
48 /// * `region` - The identifier of the predecessor region.
49 pub fn add_region(&mut self, region: RegionId, edge_type: ControlFlowEdgeType) {
50 self.region_ids.push((region, edge_type));
51 }
52
53 /// Adds predecessor `RegionId`s to this phi node.
54 ///
55 /// This method allows the phi node to record multiple regions (i.e. basic block IDs)
56 /// from which values are coming.
57 ///
58 /// # Arguments
59 /// * `regions` - The identifiers of the predecessor regions.
60 pub fn add_regions(&mut self, regions: Vec<(RegionId, ControlFlowEdgeType)>) {
61 self.region_ids.extend(regions);
62 }
63
64 /// Returns a reference to the list of region IDs associated with this phi node.
65 ///
66 /// # Returns
67 ///
68 /// A slice containing all the predecessor region IDs added so far.
69 pub fn regions(&self) -> &[(RegionId, ControlFlowEdgeType)] {
70 &self.region_ids
71 }
72}
73
74impl AstVisitable for P<PhiNode> {
75 fn accept<V: AstVisitor>(&self, visitor: &mut V) -> V::Output {
76 visitor.visit_phi(self)
77 }
78}