Skip to content

feat: Phi nodes #58

@cernec1999

Description

@cernec1999

Introduce phi nodes using the following algorithm:

  • Traverse the predecessor blocks when processing a new block (and we should be traversing using DfsPostOrder, so any BasicBlock that is a parent of a child block should already be traversed)
  • If the predecessor block has any AstNode left on the stack, introduce phi nodes, with their arguments as the predecessor RegionId as merge variabes.
  • If there is only one predecessor for the phi node we created, we can possibly simply resolve the phi node immediately, although this might not be robust for constructs like loops.

We may also have to consider weird edge cases like the following:

temp.arr = {1, temp.foo == 2 ? temp.bar : temp.baz, 3};

Sample algorithm:

            for pred in self.function.get_predecessors(block_id).map_err(|e| {
                FunctionDecompilerError::FunctionError {
                    source: e,
                    backtrace: Backtrace::capture(),
                    context: ctx.get_error_context(),
                }
            })? {
                let exec = ctx
                    .block_ast_node_stack
                    .get(&pred)
                    .expect("Critical error: stack should always be set for each basic block");

                // iterate the stack and introduce phi nodes
                for frame in exec.iter() {
                    match frame {
                        ExecutionFrame::StandaloneNode(node) => {
                            let current_region_id = self
                                .block_to_region
                                .get(&block_id)
                                .expect("[Bug] The region should exist.");

                            // For now, print debug
                            println!(
                                "Introducing Phi node for block {} to block {}. The value resolves to: {}",
                                pred,
                                block_id,
                                emit(node.clone())
                            );
                        }
                        _ => {
                            return Err(FunctionDecompilerError::Other {
                                message: "Expected StandaloneNode".to_string(),
                                context: ctx.get_error_context(),
                                backtrace: Backtrace::capture(),
                            });
                        }
                    }
                }
            }

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions