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}