use crate::ast::{Block, Expr, Statement, Type, Program};
use crate::enhanced_error::{CompilerError, SourceLocation, ErrorReporter};
use std::collections::HashMap;
pub trait OptimizationPass {
fn name(&self) -> &str;
fn description(&self) -> &str;
fn optimization_level(&self) -> OptimizationLevel;
fn optimize(&mut self, ast: &mut Program) -> Result<OptimizationResult, CompilerError>;
fn should_apply(&self, context: &OptimizationContext) -> bool;
fn dependencies(&self) -> Vec<String>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OptimizationLevel {
None = 0,
Basic = 1,
Standard = 2,
Aggressive = 3,
}
impl OptimizationLevel {
pub fn includes(self, other: OptimizationLevel) -> bool {
self as u32 >= other as u32
}
}
#[derive(Debug, Clone)]
pub struct OptimizationContext {
pub level: OptimizationLevel,
pub target_architecture: TargetArchitecture,
pub enable_debug_info: bool,
pub enable_optimizations: Vec<String>,
pub disable_optimizations: Vec<String>,
pub statistics: OptimizationStatistics,
}
impl OptimizationContext {
pub fn new(level: OptimizationLevel, target_arch: TargetArchitecture) -> Self {
Self {
level,
target_architecture: target_arch,
enable_debug_info: false,
enable_optimizations: Vec::new(),
disable_optimizations: Vec::new(),
statistics: OptimizationStatistics::new(),
}
}
pub fn is_optimization_enabled(&self, name: &str) -> bool {
if self.disable_optimizations.contains(&name.to_string()) {
return false;
}
self.enable_optimizations.contains(&name.to_string()) ||
self.level.includes(OptimizationLevel::Basic)
}
pub fn with_optimization(mut self, name: String) -> Self {
self.enable_optimizations.push(name);
self
}
pub fn with_disabled_optimization(mut self, name: String) -> Self {
self.disable_optimizations.push(name);
self
}
pub fn with_debug_info(mut self, enabled: bool) -> Self {
self.enable_debug_info = enabled;
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TargetArchitecture {
X86_64,
AArch64,
Native, }
#[derive(Debug, Clone)]
pub struct OptimizationResult {
pub success: bool,
pub modifications: usize,
pub time_ms: u64,
pub statistics: OptimizationStatistics,
pub warnings: Vec<String>,
}
impl OptimizationResult {
pub fn new(modifications: usize, time_ms: u64, stats: OptimizationStatistics) -> Self {
Self {
success: true,
modifications,
time_ms,
statistics: stats,
warnings: Vec::new(),
}
}
pub fn error(error: String) -> Self {
Self {
success: false,
modifications: 0,
time_ms: 0,
statistics: OptimizationStatistics::new(),
warnings: vec![error],
}
}
pub fn with_warning(mut self, warning: String) -> Self {
self.warnings.push(warning);
self
}
pub fn made_changes(&self) -> bool {
self.modifications > 0
}
}
#[derive(Debug, Clone, Default)]
pub struct OptimizationStatistics {
pub passes_run: usize,
pub total_optimizations: usize,
pub constants_eliminated: usize,
pub dead_code_removed: usize,
pub expressions_simplified: usize,
pub functions_inlined: usize,
pub loops_unrolled: usize,
pub memory_usage_optimized: usize,
}
impl OptimizationStatistics {
pub fn new() -> Self {
Self::default()
}
pub fn increment_passes(&mut self) {
self.passes_run += 1;
}
pub fn add_optimization(&mut self, stats: &OptimizationStats) {
self.total_optimizations += 1;
self.constants_eliminated += stats.constants_eliminated;
self.dead_code_removed += stats.dead_code_removed;
self.expressions_simplified += stats.expressions_simplified;
self.functions_inlined += stats.functions_inlined;
self.loops_unrolled += stats.loops_unrolled;
self.memory_usage_optimized += stats.memory_usage_optimized;
}
}
#[derive(Debug, Clone, Default)]
pub struct OptimizationStats {
pub constants_eliminated: usize,
pub dead_code_removed: usize,
pub expressions_simplified: usize,
pub functions_inlined: usize,
pub loops_unrolled: usize,
pub memory_usage_optimized: usize,
}
impl OptimizationStats {
pub fn new() -> Self {
Self::default()
}
pub fn add(&mut self, other: &Self) {
self.constants_eliminated += other.constants_eliminated;
self.dead_code_removed += other.dead_code_removed;
self.expressions_simplified += other.expressions_simplified;
self.functions_inlined += other.functions_inlined;
self.loops_unrolled += other.loops_unrolled;
self.memory_usage_optimized += other.memory_usage_optimized;
}
}
#[derive(Debug, Clone)]
pub struct PipelineConfig {
pub optimization_level: OptimizationLevel,
pub target_architecture: TargetArchitecture,
pub enabled_passes: Vec<String>,
pub disabled_passes: Vec<String>,
pub enable_debug_info: bool,
pub parallel_execution: bool,
}
impl PipelineConfig {
pub fn new(level: OptimizationLevel, arch: TargetArchitecture) -> Self {
Self {
optimization_level: level,
target_architecture: arch,
enabled_passes: Vec::new(),
disabled_passes: Vec::new(),
enable_debug_info: false,
parallel_execution: true,
}
}
pub fn with_enabled_passes(mut self, passes: Vec<String>) -> Self {
self.enabled_passes = passes;
self
}
pub fn with_disabled_passes(mut self, passes: Vec<String>) -> Self {
self.disabled_passes = passes;
self
}
pub fn with_debug_info(mut self, enabled: bool) -> Self {
self.enable_debug_info = enabled;
self
}
pub fn with_parallel_execution(mut self, enabled: bool) -> Self {
self.parallel_execution = enabled;
self
}
}
pub struct OptimizationPipeline {
passes: Vec<Box<dyn OptimizationPass>>,
config: PipelineConfig,
error_reporter: ErrorReporter,
}
impl OptimizationPipeline {
pub fn new(config: PipelineConfig) -> Self {
Self {
passes: Vec::new(),
config,
error_reporter: ErrorReporter::new(),
}
}
pub fn add_pass(&mut self, pass: Box<dyn OptimizationPass>) {
self.passes.push(pass);
}
pub fn add_passes(&mut self, passes: Vec<Box<dyn OptimizationPass>>) {
self.passes.extend(passes);
}
pub fn register_standard_passes(&mut self) {
self.add_passes(vec![
Box::new(ConstantFoldingPass::new()),
Box::new(DeadCodeEliminationPass::new()),
Box::new(CommonSubexpressionEliminationPass::new()),
Box::new(FunctionInliningPass::new()),
Box::new(LoopOptimizationPass::new()),
Box::new(RegisterAllocationPass::new()),
]);
}
pub fn optimize(&mut self, mut ast: Program) -> Result<OptimizationResult, CompilerError> {
let start_time = std::time::Instant::now();
let mut total_stats = OptimizationStatistics::new();
let mut total_modifications = 0;
let context = OptimizationContext::new(
self.config.optimization_level,
self.config.target_architecture,
)
.with_debug_info(self.config.enable_debug_info)
.with_optimizations(self.config.enabled_passes.clone())
.with_disabled_optimizations(self.config.disabled_passes.clone());
let sorted_passes = self.topological_sort()?;
for mut pass in sorted_passes {
if !pass.should_apply(&context) {
continue;
}
if !self.config.enabled_passes.is_empty()
&& !self.config.enabled_passes.contains(&pass.name().to_string())
{
continue;
}
if self.config.disabled_passes.contains(&pass.name().to_string()) {
continue;
}
eprintln!("[optimization] Running pass: {}", pass.name());
match pass.optimize(&mut ast) {
Ok(result) => {
total_modifications += result.modifications;
total_stats.add_optimization(&result.statistics);
for warning in result.warnings {
self.error_reporter.add_diagnostic(
crate::enhanced_error::Diagnostic::warning(
SourceLocation::new(0, 1, 1, 0, 0),
format!("{}: {}", pass.name(), warning),
)
);
}
},
Err(e) => {
self.error_reporter.report_error(e);
return Ok(OptimizationResult::error(format!(
"Optimization pass '{}' failed: {}",
pass.name(),
self.error_reporter.format_diagnostics()
)));
}
}
}
let elapsed = start_time.elapsed().as_millis() as u64;
Ok(OptimizationResult::new(
total_modifications,
elapsed,
total_stats,
))
}
fn topological_sort(&self) -> Result<Vec<Box<dyn OptimizationPass>>, CompilerError> {
Ok(self.passes.clone())
}
pub fn error_reporter(&mut self) -> &mut ErrorReporter {
&mut self.error_reporter
}
pub fn get_statistics(&self) -> &OptimizationStatistics {
static EMPTY_STATS: OptimizationStatistics = OptimizationStatistics::new();
&EMPTY_STATS
}
}
pub struct OptimizationRegistry {
passes: HashMap<String, Box<dyn OptimizationPass>>,
}
impl OptimizationRegistry {
pub fn new() -> Self {
Self {
passes: HashMap::new(),
}
}
pub fn register(&mut self, name: String, pass: Box<dyn OptimizationPass>) {
self.passes.insert(name, pass);
}
pub fn get_pass(&mut self, name: &str) -> Option<&mut Box<dyn OptimizationPass>> {
self.passes.get_mut(name)
}
pub fn get_all_passes(&self) -> Vec<&String> {
self.passes.keys().collect()
}
pub fn create_pipeline(&self, config: PipelineConfig) -> OptimizationPipeline {
let mut pipeline = OptimizationPipeline::new(config);
for (name, pass) in &self.passes {
pipeline.add_pass(pass.boxed_clone());
}
pipeline
}
}
#[macro_export]
macro_rules! define_optimization_pass {
($name:ident, $level:expr, $description:expr) => {
pub struct $name {
name: String,
description: String,
level: OptimizationLevel,
}
impl $name {
pub fn new() -> Self {
Self {
name: stringify!($name).to_string(),
description: $description.to_string(),
level: $level,
}
}
}
impl OptimizationPass for $name {
fn name(&self) -> &str {
&self.name
}
fn description(&self) -> &str {
&self.description
}
fn optimization_level(&self) -> OptimizationLevel {
self.level
}
fn optimize(&mut self, ast: &mut Program) -> Result<OptimizationResult, CompilerError> {
Ok(OptimizationResult::new(0, 0, OptimizationStatistics::new()))
}
fn should_apply(&self, _context: &OptimizationContext) -> bool {
true
}
fn dependencies(&self) -> Vec<String> {
Vec::new()
}
}
};
}
define_optimization_pass!(
ConstantFoldingPass,
OptimizationLevel::Basic,
"Fold constant expressions at compile time"
);
define_optimization_pass!(
DeadCodeEliminationPass,
OptimizationLevel::Standard,
"Remove unreachable code"
);
define_optimization_pass!(
CommonSubexpressionEliminationPass,
OptimizationLevel::Standard,
"Eliminate duplicate subexpressions"
);
define_optimization_pass!(
FunctionInliningPass,
OptimizationLevel::Aggressive,
"Inline small functions"
);
define_optimization_pass!(
LoopOptimizationPass,
OptimizationLevel::Standard,
"Optimize loops (unrolling, strength reduction)"
);
define_optimization_pass!(
RegisterAllocationPass,
OptimizationLevel::Aggressive,
"Optimize register usage"
);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pipeline_creation() {
let config = PipelineConfig::new(OptimizationLevel::Standard, TargetArchitecture::Native);
let mut pipeline = OptimizationPipeline::new(config);
pipeline.register_standard_passes();
assert!(!pipeline.passes.is_empty());
}
#[test]
fn test_optimization_context() {
let context = OptimizationContext::new(OptimizationLevel::Aggressive, TargetArchitecture::X86_64);
assert!(context.is_optimization_enabled("constant_folding"));
assert!(context.level.includes(OptimizationLevel::Basic));
}
#[test]
fn test_optimization_result() {
let stats = OptimizationStatistics::new();
let result = OptimizationResult::new(5, 100, stats);
assert!(result.success);
assert_eq!(result.modifications, 5);
assert_eq!(result.time_ms, 100);
}
#[test]
fn test_optimization_registry() {
let mut registry = OptimizationRegistry::new();
let pass = Box::new(ConstantFoldingPass::new());
registry.register("constant_folding".to_string(), pass);
assert!(registry.get_pass("constant_folding").is_some());
assert!(registry.get_all_passes().contains(&"constant_folding".to_string()));
}
#[test]
fn test_pipeline_config() {
let config = PipelineConfig::new(OptimizationLevel::Basic, TargetArchitecture::AArch64)
.with_enabled_passes(vec!["constant_folding".to_string()])
.with_debug_info(true);
assert_eq!(config.optimization_level, OptimizationLevel::Basic);
assert_eq!(config.target_architecture, TargetArchitecture::AArch64);
assert!(config.enable_debug_info);
assert_eq!(config.enabled_passes, vec!["constant_folding"]);
}
}