灵符lingfu

ling-mir

↓ 0 downloads

Mid-level IR with real optimization passes

Keywords mir, compiler, optimizer, ir
lingfu install ling-mir
LicenseApache-2.0 OR MIT
AuthorsLing Lin, Sanny Lin
READMECode / FilesVersionsDependency GraphDependentsSecurityBuildsSettings

Code / Files (29)

src/optimizations/algebraic.rs
use super::Transform;
use crate::ir::*;
use ling_ast::ast::BinOp;
use std::collections::HashMap;

pub struct AlgebraicSimplification;

impl Transform for AlgebraicSimplification {
    fn run(&self, func: &mut MirFunction) -> bool {
        let mut assign_counts: HashMap<Local, usize> = HashMap::new();
        let mut def_map: HashMap<Local, Rvalue> = HashMap::new();

        for bb in &func.basic_blocks {
            for stmt in &bb.statements {
                if let StatementKind::Assign(dest, rval) = &stmt.kind {
                    *assign_counts.entry(*dest).or_insert(0) += 1;
                    def_map.insert(*dest, rval.clone());
                }
            }
        }

        let single_def: HashMap<Local, Rvalue> = def_map
            .into_iter()
            .filter(|(l, _)| assign_counts.get(l) == Some(&1))
            .collect();

        let mut changed = false;

        for bb in &mut func.basic_blocks {
            for stmt in &mut bb.statements {
                if let StatementKind::Assign(_, rval) = &mut stmt.kind {
                    if let Rvalue::BinaryOp(
                        BinOp::Div,
                        Operand::Copy(src),
                        Operand::Constant(Constant::I64(b)),
                    ) = rval
                    {
                        if *b == 0 {
                            continue;
                        }
                        if let Some(Rvalue::BinaryOp(
                            BinOp::Mul,
                            mul_lhs,
                            Operand::Constant(Constant::I64(a)),
                        )) = single_def.get(src)
                        {
                            if *a % *b == 0 {
                                let factor = *a / *b;
                                *rval = Rvalue::BinaryOp(
                                    BinOp::Mul,
                                    mul_lhs.clone(),
                                    Operand::Constant(Constant::I64(factor)),
                                );
                                changed = true;
                            }
                        } else if let Some(Rvalue::BinaryOp(
                            BinOp::Mul,
                            Operand::Constant(Constant::I64(a)),
                            mul_rhs,
                        )) = single_def.get(src)
                        {
                            if *a % *b == 0 {
                                let factor = *a / *b;
                                *rval = Rvalue::BinaryOp(
                                    BinOp::Mul,
                                    mul_rhs.clone(),
                                    Operand::Constant(Constant::I64(factor)),
                                );
                                changed = true;
                            }
                        }
                    }
                }
            }
        }

        changed
    }
}

← Back to index