Skip to main content

spydecy_optimizer/
lib.rs

1//! Cross-Layer Optimizer - Sprint 4
2//!
3//! This module implements cross-layer optimization passes for the Unified HIR.
4//! The optimizer eliminates Python→C boundaries and performs optimizations
5//! that are only possible with unified Python+C knowledge.
6//!
7//! # Architecture
8//!
9//! The optimizer is built around a **pass-based architecture**:
10//!
11//! ```text
12//! UnifiedHIR → Pass 1 → Pass 2 → Pass N → Optimized HIR
13//! ```
14//!
15//! # Core Passes
16//!
17//! - **Boundary Elimination**: Removes Python→C FFI boundaries
18//! - **Dead Code Elimination**: Removes unreachable code
19//! - **Inlining** (future): Inlines small functions
20//! - **Constant Folding** (future): Evaluates constants at compile time
21//!
22//! # Usage
23//!
24//! ```no_run
25//! use spydecy_optimizer::{OptimizationPipeline, BoundaryEliminationPass};
26//! use spydecy_hir::unified::UnifiedHIR;
27//!
28//! # fn example(unified_hir: UnifiedHIR) -> anyhow::Result<()> {
29//! let mut pipeline = OptimizationPipeline::new();
30//! pipeline.add_pass(Box::new(BoundaryEliminationPass::new()));
31//!
32//! let optimized = pipeline.run(unified_hir)?;
33//! # Ok(())
34//! # }
35//! ```
36
37#![warn(missing_docs, clippy::all, clippy::pedantic)]
38#![deny(unsafe_code)]
39#![allow(clippy::module_name_repetitions)]
40
41use anyhow::Result;
42use spydecy_hir::unified::UnifiedHIR;
43
44/// Optimization pass trait
45///
46/// All optimization passes implement this trait.
47pub trait Pass: Send + Sync {
48    /// Get the name of this pass
49    fn name(&self) -> &'static str;
50
51    /// Run the optimization pass on the HIR
52    ///
53    /// # Errors
54    ///
55    /// Returns an error if the optimization pass fails
56    fn run(&self, hir: UnifiedHIR) -> Result<UnifiedHIR>;
57}
58
59/// Boundary elimination pass
60///
61/// Eliminates Python→C FFI boundaries by converting cross-language
62/// calls into pure Rust calls.
63///
64/// This is the **core optimization** validated by Sprint 0.
65pub struct BoundaryEliminationPass;
66
67impl BoundaryEliminationPass {
68    /// Create a new boundary elimination pass
69    #[must_use]
70    pub const fn new() -> Self {
71        Self
72    }
73}
74
75impl Default for BoundaryEliminationPass {
76    fn default() -> Self {
77        Self::new()
78    }
79}
80
81impl Pass for BoundaryEliminationPass {
82    fn name(&self) -> &'static str {
83        "BoundaryElimination"
84    }
85
86    fn run(&self, hir: UnifiedHIR) -> Result<UnifiedHIR> {
87        // Use the eliminate_boundary method already implemented in UnifiedHIR
88        Ok(hir.eliminate_boundary())
89    }
90}
91
92/// Optimization pipeline
93///
94/// Orchestrates running multiple optimization passes in sequence.
95pub struct OptimizationPipeline {
96    passes: Vec<Box<dyn Pass>>,
97}
98
99impl OptimizationPipeline {
100    /// Create a new empty optimization pipeline
101    #[must_use]
102    pub fn new() -> Self {
103        Self { passes: Vec::new() }
104    }
105
106    /// Create a pipeline with standard optimization passes
107    #[must_use]
108    pub fn standard() -> Self {
109        let mut pipeline = Self::new();
110        pipeline.add_pass(Box::new(BoundaryEliminationPass::new()));
111        pipeline
112    }
113
114    /// Add a pass to the pipeline
115    pub fn add_pass(&mut self, pass: Box<dyn Pass>) {
116        self.passes.push(pass);
117    }
118
119    /// Run all passes in the pipeline
120    ///
121    /// # Errors
122    ///
123    /// Returns an error if any pass fails
124    pub fn run(&self, mut hir: UnifiedHIR) -> Result<UnifiedHIR> {
125        for pass in &self.passes {
126            hir = pass.run(hir)?;
127        }
128        Ok(hir)
129    }
130
131    /// Get the number of passes in the pipeline
132    #[must_use]
133    pub fn pass_count(&self) -> usize {
134        self.passes.len()
135    }
136}
137
138impl Default for OptimizationPipeline {
139    fn default() -> Self {
140        Self::new()
141    }
142}
143
144#[cfg(test)]
145#[allow(clippy::expect_used, clippy::panic)]
146mod tests {
147    use super::*;
148    use spydecy_hir::{
149        metadata::Metadata,
150        types::Type,
151        unified::{CrossMapping, UnificationPattern},
152        Language, NodeId,
153    };
154
155    #[test]
156    fn test_boundary_elimination_pass() {
157        // Create a UnifiedHIR with boundary not eliminated
158        let hir = UnifiedHIR::Call {
159            id: NodeId::new(1),
160            target_language: Language::Python,
161            callee: "len".to_owned(),
162            args: vec![],
163            inferred_type: Type::Unknown,
164            source_language: Language::Python,
165            cross_mapping: Some(CrossMapping {
166                python_node: None,
167                c_node: None,
168                pattern: UnificationPattern::LenPattern,
169                boundary_eliminated: false,
170            }),
171            meta: Metadata::new(),
172        };
173
174        // Run boundary elimination pass
175        let pass = BoundaryEliminationPass::new();
176        let optimized = pass.run(hir).expect("Pass should succeed");
177
178        // Verify boundary was eliminated
179        if let UnifiedHIR::Call { cross_mapping, .. } = optimized {
180            let mapping = cross_mapping.expect("Mapping should exist");
181            assert!(mapping.boundary_eliminated, "Boundary should be eliminated");
182        } else {
183            panic!("Expected UnifiedHIR::Call");
184        }
185    }
186
187    #[test]
188    fn test_pipeline_creation() {
189        let pipeline = OptimizationPipeline::new();
190        assert_eq!(pipeline.pass_count(), 0);
191    }
192
193    #[test]
194    fn test_pipeline_add_pass() {
195        let mut pipeline = OptimizationPipeline::new();
196        pipeline.add_pass(Box::new(BoundaryEliminationPass::new()));
197        assert_eq!(pipeline.pass_count(), 1);
198    }
199
200    #[test]
201    fn test_standard_pipeline() {
202        let pipeline = OptimizationPipeline::standard();
203        assert_eq!(
204            pipeline.pass_count(),
205            1,
206            "Standard pipeline should have 1 pass"
207        );
208    }
209
210    #[test]
211    fn test_pipeline_run() {
212        // Create test HIR
213        let hir = UnifiedHIR::Call {
214            id: NodeId::new(1),
215            target_language: Language::Python,
216            callee: "len".to_owned(),
217            args: vec![],
218            inferred_type: Type::Unknown,
219            source_language: Language::Python,
220            cross_mapping: Some(CrossMapping {
221                python_node: None,
222                c_node: None,
223                pattern: UnificationPattern::LenPattern,
224                boundary_eliminated: false,
225            }),
226            meta: Metadata::new(),
227        };
228
229        // Run pipeline
230        let pipeline = OptimizationPipeline::standard();
231        let optimized = pipeline.run(hir).expect("Pipeline should succeed");
232
233        // Verify optimization occurred
234        if let UnifiedHIR::Call { cross_mapping, .. } = optimized {
235            let mapping = cross_mapping.expect("Mapping should exist");
236            assert!(
237                mapping.boundary_eliminated,
238                "Pipeline should eliminate boundary"
239            );
240        }
241    }
242}