灵符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/const_fold.rs
use super::Transform;
use crate::ir::*;
use ling_ast::ast::{BinOp, UnOp};

pub struct ConstantFolding;

impl Transform for ConstantFolding {
    fn run(&self, func: &mut MirFunction) -> bool {
        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(
                        op,
                        Operand::Constant(Constant::I64(a)),
                        Operand::Constant(Constant::I64(b)),
                    ) = rval
                    {
                        let res = match op {
                            BinOp::Add => Some(Constant::I64((*a).wrapping_add(*b))),
                            BinOp::Sub => Some(Constant::I64((*a).wrapping_sub(*b))),
                            BinOp::Mul => Some(Constant::I64((*a).wrapping_mul(*b))),
                            BinOp::Div => {
                                if *b != 0 {
                                    Some(Constant::I64(*a / *b))
                                } else {
                                    None
                                }
                            },
                            BinOp::Rem => {
                                if *b != 0 {
                                    Some(Constant::I64(*a % *b))
                                } else {
                                    None
                                }
                            },
                            BinOp::Eq => Some(Constant::Bool(*a == *b)),
                            BinOp::Ne => Some(Constant::Bool(*a != *b)),
                            BinOp::Lt => Some(Constant::Bool(*a < *b)),
                            BinOp::Le => Some(Constant::Bool(*a <= *b)),
                            BinOp::Gt => Some(Constant::Bool(*a > *b)),
                            BinOp::Ge => Some(Constant::Bool(*a >= *b)),
                            BinOp::Shl => Some(Constant::I64((*a).wrapping_shl(*b as u32))),
                            BinOp::Shr => Some(Constant::I64((*a).wrapping_shr(*b as u32))),
                            _ => None,
                        };
                        if let Some(val) = res {
                            *rval = Rvalue::Use(Operand::Constant(val));
                            changed = true;
                        }
                    } else if let Rvalue::BinaryOp(
                        op,
                        Operand::Constant(Constant::F64(a_bits)),
                        Operand::Constant(Constant::F64(b_bits)),
                    ) = rval
                    {
                        let a = f64::from_bits(*a_bits);
                        let b = f64::from_bits(*b_bits);
                        let res = match op {
                            BinOp::Add => Some(Constant::F64((a + b).to_bits())),
                            BinOp::Sub => Some(Constant::F64((a - b).to_bits())),
                            BinOp::Mul => Some(Constant::F64((a * b).to_bits())),
                            BinOp::Div => Some(Constant::F64((a / b).to_bits())),
                            BinOp::Eq => Some(Constant::Bool(a == b)),
                            BinOp::Ne => Some(Constant::Bool(a != b)),
                            BinOp::Lt => Some(Constant::Bool(a < b)),
                            BinOp::Le => Some(Constant::Bool(a <= b)),
                            BinOp::Gt => Some(Constant::Bool(a > b)),
                            BinOp::Ge => Some(Constant::Bool(a >= b)),
                            _ => None,
                        };
                        if let Some(val) = res {
                            *rval = Rvalue::Use(Operand::Constant(val));
                            changed = true;
                        }
                    } else if let Rvalue::BinaryOp(
                        op,
                        Operand::Constant(Constant::Bool(a)),
                        Operand::Constant(Constant::Bool(b)),
                    ) = rval
                    {
                        let res = match op {
                            BinOp::Eq => Some(Constant::Bool(*a == *b)),
                            BinOp::Ne => Some(Constant::Bool(*a != *b)),
                            BinOp::And => Some(Constant::Bool(*a && *b)),
                            BinOp::Or => Some(Constant::Bool(*a || *b)),
                            _ => None,
                        };
                        if let Some(val) = res {
                            *rval = Rvalue::Use(Operand::Constant(val));
                            changed = true;
                        }
                    } else if let Rvalue::UnaryOp(op, Operand::Constant(c)) = rval {
                        let res = match (op, c.clone()) {
                            (UnOp::Neg, Constant::I64(a)) => Some(Constant::I64(-a)),
                            (UnOp::Neg, Constant::F64(a)) => {
                                Some(Constant::F64((-f64::from_bits(a)).to_bits()))
                            },
                            (UnOp::Not, Constant::Bool(a)) => Some(Constant::Bool(!a)),
                            (UnOp::Not, Constant::I64(a)) => Some(Constant::Bool(a == 0)),
                            _ => None,
                        };
                        if let Some(val) = res {
                            *rval = Rvalue::Use(Operand::Constant(val));
                            changed = true;
                        }
                    }
                }
            }
        }
        changed
    }
}

← Back to index