From b2ac92fcb6baae47d15817f6a14c1000fc637ecd Mon Sep 17 00:00:00 2001 From: Cr0a3 Date: Sun, 10 Nov 2024 16:21:06 +0100 Subject: [PATCH] [IR] reimplemented intenger optimizations + [FIX] fixed load ir printing --- src/IR/nodes/load.rs | 8 +- src/IR/nodes/math.rs | 394 +++++++++++++++++++++-- tests/IR/math/rem/rem0.yl | 2 +- tests/IR/math/shl/shl0.yl | 2 +- tests/Optimizations/const_eval/store0.yl | 2 +- 5 files changed, 381 insertions(+), 27 deletions(-) diff --git a/src/IR/nodes/load.rs b/src/IR/nodes/load.rs index 377a2ab8..938251b8 100644 --- a/src/IR/nodes/load.rs +++ b/src/IR/nodes/load.rs @@ -7,15 +7,15 @@ use super::{EvalOptVisitor, IROperand, Ir, Load}; impl Ir for Load { fn dump(&self) -> String { - format!("{} = load {}, {}", self.inner1.name, self.inner3, self.inner2) + format!("{} = load {} {}", self.inner1.name, self.inner2, self.inner3) } fn dumpColored(&self, profile: crate::Support::ColorProfile) -> String { - format!("{} = {} {}, {}", + format!("{} = {} {} {}", profile.markup(&self.inner1.name, ColorClass::Var), profile.markup("load", ColorClass::Instr), - profile.markup(&self.inner3.to_string(), ColorClass::Ty), - profile.markup(&self.inner2.to_string(), ColorClass::Var), + profile.markup(&self.inner2.to_string(), ColorClass::Ty), + profile.markup(&self.inner3.to_string(), ColorClass::Var), ) } diff --git a/src/IR/nodes/math.rs b/src/IR/nodes/math.rs index e5a05ff5..48ec5988 100644 --- a/src/IR/nodes/math.rs +++ b/src/IR/nodes/math.rs @@ -163,100 +163,454 @@ MathIrNode!(Shr, compile_shr, BuildShr, BuildShr, "shr"); impl EvalOptVisitor for Add { fn maybe_inline(&self, const_values: &HashMap) -> Option> { - todo!() + let mut new_ls = self.inner1.to_owned(); + let mut new_rs = self.inner2.to_owned(); + + if let IROperand::Var(ls) = &self.inner1 { + if let Some(ls) = const_values.get(&ls.name) { + new_ls = IROperand::Type(*ls); + } + } + if let IROperand::Var(rs) = &self.inner2 { + if let Some(rs) = const_values.get(&rs.name) { + new_rs = IROperand::Type(*rs); + } + } + + Some(Box::new(Add { + inner1: new_ls, + inner2: new_rs, + inner3: self.inner3.to_owned(), + })) } fn eval(&self) -> Option> { - todo!() + if let IROperand::Type(ty) = &self.inner1 { + if ty.val() == 0.0 { + return Some(match &self.inner2 { + IROperand::Type(rs) => Assign::new(self.inner3.to_owned(), *rs), + IROperand::Var(rs) => Assign::new(self.inner3.to_owned(), rs.to_owned()), + }) + } + } + if let IROperand::Type(ty) = &self.inner2 { + if ty.val() == 0.0 { + return Some(match &self.inner1 { + IROperand::Type(ls) => Assign::new(self.inner3.to_owned(), *ls), + IROperand::Var(ls) => Assign::new(self.inner3.to_owned(), ls.to_owned()), + }) + } + } + + if let IROperand::Type(ls) = &self.inner1 { + if let IROperand::Type(rs) = &self.inner2 { + let calc = ls.val() + rs.val(); + let calc = Type::from_int(self.inner3.ty, calc); + return Some(Assign::new(self.inner3.to_owned(), calc)); + } + } + + None } } impl EvalOptVisitor for Sub { fn maybe_inline(&self, const_values: &HashMap) -> Option> { - todo!() + let mut new_ls = self.inner1.to_owned(); + let mut new_rs = self.inner2.to_owned(); + + if let IROperand::Var(ls) = &self.inner1 { + if let Some(ls) = const_values.get(&ls.name) { + new_ls = IROperand::Type(*ls); + } + } + if let IROperand::Var(rs) = &self.inner2 { + if let Some(rs) = const_values.get(&rs.name) { + new_rs = IROperand::Type(*rs); + } + } + + Some(Box::new(Sub { + inner1: new_ls, + inner2: new_rs, + inner3: self.inner3.to_owned(), + })) } fn eval(&self) -> Option> { - todo!() + if let IROperand::Type(ty) = &self.inner2 { + if ty.val() == 0.0 { + return Some(match &self.inner1 { + IROperand::Type(ls) => Assign::new(self.inner3.to_owned(), *ls), + IROperand::Var(ls) => Assign::new(self.inner3.to_owned(), ls.to_owned()), + }) + } + } + if let IROperand::Type(ty) = &self.inner1 { + if ty.val() == 0.0 { + return Some(match &self.inner2 { + IROperand::Type(rs) => Assign::new(self.inner3.to_owned(), *rs), + IROperand::Var(rs) => Assign::new(self.inner3.to_owned(), rs.to_owned()), + }) + } + } + + if self.inner1 == self.inner2 { + return Some(Assign::new(self.inner3.to_owned(), Type::from_int(self.inner3.ty, 0.0))) + } + + + if let IROperand::Type(ls) = &self.inner1 { + if let IROperand::Type(rs) = &self.inner2 { + let calc = ls.val() - rs.val(); + let calc = Type::from_int(self.inner3.ty, calc); + return Some(Assign::new(self.inner3.to_owned(), calc)); + } + } + None } } impl EvalOptVisitor for Xor { fn maybe_inline(&self, const_values: &HashMap) -> Option> { - todo!() + let mut new_ls = self.inner1.to_owned(); + let mut new_rs = self.inner2.to_owned(); + + if let IROperand::Var(ls) = &self.inner1 { + if let Some(ls) = const_values.get(&ls.name) { + new_ls = IROperand::Type(*ls); + } + } + if let IROperand::Var(rs) = &self.inner2 { + if let Some(rs) = const_values.get(&rs.name) { + new_rs = IROperand::Type(*rs); + } + } + + Some(Box::new(Xor { + inner1: new_ls, + inner2: new_rs, + inner3: self.inner3.to_owned(), + })) } fn eval(&self) -> Option> { - todo!() + if self.inner1 == self.inner2 { + return Some(Assign::new(self.inner3.to_owned(), Type::from_int(self.inner3.ty, 0.0))) + } + + if let IROperand::Type(ls) = &self.inner1 { + if let IROperand::Type(rs) = &self.inner2 { + let calc = (ls.val() as i64) ^ (rs.val() as i64); + let calc = Type::from_int(self.inner3.ty, calc as f64); + return Some(Assign::new(self.inner3.to_owned(), calc)); + } + } + + None } } impl EvalOptVisitor for Or { fn maybe_inline(&self, const_values: &HashMap) -> Option> { - todo!() + let mut new_ls = self.inner1.to_owned(); + let mut new_rs = self.inner2.to_owned(); + + if let IROperand::Var(ls) = &self.inner1 { + if let Some(ls) = const_values.get(&ls.name) { + new_ls = IROperand::Type(*ls); + } + } + if let IROperand::Var(rs) = &self.inner2 { + if let Some(rs) = const_values.get(&rs.name) { + new_rs = IROperand::Type(*rs); + } + } + + Some(Box::new(Or { + inner1: new_ls, + inner2: new_rs, + inner3: self.inner3.to_owned(), + })) } fn eval(&self) -> Option> { - todo!() + if let IROperand::Type(ls) = &self.inner1 { + if let IROperand::Type(rs) = &self.inner2 { + let calc = (ls.val() as i64) | (rs.val() as i64); + let calc = Type::from_int(self.inner3.ty, calc as f64); + return Some(Assign::new(self.inner3.to_owned(), calc)); + } + } + + None } } impl EvalOptVisitor for And { fn maybe_inline(&self, const_values: &HashMap) -> Option> { - todo!() + let mut new_ls = self.inner1.to_owned(); + let mut new_rs = self.inner2.to_owned(); + + if let IROperand::Var(ls) = &self.inner1 { + if let Some(ls) = const_values.get(&ls.name) { + new_ls = IROperand::Type(*ls); + } + } + if let IROperand::Var(rs) = &self.inner2 { + if let Some(rs) = const_values.get(&rs.name) { + new_rs = IROperand::Type(*rs); + } + } + + Some(Box::new(And { + inner1: new_ls, + inner2: new_rs, + inner3: self.inner3.to_owned(), + })) } fn eval(&self) -> Option> { - todo!() + if let IROperand::Type(ls) = &self.inner1 { + if let IROperand::Type(rs) = &self.inner2 { + let calc = (ls.val() as i64) & (rs.val() as i64); + let calc = Type::from_int(self.inner3.ty, calc as f64); + return Some(Assign::new(self.inner3.to_owned(), calc)); + } + } + None } } impl EvalOptVisitor for Mul { fn maybe_inline(&self, const_values: &HashMap) -> Option> { - todo!() + let mut new_ls = self.inner1.to_owned(); + let mut new_rs = self.inner2.to_owned(); + + if let IROperand::Var(ls) = &self.inner1 { + if let Some(ls) = const_values.get(&ls.name) { + new_ls = IROperand::Type(*ls); + } + } + if let IROperand::Var(rs) = &self.inner2 { + if let Some(rs) = const_values.get(&rs.name) { + new_rs = IROperand::Type(*rs); + } + } + + Some(Box::new(Mul { + inner1: new_ls, + inner2: new_rs, + inner3: self.inner3.to_owned(), + })) } fn eval(&self) -> Option> { - todo!() + if let IROperand::Type(ty) = &self.inner1 { + if ty.val() == 0.0 { + return Some(Assign::new(self.inner3.to_owned(), Type::from_int((*ty).into(), 0.0))); + } else if ty.val() == 1.0 { + return Some(Assign::new(self.inner3.to_owned(), Type::from_int((*ty).into(), 0.0))); + } + } + + if let IROperand::Type(ty) = &self.inner2 { + if ty.val() == 0.0 { + return Some(Assign::new(self.inner3.to_owned(), Type::from_int((*ty).into(), 0.0))); + } else if ty.val() == 1.0 { + return Some(Assign::new(self.inner3.to_owned(), Type::from_int((*ty).into(), 0.0))); + } + } + + if let IROperand::Type(ls) = &self.inner1 { + if let IROperand::Type(rs) = &self.inner2 { + let calc = ls.val() * rs.val(); + let calc = Type::from_int(self.inner3.ty, calc); + return Some(Assign::new(self.inner3.to_owned(), calc)); + } + } + None } } impl EvalOptVisitor for Div { fn maybe_inline(&self, const_values: &HashMap) -> Option> { - todo!() + let mut new_ls = self.inner1.to_owned(); + let mut new_rs = self.inner2.to_owned(); + + if let IROperand::Var(ls) = &self.inner1 { + if let Some(ls) = const_values.get(&ls.name) { + new_ls = IROperand::Type(*ls); + } + } + if let IROperand::Var(rs) = &self.inner2 { + if let Some(rs) = const_values.get(&rs.name) { + new_rs = IROperand::Type(*rs); + } + } + + Some(Box::new(Div { + inner1: new_ls, + inner2: new_rs, + inner3: self.inner3.to_owned(), + })) } fn eval(&self) -> Option> { - todo!() + if self.inner1 == self.inner2 { + return Some(Assign::new(self.inner3.to_owned(), Type::from_int(self.inner3.ty, 1.0))); + } + + if let IROperand::Type(ty) = &self.inner2 { + if ty.val() == 1.0 { + return Some(Assign::new(self.inner3.to_owned(), Type::from_int((*ty).into(), 1.0))); + } // we could check for 0 but this would hide runtime errors which (positivly) "change" runtime behauvior + } + + if let IROperand::Type(ls) = &self.inner1 { + if let IROperand::Type(rs) = &self.inner2 { + let calc = ls.val() / rs.val(); + let calc = Type::from_int(self.inner3.ty, calc); + return Some(Assign::new(self.inner3.to_owned(), calc)); + } + } + None } } impl EvalOptVisitor for Rem { fn maybe_inline(&self, const_values: &HashMap) -> Option> { - todo!() + let mut new_ls = self.inner1.to_owned(); + let mut new_rs = self.inner2.to_owned(); + + if let IROperand::Var(ls) = &self.inner1 { + if let Some(ls) = const_values.get(&ls.name) { + new_ls = IROperand::Type(*ls); + } + } + if let IROperand::Var(rs) = &self.inner2 { + if let Some(rs) = const_values.get(&rs.name) { + new_rs = IROperand::Type(*rs); + } + } + + Some(Box::new(Rem { + inner1: new_ls, + inner2: new_rs, + inner3: self.inner3.to_owned(), + })) } fn eval(&self) -> Option> { - todo!() + if self.inner1 == self.inner2 { + return Some(Assign::new(self.inner3.to_owned(), Type::from_int(self.inner3.ty, 0.0))); + } + + if let IROperand::Type(ty) = &self.inner2 { + if ty.val() == 1.0 { + return Some(Assign::new(self.inner3.to_owned(), Type::from_int((*ty).into(), 0.0))); + } // we could check for 0 but this would hide runtime errors which (positivly) "change" runtime behauvior + } + + if let IROperand::Type(ls) = &self.inner1 { + if let IROperand::Type(rs) = &self.inner2 { + let calc = ls.val() % rs.val(); + let calc = Type::from_int(self.inner3.ty, calc); + return Some(Assign::new(self.inner3.to_owned(), calc)); + } + } + None } } impl EvalOptVisitor for Shl { fn maybe_inline(&self, const_values: &HashMap) -> Option> { - todo!() + let mut new_ls = self.inner1.to_owned(); + let mut new_rs = self.inner2.to_owned(); + + if let IROperand::Var(ls) = &self.inner1 { + if let Some(ls) = const_values.get(&ls.name) { + new_ls = IROperand::Type(*ls); + } + } + if let IROperand::Var(rs) = &self.inner2 { + if let Some(rs) = const_values.get(&rs.name) { + new_rs = IROperand::Type(*rs); + } + } + + Some(Box::new(Shl { + inner1: new_ls, + inner2: new_rs, + inner3: self.inner3.to_owned(), + })) } fn eval(&self) -> Option> { - todo!() + if let IROperand::Type(ty) = &self.inner2 { + if ty.val() == 0.0 { + return Some(match &self.inner1 { + IROperand::Type(ty) => Assign::new(self.inner3.to_owned(), *ty), + IROperand::Var(var) => Assign::new(self.inner3.to_owned(), var.to_owned()), + }); + } + } + + if let IROperand::Type(ls) = &self.inner1 { + if let IROperand::Type(rs) = &self.inner2 { + let calc = (ls.val() as i64) << (rs.val() as i64); + let calc = Type::from_int(self.inner3.ty, calc as f64); + return Some(Assign::new(self.inner3.to_owned(), calc)); + } + } + None } } impl EvalOptVisitor for Shr { fn maybe_inline(&self, const_values: &HashMap) -> Option> { - todo!() + let mut new_ls = self.inner1.to_owned(); + let mut new_rs = self.inner2.to_owned(); + + if let IROperand::Var(ls) = &self.inner1 { + if let Some(ls) = const_values.get(&ls.name) { + new_ls = IROperand::Type(*ls); + } + } + if let IROperand::Var(rs) = &self.inner2 { + if let Some(rs) = const_values.get(&rs.name) { + new_rs = IROperand::Type(*rs); + } + } + + Some(Box::new(Shr { + inner1: new_ls, + inner2: new_rs, + inner3: self.inner3.to_owned(), + })) } fn eval(&self) -> Option> { - todo!() + if self.inner1 == self.inner2 { + return Some(Assign::new(self.inner3.to_owned(), Type::from_int(self.inner3.ty, 0.0))); + } + + if let IROperand::Type(ty) = &self.inner2 { + if ty.val() == 0.0 { + return Some(match &self.inner1 { + IROperand::Type(ty) => Assign::new(self.inner3.to_owned(), *ty), + IROperand::Var(var) => Assign::new(self.inner3.to_owned(), var.to_owned()), + }); + } + } + + if let IROperand::Type(ls) = &self.inner1 { + if let IROperand::Type(rs) = &self.inner2 { + let calc = (ls.val() as i64) >> (rs.val() as i64); + let calc = Type::from_int(self.inner3.ty, calc as f64); + return Some(Assign::new(self.inner3.to_owned(), calc)); + } + } + None } } \ No newline at end of file diff --git a/tests/IR/math/rem/rem0.yl b/tests/IR/math/rem/rem0.yl index b8c0cf8d..3aacd231 100644 --- a/tests/IR/math/rem/rem0.yl +++ b/tests/IR/math/rem/rem0.yl @@ -6,7 +6,7 @@ gcc out.o -o a.exe define i32 @main() { entry: %1 = rem i32 12, 5 - ret u32 %1 + ret i32 %1 } # EXIT_CODE=2 \ No newline at end of file diff --git a/tests/IR/math/shl/shl0.yl b/tests/IR/math/shl/shl0.yl index 6deea191..e9e518b7 100644 --- a/tests/IR/math/shl/shl0.yl +++ b/tests/IR/math/shl/shl0.yl @@ -6,7 +6,7 @@ gcc out.o -o a.exe define i32 @main() { entry: %1 = shl i32 4, 1 - ret u32 %1 + ret i32 %1 } # EXIT_CODE=8 \ No newline at end of file diff --git a/tests/Optimizations/const_eval/store0.yl b/tests/Optimizations/const_eval/store0.yl index aacaaa9b..bcefe3af 100644 --- a/tests/Optimizations/const_eval/store0.yl +++ b/tests/Optimizations/const_eval/store0.yl @@ -17,6 +17,6 @@ define i32 @main() { %0 = alloca i32 %1 = i32 5 store i32 5, %0 - %3 = load i32, %0 + %3 = load i32 %0 ret i32 0 } \ No newline at end of file