diff --git a/Cargo.lock b/Cargo.lock index 3c420ee8..d44fada2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5399,6 +5399,7 @@ dependencies = [ "veryl-analyzer", "veryl-emitter", "veryl-formatter", + "veryl-ir", "veryl-metadata", "veryl-migrator", "veryl-parser", @@ -5429,6 +5430,7 @@ dependencies = [ "strnum_bitwidth", "thiserror 2.0.17", "toml 0.9.8", + "veryl-ir", "veryl-metadata", "veryl-parser", ] @@ -5458,6 +5460,15 @@ dependencies = [ "veryl-parser", ] +[[package]] +name = "veryl-ir" +version = "0.17.0" +dependencies = [ + "num-bigint", + "num-traits", + "veryl-parser", +] + [[package]] name = "veryl-ls" version = "0.17.0" diff --git a/Cargo.toml b/Cargo.toml index aa887865..624c10c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "crates/analyzer", "crates/emitter", "crates/formatter", + "crates/ir", "crates/languageserver", "crates/mdbook", "crates/metadata", @@ -42,6 +43,8 @@ handlebars = "6.3" log = "0.4.28" mdbook = "0.4.51" miette = {version = "7.6"} +num-bigint = "0.4.6" +num-traits = "0.2.19" once_cell = "1.21" parol_runtime = "4.0" pulldown-cmark = "0.13.0" diff --git a/Makefile b/Makefile index 846ca53a..9d012244 100644 --- a/Makefile +++ b/Makefile @@ -77,6 +77,9 @@ install: gen_sv: cargo run --bin veryl -- build +gen_ir: + cargo run --bin veryl -- dump --ir + fmt_veryl: cargo run --bin veryl -- fmt diff --git a/crates/analyzer/Cargo.toml b/crates/analyzer/Cargo.toml index 57d7e145..a5362253 100644 --- a/crates/analyzer/Cargo.toml +++ b/crates/analyzer/Cargo.toml @@ -18,11 +18,12 @@ daggy = "0.9.0" fxhash = {workspace = true} itertools = "0.14.0" log = {workspace = true} -num-bigint = "0.4.6" -num-traits = "0.2.19" +num-bigint = {workspace = true} +num-traits = {workspace = true} smallvec = {workspace = true} strnum_bitwidth = {workspace = true} thiserror = {workspace = true} +veryl-ir = {version = "0.17.0", path = "../ir"} veryl-metadata = {version = "0.17.0", path = "../metadata"} veryl-parser = {version = "0.17.0", path = "../parser"} diff --git a/crates/analyzer/src/analyzer.rs b/crates/analyzer/src/analyzer.rs index 455205ee..71a08d69 100644 --- a/crates/analyzer/src/analyzer.rs +++ b/crates/analyzer/src/analyzer.rs @@ -21,6 +21,7 @@ use crate::var_ref::{ }; use itertools::Itertools; use std::path::Path; +use veryl_ir::Ir; use veryl_metadata::{Build, EnvVar, Lint, Metadata}; use veryl_parser::resource_table::{self, StrId}; use veryl_parser::token_range::TokenRange; @@ -56,6 +57,10 @@ impl AnalyzerPass2 { handlers: Pass2Handlers::new(build_opt, lint_opt, env_var), } } + + pub fn get_ir(&self) -> Ir { + self.handlers.get_ir() + } } impl VerylWalker for AnalyzerPass2 { @@ -382,6 +387,7 @@ impl Analyzer { project_name: &str, _path: T, input: &Veryl, + ir: Option<&mut Ir>, ) -> Vec { let mut ret = Vec::new(); @@ -393,6 +399,10 @@ impl Analyzer { pass2.veryl(input); ret.append(&mut pass2.handlers.get_errors()); + if let Some(x) = ir { + x.append(&mut pass2.get_ir()); + } + ret } diff --git a/crates/analyzer/src/handlers.rs b/crates/analyzer/src/handlers.rs index 6679079e..470e3e34 100644 --- a/crates/analyzer/src/handlers.rs +++ b/crates/analyzer/src/handlers.rs @@ -18,6 +18,7 @@ pub mod check_statement; pub mod check_type; pub mod check_unsafe; pub mod check_var_ref; +pub mod create_ir; pub mod create_symbol_table; use check_anonymous::*; use check_attribute::*; @@ -39,9 +40,11 @@ use check_statement::*; use check_type::*; use check_unsafe::*; use check_var_ref::*; +use create_ir::*; use create_symbol_table::*; use crate::analyzer_error::AnalyzerError; +use veryl_ir::Ir; use veryl_metadata::{Build, EnvVar, Lint}; use veryl_parser::veryl_walker::Handler; @@ -114,7 +117,8 @@ pub struct Pass2Handlers { check_clock_domain: CheckClockDomain, check_proto: CheckProto, check_type: CheckType, - enables: [bool; 13], + create_ir: CreateIr, + enables: [bool; 14], } impl Pass2Handlers { @@ -133,6 +137,7 @@ impl Pass2Handlers { check_clock_domain: CheckClockDomain::new(), check_proto: CheckProto::new(), check_type: CheckType::new(), + create_ir: CreateIr::new(), enables: env_var.analyzer_pass2_enables, } } @@ -153,6 +158,7 @@ impl Pass2Handlers { (en[10], &mut self.check_clock_domain as &mut dyn Handler), (en[11], &mut self.check_proto as &mut dyn Handler), (en[12], &mut self.check_type as &mut dyn Handler), + (en[13], &mut self.create_ir as &mut dyn Handler), ] } @@ -171,6 +177,11 @@ impl Pass2Handlers { ret.append(&mut self.check_clock_domain.errors); ret.append(&mut self.check_proto.errors); ret.append(&mut self.check_type.errors); + ret.append(&mut self.create_ir.errors); ret } + + pub fn get_ir(&self) -> Ir { + self.create_ir.ir.clone() + } } diff --git a/crates/analyzer/src/handlers/create_ir.rs b/crates/analyzer/src/handlers/create_ir.rs new file mode 100644 index 00000000..3d1a21ae --- /dev/null +++ b/crates/analyzer/src/handlers/create_ir.rs @@ -0,0 +1,122 @@ +use crate::AnalyzerError; +use crate::handlers::Handler; +use crate::symbol::{Direction, SymbolKind}; +use crate::symbol_table; +use std::collections::HashMap; +use veryl_ir::{Declaration, Expression, Ir, Module, Value, VarId, VarKind, VarPath, Variable}; +use veryl_parser::ParolError; +use veryl_parser::veryl_grammar_trait::*; +use veryl_parser::veryl_walker::HandlerPoint; + +#[derive(Default)] +pub struct CreateIr { + pub errors: Vec, + pub ir: Ir, + var_id: VarId, + variables: HashMap, + declarations: Vec, + point: HandlerPoint, +} + +impl CreateIr { + pub fn new() -> Self { + Self { + ..Default::default() + } + } + + fn add_var(&mut self, var: Variable) { + self.variables.insert(self.var_id, var); + self.var_id.inc(); + } +} + +impl Handler for CreateIr { + fn set_point(&mut self, p: HandlerPoint) { + self.point = p; + } +} + +impl VerylGrammarTrait for CreateIr { + fn module_declaration(&mut self, arg: &ModuleDeclaration) -> Result<(), ParolError> { + match self.point { + HandlerPoint::Before => { + self.variables.clear(); + self.declarations.clear(); + } + HandlerPoint::After => { + let name = arg.identifier.identifier_token.token.text; + let module = Module { + name, + variables: self.variables.drain().collect(), + declarations: self.declarations.drain(..).collect(), + }; + + self.ir.modules.push(module); + } + } + Ok(()) + } + + fn with_parameter_item(&mut self, arg: &WithParameterItem) -> Result<(), ParolError> { + if let HandlerPoint::Before = self.point + && let Ok(symbol) = symbol_table::resolve(arg.identifier.as_ref()) + { + if let SymbolKind::Parameter(x) = symbol.found.kind { + let path = VarPath(vec![(symbol.found.token.text, vec![])]); + let kind = if x.kind.is_const() { + VarKind::Const + } else { + VarKind::Param + }; + if let Some(value) = &x.value { + let value: Expression = value.into(); + let value = value.eval(None, &self.variables); + + let variable = Variable { + id: self.var_id, + path, + kind, + value, + }; + self.add_var(variable); + } else { + // TODO missing_default_argument if not proto + } + } else { + unreachable!(); + } + } + Ok(()) + } + + fn port_declaration_item(&mut self, arg: &PortDeclarationItem) -> Result<(), ParolError> { + if let HandlerPoint::Before = self.point + && let Ok(symbol) = symbol_table::resolve(arg.identifier.as_ref()) + { + if let SymbolKind::Port(x) = symbol.found.kind { + let path = VarPath(vec![(symbol.found.token.text, vec![])]); + let kind = match x.direction { + Direction::Input => VarKind::Input, + Direction::Output => VarKind::Output, + Direction::Inout => VarKind::Inout, + _ => { + // TODO modport + return Ok(()); + } + }; + let value = Value::new_x(1, false); + let variable = Variable { + id: self.var_id, + path, + kind, + value, + }; + self.add_var(variable); + } else { + unreachable!(); + } + } + Ok(()) + } +} diff --git a/crates/analyzer/src/tests.rs b/crates/analyzer/src/tests.rs index d33c1800..92a599c3 100644 --- a/crates/analyzer/src/tests.rs +++ b/crates/analyzer/src/tests.rs @@ -16,7 +16,7 @@ fn analyze(code: &str) -> Vec { let mut errors = vec![]; errors.append(&mut analyzer.analyze_pass1(&"prj", &"", &parser.veryl)); errors.append(&mut Analyzer::analyze_post_pass1()); - errors.append(&mut analyzer.analyze_pass2(&"prj", &"", &parser.veryl)); + errors.append(&mut analyzer.analyze_pass2(&"prj", &"", &parser.veryl, None)); let info = Analyzer::analyze_post_pass2(); errors.append(&mut analyzer.analyze_pass3(&"prj", &"", &parser.veryl, &info)); dbg!(&errors); diff --git a/crates/emitter/src/tests.rs b/crates/emitter/src/tests.rs index 6c813bb8..e3f0e2f7 100644 --- a/crates/emitter/src/tests.rs +++ b/crates/emitter/src/tests.rs @@ -14,7 +14,7 @@ fn emit(metadata: &Metadata, code: &str) -> String { analyzer.analyze_pass1(&"prj", &"", &parser.veryl); Analyzer::analyze_post_pass1(); - analyzer.analyze_pass2(&"prj", &"", &parser.veryl); + analyzer.analyze_pass2(&"prj", &"", &parser.veryl, None); let mut emitter = Emitter::new( metadata, diff --git a/crates/formatter/src/tests.rs b/crates/formatter/src/tests.rs index a3eade66..3ba9ee9a 100644 --- a/crates/formatter/src/tests.rs +++ b/crates/formatter/src/tests.rs @@ -10,7 +10,7 @@ fn format(metadata: &Metadata, code: &str) -> String { analyzer.analyze_pass1(&"prj", &"", &parser.veryl); Analyzer::analyze_post_pass1(); - analyzer.analyze_pass2(&"prj", &"", &parser.veryl); + analyzer.analyze_pass2(&"prj", &"", &parser.veryl, None); let mut formatter = Formatter::new(metadata); formatter.format(&parser.veryl); diff --git a/crates/ir/Cargo.toml b/crates/ir/Cargo.toml new file mode 100644 index 00000000..307aeff7 --- /dev/null +++ b/crates/ir/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "veryl-ir" +version = "0.17.0" +authors.workspace = true +repository.workspace = true +keywords.workspace = true +categories.workspace = true +license.workspace = true +readme.workspace = true +description.workspace = true +edition.workspace = true + +[dependencies] +num-bigint = {workspace = true} +num-traits = {workspace = true} +veryl-parser = {version = "0.17.0", path = "../parser"} diff --git a/crates/ir/src/bigint.rs b/crates/ir/src/bigint.rs new file mode 100644 index 00000000..152468f9 --- /dev/null +++ b/crates/ir/src/bigint.rs @@ -0,0 +1,104 @@ +use num_bigint::{BigInt, BigUint, Sign}; + +pub fn gen_mask(width: usize) -> BigUint { + let mut ret = Vec::new(); + let mut remaining = width; + loop { + if remaining >= 32 { + ret.push(0xffffffff); + remaining -= 32; + } else { + ret.push((1u32 << remaining) - 1); + break; + } + } + BigUint::from_slice(&ret) +} + +pub fn inv(value: BigUint, width: usize) -> BigUint { + let mut ret = Vec::new(); + let mut remaining = width; + let values = value.to_u32_digits(); + let mut i = 0; + loop { + if remaining >= 32 { + let value = values.get(i).unwrap_or(&0); + ret.push(!value); + remaining -= 32; + i += 1; + } else { + let value = values.get(i).unwrap_or(&0); + let mask = (1u32 << remaining) - 1; + ret.push((!value) & mask); + break; + } + } + BigUint::from_slice(&ret) +} + +pub fn to_biguint(value: BigInt, width: usize) -> BigUint { + if value.sign() == Sign::Plus { + value.magnitude().clone() + } else { + let payload = value.magnitude().clone(); + let mask = gen_mask(width); + (inv(payload, width) + BigUint::from(1u32)) & mask + } +} + +pub fn select(value: BigUint, beg: usize, end: usize) -> BigUint { + let ret = value >> end; + let mask = gen_mask(beg - end + 1); + ret & mask +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_mask() { + assert_eq!(format!("{:x}", gen_mask(1)), "1"); + assert_eq!(format!("{:x}", gen_mask(2)), "3"); + assert_eq!(format!("{:x}", gen_mask(3)), "7"); + assert_eq!(format!("{:x}", gen_mask(10)), "3ff"); + assert_eq!(format!("{:x}", gen_mask(59)), "7ffffffffffffff"); + assert_eq!(format!("{:x}", gen_mask(90)), "3ffffffffffffffffffffff"); + } + + #[test] + fn test_inv() { + assert_eq!(format!("{:x}", inv(BigUint::from(1u32), 1)), "0"); + assert_eq!(format!("{:x}", inv(BigUint::from(1u32), 2)), "2"); + assert_eq!(format!("{:x}", inv(BigUint::from(1u32), 3)), "6"); + assert_eq!(format!("{:x}", inv(BigUint::from(1u32), 10)), "3fe"); + assert_eq!( + format!("{:x}", inv(BigUint::from(1u32), 59)), + "7fffffffffffffe" + ); + assert_eq!( + format!("{:x}", inv(BigUint::from(1u32), 90)), + "3fffffffffffffffffffffe" + ); + } + + #[test] + fn test_to_biguint() { + assert_eq!(format!("{:x}", to_biguint(BigInt::from(1), 10)), "1"); + assert_eq!(format!("{:x}", to_biguint(BigInt::from(2), 10)), "2"); + assert_eq!(format!("{:x}", to_biguint(BigInt::from(3), 10)), "3"); + assert_eq!(format!("{:x}", to_biguint(BigInt::from(-1), 10)), "3ff"); + assert_eq!(format!("{:x}", to_biguint(BigInt::from(-2), 10)), "3fe"); + assert_eq!(format!("{:x}", to_biguint(BigInt::from(-3), 10)), "3fd"); + } + + #[test] + fn test_select() { + assert_eq!(format!("{:x}", select(BigUint::from(0xffu32), 0, 0)), "1"); + assert_eq!(format!("{:x}", select(BigUint::from(0xffu32), 1, 0)), "3"); + assert_eq!(format!("{:x}", select(BigUint::from(0xffu32), 3, 0)), "f"); + assert_eq!(format!("{:x}", select(BigUint::from(0xf0u32), 3, 0)), "0"); + assert_eq!(format!("{:x}", select(BigUint::from(0xf0u32), 4, 1)), "8"); + assert_eq!(format!("{:x}", select(BigUint::from(0xf0u32), 7, 2)), "3c"); + } +} diff --git a/crates/ir/src/conv_expr.rs b/crates/ir/src/conv_expr.rs new file mode 100644 index 00000000..d5633ace --- /dev/null +++ b/crates/ir/src/conv_expr.rs @@ -0,0 +1,868 @@ +use crate::expression::Expression as IrExpression; +use crate::expression::Factor as IrFactor; +use crate::expression::Op; +use crate::variable::Value; +use num_bigint::BigUint; +use num_traits::Num; +use veryl_parser::veryl_grammar_trait::*; + +impl From<&Expression> for IrExpression { + fn from(value: &Expression) -> Self { + value.if_expression.as_ref().into() + } +} + +impl From<&IfExpression> for IrExpression { + fn from(value: &IfExpression) -> Self { + let mut ret: IrExpression = value.expression01.as_ref().into(); + for x in value.if_expression_list.iter().rev() { + let y: IrExpression = x.expression.as_ref().into(); + let z: IrExpression = x.expression0.as_ref().into(); + ret = IrExpression::Ternary(Box::new(y), Box::new(z), Box::new(ret)); + } + ret + } +} + +impl From<&Expression01> for IrExpression { + fn from(value: &Expression01) -> Self { + let mut ret: IrExpression = value.expression02.as_ref().into(); + for x in &value.expression01_list { + let right: IrExpression = x.expression02.as_ref().into(); + ret = IrExpression::Binary(Box::new(ret), Op::LogicOr, Box::new(right)); + } + ret + } +} + +impl From<&Expression02> for IrExpression { + fn from(value: &Expression02) -> Self { + let mut ret: IrExpression = value.expression03.as_ref().into(); + for x in &value.expression02_list { + let right: IrExpression = x.expression03.as_ref().into(); + ret = IrExpression::Binary(Box::new(ret), Op::LogicAnd, Box::new(right)); + } + ret + } +} + +impl From<&Expression03> for IrExpression { + fn from(value: &Expression03) -> Self { + let mut ret: IrExpression = value.expression04.as_ref().into(); + for x in &value.expression03_list { + let right: IrExpression = x.expression04.as_ref().into(); + ret = IrExpression::Binary(Box::new(ret), Op::BitOr, Box::new(right)); + } + ret + } +} + +impl From<&Expression04> for IrExpression { + fn from(value: &Expression04) -> Self { + let mut ret: IrExpression = value.expression05.as_ref().into(); + for x in &value.expression04_list { + let right: IrExpression = x.expression05.as_ref().into(); + let op = x.operator05.operator05_token.to_string(); + let op = match op.as_str() { + "^" => Op::BitXor, + "~^" => Op::BitXnor, + _ => unreachable!(), + }; + ret = IrExpression::Binary(Box::new(ret), op, Box::new(right)); + } + ret + } +} + +impl From<&Expression05> for IrExpression { + fn from(value: &Expression05) -> Self { + let mut ret: IrExpression = value.expression06.as_ref().into(); + for x in &value.expression05_list { + let right: IrExpression = x.expression06.as_ref().into(); + ret = IrExpression::Binary(Box::new(ret), Op::BitAnd, Box::new(right)); + } + ret + } +} + +impl From<&Expression06> for IrExpression { + fn from(value: &Expression06) -> Self { + let mut ret: IrExpression = value.expression07.as_ref().into(); + for x in &value.expression06_list { + let right: IrExpression = x.expression07.as_ref().into(); + let op = x.operator07.operator07_token.to_string(); + let op = match op.as_str() { + "==" => Op::Eq, + "!=" => Op::Ne, + "==?" => Op::EqWildcard, + "!=?" => Op::NeWildcard, + _ => unreachable!(), + }; + ret = IrExpression::Binary(Box::new(ret), op, Box::new(right)); + } + ret + } +} + +impl From<&Expression07> for IrExpression { + fn from(value: &Expression07) -> Self { + let mut ret: IrExpression = value.expression08.as_ref().into(); + for x in &value.expression07_list { + let right: IrExpression = x.expression08.as_ref().into(); + let op = x.operator08.operator08_token.to_string(); + let op = match op.as_str() { + "<=" => Op::LessEq, + ">=" => Op::GreaterEq, + "<:" => Op::Less, + ">:" => Op::Greater, + _ => unreachable!(), + }; + ret = IrExpression::Binary(Box::new(ret), op, Box::new(right)); + } + ret + } +} + +impl From<&Expression08> for IrExpression { + fn from(value: &Expression08) -> Self { + let mut ret: IrExpression = value.expression09.as_ref().into(); + for x in &value.expression08_list { + let right: IrExpression = x.expression09.as_ref().into(); + let op = x.operator09.operator09_token.to_string(); + let op = match op.as_str() { + "<<<" => Op::ArithShiftL, + ">>>" => Op::ArithShiftR, + "<<" => Op::LogicShiftL, + ">>" => Op::LogicShiftR, + _ => unreachable!(), + }; + ret = IrExpression::Binary(Box::new(ret), op, Box::new(right)); + } + ret + } +} + +impl From<&Expression09> for IrExpression { + fn from(value: &Expression09) -> Self { + let mut ret: IrExpression = value.expression10.as_ref().into(); + for x in &value.expression09_list { + let right: IrExpression = x.expression10.as_ref().into(); + let op = x.operator10.operator10_token.to_string(); + let op = match op.as_str() { + "+" => Op::Add, + "-" => Op::Sub, + _ => unreachable!(), + }; + ret = IrExpression::Binary(Box::new(ret), op, Box::new(right)); + } + ret + } +} + +impl From<&Expression10> for IrExpression { + fn from(value: &Expression10) -> Self { + let mut ret: IrExpression = value.expression11.as_ref().into(); + for x in &value.expression10_list { + let right: IrExpression = x.expression11.as_ref().into(); + let op = match x.expression10_list_group.as_ref() { + Expression10ListGroup::Operator11(x) => { + let op = x.operator11.operator11_token.to_string(); + match op.as_str() { + "/" => Op::Div, + "%" => Op::Rem, + _ => unreachable!(), + } + } + Expression10ListGroup::Star(_) => Op::Mul, + }; + ret = IrExpression::Binary(Box::new(ret), op, Box::new(right)); + } + ret + } +} + +impl From<&Expression11> for IrExpression { + fn from(value: &Expression11) -> Self { + let mut ret: IrExpression = value.expression12.as_ref().into(); + for x in &value.expression11_list { + let right: IrExpression = x.expression12.as_ref().into(); + ret = IrExpression::Binary(Box::new(ret), Op::Pow, Box::new(right)); + } + ret + } +} + +impl From<&Expression12> for IrExpression { + fn from(value: &Expression12) -> Self { + let ret = value.expression13.as_ref().into(); + if value.expression12_opt.is_some() { + // TODO + IrExpression::Binary( + Box::new(ret), + Op::As, + Box::new(IrExpression::Term(IrFactor::Unknown)), + ) + } else { + ret + } + } +} + +impl From<&Expression13> for IrExpression { + fn from(value: &Expression13) -> Self { + let mut ret: IrExpression = value.factor.as_ref().into(); + for x in value.expression13_list.iter().rev() { + let op = match x.expression13_list_group.as_ref() { + Expression13ListGroup::UnaryOperator(x) => { + let token = x.unary_operator.unary_operator_token.to_string(); + match token.as_str() { + "~&" => Op::BitNand, + "~|" => Op::BitNor, + "~" => Op::BitNot, + "!" => Op::LogicNot, + _ => unreachable!(), + } + } + Expression13ListGroup::Operator04(_) => Op::BitOr, + Expression13ListGroup::Operator05(x) => { + let token = x.operator05.operator05_token.to_string(); + match token.as_str() { + "^" => Op::BitXor, + "~^" => Op::BitXnor, + _ => unreachable!(), + } + } + Expression13ListGroup::Operator06(_) => Op::BitAnd, + Expression13ListGroup::Operator10(x) => { + let token = x.operator10.operator10_token.to_string(); + match token.as_str() { + "+" => Op::Add, + "-" => Op::Sub, + _ => unreachable!(), + } + } + }; + + ret = IrExpression::Unary(op, Box::new(ret)); + } + ret + } +} + +impl From<&Factor> for IrExpression { + fn from(value: &Factor) -> Self { + match value { + Factor::Number(x) => { + let x: Value = x.number.as_ref().into(); + IrExpression::Term(IrFactor::Value(x)) + } + Factor::BooleanLiteral(x) => { + let x = match x.boolean_literal.as_ref() { + BooleanLiteral::True(_) => 1u32, + BooleanLiteral::False(_) => 0u32, + }; + let x = Value::new(BigUint::from(x), 1, false); + IrExpression::Term(IrFactor::Value(x)) + } + Factor::IdentifierFactor(x) => { + if x.identifier_factor.identifier_factor_opt.is_some() { + // TODO function call + IrExpression::Term(IrFactor::Unknown) + } else { + IrExpression::Term(IrFactor::Unresolved( + x.identifier_factor.expression_identifier.as_ref().clone(), + )) + } + } + Factor::LParenExpressionRParen(x) => x.expression.as_ref().into(), + Factor::LBraceConcatenationListRBrace(x) => { + let x = x.concatenation_list.as_ref(); + let exp: IrExpression = x.concatenation_item.expression.as_ref().into(); + let rep: Option = x + .concatenation_item + .concatenation_item_opt + .as_ref() + .map(|x| x.expression.as_ref().into()); + let mut ret = vec![(exp, rep)]; + + for x in &x.concatenation_list_list { + let exp: IrExpression = x.concatenation_item.expression.as_ref().into(); + let rep: Option = x + .concatenation_item + .concatenation_item_opt + .as_ref() + .map(|x| x.expression.as_ref().into()); + ret.push((exp, rep)); + } + + IrExpression::Concatenation(ret) + } + Factor::QuoteLBraceArrayLiteralListRBrace(_) => IrExpression::Term(IrFactor::Unknown), + Factor::CaseExpression(x) => { + let tgt: IrExpression = x.case_expression.expression.as_ref().into(); + let exp: IrExpression = x.case_expression.expression0.as_ref().into(); + let defaul: IrExpression = x.case_expression.expression1.as_ref().into(); + let cond = case_condition(&tgt, x.case_expression.case_condition.as_ref()); + + let mut ret = + IrExpression::Ternary(Box::new(cond), Box::new(exp), Box::new(defaul)); + + for x in &x.case_expression.case_expression_list { + let cond = case_condition(&tgt, x.case_condition.as_ref()); + let exp: IrExpression = x.expression.as_ref().into(); + + if let IrExpression::Ternary(x, y, z) = ret { + let arm = IrExpression::Ternary(Box::new(cond), Box::new(exp), z); + ret = IrExpression::Ternary(x, y, Box::new(arm)); + } else { + unreachable!() + } + } + ret + } + Factor::SwitchExpression(x) => { + let exp: IrExpression = x.switch_expression.expression.as_ref().into(); + let defaul: IrExpression = x.switch_expression.expression0.as_ref().into(); + let cond = switch_condition(x.switch_expression.switch_condition.as_ref()); + + let mut ret = + IrExpression::Ternary(Box::new(cond), Box::new(exp), Box::new(defaul)); + + for x in &x.switch_expression.switch_expression_list { + let cond = switch_condition(x.switch_condition.as_ref()); + let exp: IrExpression = x.expression.as_ref().into(); + + if let IrExpression::Ternary(x, y, z) = ret { + let arm = IrExpression::Ternary(Box::new(cond), Box::new(exp), z); + ret = IrExpression::Ternary(x, y, Box::new(arm)); + } else { + unreachable!() + } + } + ret + } + Factor::StringLiteral(_) => IrExpression::Term(IrFactor::Unknown), + Factor::FactorGroup(_) => IrExpression::Term(IrFactor::Unknown), + Factor::InsideExpression(x) => { + let exp: IrExpression = x.inside_expression.expression.as_ref().into(); + range_list(&exp, x.inside_expression.range_list.as_ref()) + } + Factor::OutsideExpression(x) => { + let exp: IrExpression = x.outside_expression.expression.as_ref().into(); + let ret = range_list(&exp, x.outside_expression.range_list.as_ref()); + IrExpression::Unary(Op::LogicNot, Box::new(ret)) + } + Factor::TypeExpression(_) => IrExpression::Term(IrFactor::Unknown), + Factor::FactorTypeFactor(_) => IrExpression::Term(IrFactor::Unknown), + } + } +} + +fn case_condition(tgt: &IrExpression, cond: &CaseCondition) -> IrExpression { + let mut ret = range_item(tgt, &cond.range_item); + for x in &cond.case_condition_list { + let item = range_item(tgt, &x.range_item); + ret = IrExpression::Binary(Box::new(ret), Op::LogicOr, Box::new(item)); + } + ret +} + +fn range_list(tgt: &IrExpression, list: &RangeList) -> IrExpression { + let mut ret = range_item(tgt, &list.range_item); + for x in &list.range_list_list { + let item = range_item(tgt, &x.range_item); + ret = IrExpression::Binary(Box::new(ret), Op::LogicOr, Box::new(item)); + } + ret +} + +fn range_item(tgt: &IrExpression, range_item: &RangeItem) -> IrExpression { + let exp: IrExpression = range_item.range.expression.as_ref().into(); + if let Some(x) = &range_item.range.range_opt { + let exp0: IrExpression = x.expression.as_ref().into(); + match x.range_operator.as_ref() { + RangeOperator::DotDot(_) => { + let cond0 = + IrExpression::Binary(Box::new(exp.clone()), Op::LessEq, Box::new(tgt.clone())); + let cond1 = + IrExpression::Binary(Box::new(tgt.clone()), Op::Less, Box::new(exp0.clone())); + IrExpression::Binary(Box::new(cond0), Op::LogicAnd, Box::new(cond1)) + } + RangeOperator::DotDotEqu(_) => { + let cond0 = + IrExpression::Binary(Box::new(exp.clone()), Op::LessEq, Box::new(tgt.clone())); + let cond1 = + IrExpression::Binary(Box::new(tgt.clone()), Op::LessEq, Box::new(exp0.clone())); + IrExpression::Binary(Box::new(cond0), Op::LogicAnd, Box::new(cond1)) + } + } + } else { + IrExpression::Binary(Box::new(tgt.clone()), Op::EqWildcard, Box::new(exp)) + } +} + +fn switch_condition(cond: &SwitchCondition) -> IrExpression { + let mut ret: IrExpression = cond.expression.as_ref().into(); + for x in &cond.switch_condition_list { + let exp: IrExpression = x.expression.as_ref().into(); + ret = IrExpression::Binary(Box::new(ret), Op::LogicOr, Box::new(exp)); + } + ret +} + +impl From<&Number> for Value { + fn from(value: &Number) -> Self { + match value { + Number::IntegralNumber(x) => match x.integral_number.as_ref() { + IntegralNumber::Based(x) => { + let x = x.based.based_token.to_string().replace('_', ""); + if let Some((width, rest)) = x.split_once('\'') { + let signed = &rest[0..1] == "s"; + let rest = if signed { &rest[1..] } else { rest }; + let (base, value) = rest.split_at(1); + let (radix, all1_char) = match base { + "b" => (2, '1'), + "o" => (8, '7'), + "d" => (10, '0'), + "h" => (16, 'f'), + _ => unreachable!(), + }; + + let payload = value.replace(['x', 'X', 'z', 'Z'], "0"); + let mask_x: String = value + .chars() + .map(|x| if x == 'x' || x == 'X' { all1_char } else { '0' }) + .collect(); + let mask_z: String = value + .chars() + .map(|x| if x == 'z' || x == 'Z' { all1_char } else { '0' }) + .collect(); + + let payload = BigUint::from_str_radix(&payload, radix).unwrap(); + let mask_x = BigUint::from_str_radix(&mask_x, radix).unwrap(); + let mask_z = BigUint::from_str_radix(&mask_z, radix).unwrap(); + + let width = if let Ok(x) = str::parse::(width) { + x + } else { + payload.bits().max(mask_x.bits()).max(mask_z.bits()) as usize + }; + + Value { + payload, + mask_x, + mask_z, + width, + signed, + } + } else { + unreachable!() + } + } + IntegralNumber::BaseLess(x) => { + let x = x.base_less.base_less_token.to_string().replace('_', ""); + let x = str::parse::(&x).unwrap(); + Value::new(x, 32, true) + } + IntegralNumber::AllBit(x) => { + let x = x.all_bit.all_bit_token.to_string(); + match x.as_str() { + "'1" => Value { + payload: BigUint::from(1u32), + mask_x: BigUint::from(0u32), + mask_z: BigUint::from(0u32), + width: 0, + signed: false, + }, + "'0" => Value { + payload: BigUint::from(0u32), + mask_x: BigUint::from(0u32), + mask_z: BigUint::from(0u32), + width: 0, + signed: false, + }, + "'x" | "'X" => Value { + payload: BigUint::from(0u32), + mask_x: BigUint::from(1u32), + mask_z: BigUint::from(0u32), + width: 0, + signed: false, + }, + "'z" | "'Z" => Value { + payload: BigUint::from(0u32), + mask_x: BigUint::from(0u32), + mask_z: BigUint::from(1u32), + width: 0, + signed: false, + }, + _ => unreachable!(), + } + } + }, + Number::RealNumber(_) => todo!(), + } + } +} + +#[cfg(test)] +pub fn parse_number(s: &str) -> Number { + use veryl_parser::parser::Parser; + use veryl_parser::veryl_walker::VerylWalker; + + let src = format!( + r#" + module A {{ + let a: bit = {s}; + }} + "# + ); + let parser = Parser::parse(&src, &"").unwrap(); + + struct Extractor(Option); + impl VerylWalker for Extractor { + fn number(&mut self, arg: &Number) { + self.0 = Some(arg.clone()); + } + } + + let mut extractor = Extractor(None); + extractor.veryl(&parser.veryl); + extractor.0.unwrap() +} + +#[cfg(test)] +pub fn parse_expression(s: &str) -> Expression { + use veryl_parser::parser::Parser; + use veryl_parser::veryl_walker::VerylWalker; + + let src = format!( + r#" + module A {{ + let a: bit = {s}; + }} + "# + ); + let parser = Parser::parse(&src, &"").unwrap(); + + struct Extractor(Option); + impl VerylWalker for Extractor { + fn expression(&mut self, arg: &Expression) { + self.0 = Some(arg.clone()); + } + } + + let mut extractor = Extractor(None); + extractor.veryl(&parser.veryl); + extractor.0.unwrap() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn baseless() { + let x0 = parse_number("0"); + let x1 = parse_number("1"); + let x2 = parse_number("1_00"); + let x3 = parse_number("10_000"); + + let x0: Value = (&x0).into(); + let x1: Value = (&x1).into(); + let x2: Value = (&x2).into(); + let x3: Value = (&x3).into(); + + assert_eq!(format!("{x0:x}"), "00000000"); + assert_eq!(format!("{x1:x}"), "00000001"); + assert_eq!(format!("{x2:x}"), "00000064"); + assert_eq!(format!("{x3:x}"), "00002710"); + } + + #[test] + fn based() { + let x0 = parse_number("16'b000011110101"); + let x1 = parse_number("16'b0x0X11z10Z01"); + let x2 = parse_number("24'o20701231"); + let x3 = parse_number("24'o11z173x1"); + let x4 = parse_number("32'd123456789"); + let x5 = parse_number("32'd987654321"); + let x6 = parse_number("32'h12a45f78"); + let x7 = parse_number("32'hfx7Z5X32"); + + let x0: Value = (&x0).into(); + let x1: Value = (&x1).into(); + let x2: Value = (&x2).into(); + let x3: Value = (&x3).into(); + let x4: Value = (&x4).into(); + let x5: Value = (&x5).into(); + let x6: Value = (&x6).into(); + let x7: Value = (&x7).into(); + + assert_eq!(format!("{x0:x}"), "00f5"); + assert_eq!(format!("{x1:x}"), "0xzz"); + assert_eq!(format!("{x2:x}"), "438299"); + assert_eq!(format!("{x3:x}"), "2zzexx"); + assert_eq!(format!("{x4:x}"), "075bcd15"); + assert_eq!(format!("{x5:x}"), "3ade68b1"); + assert_eq!(format!("{x6:x}"), "12a45f78"); + assert_eq!(format!("{x7:x}"), "fx7z5x32"); + } + + #[test] + fn widthless_based() { + let x0 = parse_number("'b000011110101"); + let x1 = parse_number("'b0x0X11z10Z01"); + let x2 = parse_number("'o20701231"); + let x3 = parse_number("'o11z173x1"); + let x4 = parse_number("'d123456789"); + let x5 = parse_number("'d987654321"); + let x6 = parse_number("'h12a45f78"); + let x7 = parse_number("'hfx7Z5X32"); + + let x0: Value = (&x0).into(); + let x1: Value = (&x1).into(); + let x2: Value = (&x2).into(); + let x3: Value = (&x3).into(); + let x4: Value = (&x4).into(); + let x5: Value = (&x5).into(); + let x6: Value = (&x6).into(); + let x7: Value = (&x7).into(); + + assert_eq!(format!("{x0:x}"), "f5"); + assert_eq!(format!("{x1:x}"), "xzz"); + assert_eq!(format!("{x2:x}"), "438299"); + assert_eq!(format!("{x3:x}"), "2zzexx"); + assert_eq!(format!("{x4:x}"), "75bcd15"); + assert_eq!(format!("{x5:x}"), "3ade68b1"); + assert_eq!(format!("{x6:x}"), "12a45f78"); + assert_eq!(format!("{x7:x}"), "fx7z5x32"); + } + + #[test] + fn all_bit() { + let x0 = parse_number("'0"); + let x1 = parse_number("'1"); + let x2 = parse_number("'x"); + let x3 = parse_number("'X"); + let x4 = parse_number("'z"); + let x5 = parse_number("'Z"); + + let x0: Value = (&x0).into(); + let x1: Value = (&x1).into(); + let x2: Value = (&x2).into(); + let x3: Value = (&x3).into(); + let x4: Value = (&x4).into(); + let x5: Value = (&x5).into(); + + assert_eq!(format!("{x0:x}"), "all 0"); + assert_eq!(format!("{x1:x}"), "all 1"); + assert_eq!(format!("{x2:x}"), "all x"); + assert_eq!(format!("{x3:x}"), "all x"); + assert_eq!(format!("{x4:x}"), "all z"); + assert_eq!(format!("{x5:x}"), "all z"); + } + + #[test] + fn unary() { + let x0 = parse_expression("+1"); + let x1 = parse_expression("-1"); + let x2 = parse_expression("!1"); + let x3 = parse_expression("~1"); + let x4 = parse_expression("&1"); + let x5 = parse_expression("|1"); + let x6 = parse_expression("^1"); + let x7 = parse_expression("~&1"); + let x8 = parse_expression("~|1"); + let x9 = parse_expression("~^1"); + + let x0: IrExpression = (&x0).into(); + let x1: IrExpression = (&x1).into(); + let x2: IrExpression = (&x2).into(); + let x3: IrExpression = (&x3).into(); + let x4: IrExpression = (&x4).into(); + let x5: IrExpression = (&x5).into(); + let x6: IrExpression = (&x6).into(); + let x7: IrExpression = (&x7).into(); + let x8: IrExpression = (&x8).into(); + let x9: IrExpression = (&x9).into(); + + assert_eq!(format!("{x0}"), "(+ 00000001)"); + assert_eq!(format!("{x1}"), "(- 00000001)"); + assert_eq!(format!("{x2}"), "(! 00000001)"); + assert_eq!(format!("{x3}"), "(~ 00000001)"); + assert_eq!(format!("{x4}"), "(& 00000001)"); + assert_eq!(format!("{x5}"), "(| 00000001)"); + assert_eq!(format!("{x6}"), "(^ 00000001)"); + assert_eq!(format!("{x7}"), "(~& 00000001)"); + assert_eq!(format!("{x8}"), "(~| 00000001)"); + assert_eq!(format!("{x9}"), "(~^ 00000001)"); + } + + #[test] + fn binary() { + let x00 = parse_expression("1 ** 1"); + let x01 = parse_expression("1 * 1"); + let x02 = parse_expression("1 / 1"); + let x03 = parse_expression("1 % 1"); + let x04 = parse_expression("1 + 1"); + let x05 = parse_expression("1 - 1"); + let x06 = parse_expression("1 << 1"); + let x07 = parse_expression("1 >> 1"); + let x08 = parse_expression("1 <<< 1"); + let x09 = parse_expression("1 >>> 1"); + let x10 = parse_expression("1 <: 1"); + let x11 = parse_expression("1 <= 1"); + let x12 = parse_expression("1 >: 1"); + let x13 = parse_expression("1 >= 1"); + let x14 = parse_expression("1 == 1"); + let x15 = parse_expression("1 != 1"); + let x16 = parse_expression("1 ==? 1"); + let x17 = parse_expression("1 !=? 1"); + let x18 = parse_expression("1 & 1"); + let x19 = parse_expression("1 ^ 1"); + let x20 = parse_expression("1 ~^ 1"); + let x21 = parse_expression("1 | 1"); + let x22 = parse_expression("1 && 1"); + let x23 = parse_expression("1 || 1"); + let x24 = parse_expression("1 ** 1 + 1 - 1 / 1 % 1"); + + let x00: IrExpression = (&x00).into(); + let x01: IrExpression = (&x01).into(); + let x02: IrExpression = (&x02).into(); + let x03: IrExpression = (&x03).into(); + let x04: IrExpression = (&x04).into(); + let x05: IrExpression = (&x05).into(); + let x06: IrExpression = (&x06).into(); + let x07: IrExpression = (&x07).into(); + let x08: IrExpression = (&x08).into(); + let x09: IrExpression = (&x09).into(); + let x10: IrExpression = (&x10).into(); + let x11: IrExpression = (&x11).into(); + let x12: IrExpression = (&x12).into(); + let x13: IrExpression = (&x13).into(); + let x14: IrExpression = (&x14).into(); + let x15: IrExpression = (&x15).into(); + let x16: IrExpression = (&x16).into(); + let x17: IrExpression = (&x17).into(); + let x18: IrExpression = (&x18).into(); + let x19: IrExpression = (&x19).into(); + let x20: IrExpression = (&x20).into(); + let x21: IrExpression = (&x21).into(); + let x22: IrExpression = (&x22).into(); + let x23: IrExpression = (&x23).into(); + let x24: IrExpression = (&x24).into(); + + assert_eq!(format!("{x00}"), "(00000001 ** 00000001)"); + assert_eq!(format!("{x01}"), "(00000001 * 00000001)"); + assert_eq!(format!("{x02}"), "(00000001 / 00000001)"); + assert_eq!(format!("{x03}"), "(00000001 % 00000001)"); + assert_eq!(format!("{x04}"), "(00000001 + 00000001)"); + assert_eq!(format!("{x05}"), "(00000001 - 00000001)"); + assert_eq!(format!("{x06}"), "(00000001 << 00000001)"); + assert_eq!(format!("{x07}"), "(00000001 >> 00000001)"); + assert_eq!(format!("{x08}"), "(00000001 <<< 00000001)"); + assert_eq!(format!("{x09}"), "(00000001 >>> 00000001)"); + assert_eq!(format!("{x10}"), "(00000001 <: 00000001)"); + assert_eq!(format!("{x11}"), "(00000001 <= 00000001)"); + assert_eq!(format!("{x12}"), "(00000001 >: 00000001)"); + assert_eq!(format!("{x13}"), "(00000001 >= 00000001)"); + assert_eq!(format!("{x14}"), "(00000001 == 00000001)"); + assert_eq!(format!("{x15}"), "(00000001 != 00000001)"); + assert_eq!(format!("{x16}"), "(00000001 ==? 00000001)"); + assert_eq!(format!("{x17}"), "(00000001 !=? 00000001)"); + assert_eq!(format!("{x18}"), "(00000001 & 00000001)"); + assert_eq!(format!("{x19}"), "(00000001 ^ 00000001)"); + assert_eq!(format!("{x20}"), "(00000001 ~^ 00000001)"); + assert_eq!(format!("{x21}"), "(00000001 | 00000001)"); + assert_eq!(format!("{x22}"), "(00000001 && 00000001)"); + assert_eq!(format!("{x23}"), "(00000001 || 00000001)"); + assert_eq!( + format!("{x24}"), + "(((00000001 ** 00000001) + 00000001) - ((00000001 / 00000001) % 00000001))" + ); + } + + #[test] + fn ternary() { + let x0 = parse_expression("if 1 ? 2 : 3"); + let x1 = parse_expression("if 1 ? 2 : if 3 ? 4 : 5"); + + let x0: IrExpression = (&x0).into(); + let x1: IrExpression = (&x1).into(); + + assert_eq!(format!("{x0}"), "(00000001 ? 00000002 : 00000003)"); + assert_eq!( + format!("{x1}"), + "(00000001 ? 00000002 : (00000003 ? 00000004 : 00000005))" + ); + } + + #[test] + fn boolean() { + let x0 = parse_expression("true"); + let x1 = parse_expression("false"); + + let x0: IrExpression = (&x0).into(); + let x1: IrExpression = (&x1).into(); + + assert_eq!(format!("{x0}"), "1"); + assert_eq!(format!("{x1}"), "0"); + } + + #[test] + fn paren() { + let x0 = parse_expression("(1 + 2) * 3"); + let x1 = parse_expression("1 + (2 * 3)"); + + let x0: IrExpression = (&x0).into(); + let x1: IrExpression = (&x1).into(); + + assert_eq!(format!("{x0}"), "((00000001 + 00000002) * 00000003)"); + assert_eq!(format!("{x1}"), "(00000001 + (00000002 * 00000003))"); + } + + #[test] + fn concatenation() { + let x0 = parse_expression("{1, 2, 3}"); + let x1 = parse_expression("{1 repeat 2, 2, 3 repeat 4}"); + + let x0: IrExpression = (&x0).into(); + let x1: IrExpression = (&x1).into(); + + assert_eq!(format!("{x0}"), "{00000001, 00000002, 00000003}"); + assert_eq!( + format!("{x1}"), + "{00000001 repeat 00000002, 00000002, 00000003 repeat 00000004}" + ); + } + + #[test] + fn case_expression() { + let x0 = parse_expression("case 10 {0: 1, 1: 2, default: 3}"); + let x1 = parse_expression("case 10 {0..=2: 1, 4..5: 2, default: 3}"); + + let x0: IrExpression = (&x0).into(); + let x1: IrExpression = (&x1).into(); + + assert_eq!( + format!("{x0}"), + "((0000000a ==? 00000000) ? 00000001 : ((0000000a ==? 00000001) ? 00000002 : 00000003))" + ); + assert_eq!( + format!("{x1}"), + "(((00000000 <= 0000000a) && (0000000a <= 00000002)) ? 00000001 : (((00000004 <= 0000000a) && (0000000a <: 00000005)) ? 00000002 : 00000003))" + ); + } + + #[test] + fn switch_expression() { + let x0 = parse_expression("switch {0 == 1: 2, 1 <: 2: 2, default: 3}"); + + let x0: IrExpression = (&x0).into(); + + assert_eq!( + format!("{x0}"), + "((00000000 == 00000001) ? 00000002 : ((00000001 <: 00000002) ? 00000002 : 00000003))" + ); + } +} diff --git a/crates/ir/src/declaration.rs b/crates/ir/src/declaration.rs new file mode 100644 index 00000000..e70379c3 --- /dev/null +++ b/crates/ir/src/declaration.rs @@ -0,0 +1,75 @@ +use crate::module::Module; +use crate::statement::Statement; +use crate::variable::VarId; +use std::fmt; + +#[derive(Clone)] +pub enum Declaration { + Comb(CombDeclaration), + Ff(FfDeclaration), + Inst(InstDeclaration), +} + +impl fmt::Display for Declaration { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Declaration::Comb(x) => x.fmt(f), + Declaration::Ff(x) => x.fmt(f), + Declaration::Inst(x) => x.fmt(f), + } + } +} + +#[derive(Clone)] +pub struct CombDeclaration { + pub statements: Vec, +} + +impl fmt::Display for CombDeclaration { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut ret = "comb {\n".to_string(); + + for x in &self.statements { + ret.push_str(&format!("{}\n", x)); + } + + ret.push('}'); + ret.fmt(f) + } +} + +#[derive(Clone)] +pub struct FfDeclaration { + pub clock: VarId, + pub reset: VarId, + pub statements: Vec, +} + +impl fmt::Display for FfDeclaration { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut ret = format!("ff ({}, {}) {{\n", self.clock, self.reset); + + for x in &self.statements { + ret.push_str(&format!("{}\n", x)); + } + + ret.push('}'); + ret.fmt(f) + } +} + +#[derive(Clone)] +pub struct InstDeclaration { + pub module: Module, +} + +impl fmt::Display for InstDeclaration { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut ret = "inst {\n".to_string(); + + ret.push_str(&format!("{}\n", self.module)); + + ret.push('}'); + ret.fmt(f) + } +} diff --git a/crates/ir/src/expression.rs b/crates/ir/src/expression.rs new file mode 100644 index 00000000..fde6e1b8 --- /dev/null +++ b/crates/ir/src/expression.rs @@ -0,0 +1,931 @@ +use crate::bigint::{gen_mask, to_biguint}; +use crate::variable::{Value, VarId, Variable}; +use num_bigint::{BigInt, BigUint}; +use num_traits::{CheckedSub, ToPrimitive}; +use std::collections::HashMap; +use std::fmt; +use veryl_parser::veryl_grammar_trait::ExpressionIdentifier; + +#[derive(Clone, Debug)] +pub enum Expression { + Term(Factor), + Unary(Op, Box), + Binary(Box, Op, Box), + Ternary(Box, Box, Box), + Concatenation(Vec<(Expression, Option)>), +} + +impl Expression { + pub fn resolve(&mut self, func: F) + where + F: Fn(&ExpressionIdentifier) -> Factor, + { + match self { + Expression::Term(x) => x.resolve(func), + Expression::Unary(_, x) => x.resolve(func), + Expression::Binary(x, _, y) => { + x.resolve(&func); + y.resolve(&func); + } + Expression::Ternary(x, y, z) => { + x.resolve(&func); + y.resolve(&func); + z.resolve(&func); + } + Expression::Concatenation(x) => { + for (x, y) in x { + x.resolve(&func); + if let Some(y) = y { + y.resolve(&func); + } + } + } + } + } +} + +impl fmt::Display for Expression { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let ret = match self { + Expression::Term(x) => x.to_string(), + Expression::Unary(x, y) => { + format!("({x} {y})") + } + Expression::Binary(x, y, z) => { + format!("({x} {y} {z})") + } + Expression::Ternary(x, y, z) => { + format!("({x} ? {y} : {z})") + } + Expression::Concatenation(x) => { + let mut ret = String::new(); + for (x, y) in x.iter() { + if let Some(y) = y { + ret = format!("{ret}, {x} repeat {y}") + } else { + ret = format!("{ret}, {x}") + } + } + format!("{{{}}}", &ret[2..]) + } + }; + + ret.fmt(f) + } +} + +impl Expression { + pub fn eval(&self, context_width: Option, map: &HashMap) -> Value { + match self { + Expression::Term(x) => match x { + Factor::Variable(x, y) => { + let value = map.get(x).unwrap().value.clone(); + if let Some(y) = y { + let beg = y.beg.eval(context_width, map); + let end = if let Some(end) = &y.end { + end.eval(context_width, map) + } else { + beg.clone() + }; + value.select(beg, end) + } else { + value + } + } + Factor::Value(x) => x.clone(), + // TODO + Factor::Unresolved(_) => Value::new_x(0, false), + // TODO + Factor::Unknown => Value::new_x(0, false), + }, + Expression::Unary(op, x) => { + let mut ret = x.eval(context_width, map); + match op { + Op::BitAnd => reduction(ret, |x, y| x & y), + Op::BitOr => reduction(ret, |x, y| x | y), + Op::BitXor => reduction(ret, |x, y| x ^ y), + Op::BitXnor => { + let mut ret = reduction(ret, |x, y| x ^ y); + ret.payload = (ret.payload == 0u32.into()).into(); + ret + } + Op::BitNand => { + let mut ret = reduction(ret, |x, y| x & y); + ret.payload = (ret.payload == 0u32.into()).into(); + ret + } + Op::BitNor => { + let mut ret = reduction(ret, |x, y| x | y); + ret.payload = (ret.payload == 0u32.into()).into(); + ret + } + Op::BitNot => { + for i in 0..ret.width { + let i = i as u64; + ret.payload.set_bit(i, !ret.payload.bit(i)); + if ret.mask_x.bit(i) | ret.mask_z.bit(i) { + ret.mask_x.set_bit(i, true); + } + } + ret + } + Op::LogicNot => { + ret.payload = (ret.payload == 0u32.into()).into(); + ret.width = 1; + ret.signed = false; + ret + } + Op::Add => ret, + Op::Sub => { + ret.payload = BigUint::from_slice( + &ret.payload + .to_u32_digits() + .iter() + .map(|x| !x) + .collect::>(), + ); + ret.payload += BigUint::from(1u32); + ret + } + _ => unreachable!(), + } + } + Expression::Binary(x, op, y) => { + let x = x.eval(context_width, map); + let y = y.eval(context_width, map); + match op { + Op::Pow => binary_op_signed( + x, + y, + context_width, + |x, _, z| x.max(z.unwrap_or(0)), + |x, y| x.pow(y.to_u32().unwrap()), + |x, y| x & y, + ), + Op::Div => binary_op_signed( + x, + y, + context_width, + |x, y, z| x.max(y).max(z.unwrap_or(0)), + |x, y| x / y, + |x, y| x & y, + ), + Op::Rem => binary_op_signed( + x, + y, + context_width, + |x, y, z| x.max(y).max(z.unwrap_or(0)), + |x, y| x % y, + |x, y| x & y, + ), + Op::Mul => binary_op_signed( + x, + y, + context_width, + |x, y, z| x.max(y).max(z.unwrap_or(0)), + |x, y| x * y, + |x, y| x & y, + ), + Op::Add => binary_op( + x, + y, + context_width, + |x, y, z| x.max(y).max(z.unwrap_or(0)), + |x, y| x + y, + |x, y| x & y, + ), + Op::Sub => binary_op( + x, + y, + context_width, + |x, y, z| x.max(y).max(z.unwrap_or(0)), + |x, y| x.checked_sub(&y).unwrap_or(0u32.into()), + |x, y| x & y, + ), + Op::ArithShiftL => binary_op( + x, + y, + context_width, + |x, _, z| x.max(z.unwrap_or(0)), + |x, y| x << y.to_u32().unwrap(), + |x, y| x & y, + ), + Op::ArithShiftR => todo!(), + Op::LogicShiftL => binary_op( + x, + y, + context_width, + |x, _, z| x.max(z.unwrap_or(0)), + |x, y| x << y.to_u32().unwrap(), + |x, y| x & y, + ), + Op::LogicShiftR => binary_op( + x, + y, + context_width, + |x, _, z| x.max(z.unwrap_or(0)), + |x, y| x >> y.to_u32().unwrap(), + |x, y| x & y, + ), + Op::LessEq => binary_op( + x, + y, + context_width, + |_, _, _| 1, + |x, y| (x <= y).into(), + |_, _| false, + ), + Op::GreaterEq => binary_op( + x, + y, + context_width, + |_, _, _| 1, + |x, y| (x >= y).into(), + |_, _| false, + ), + Op::Less => binary_op( + x, + y, + context_width, + |_, _, _| 1, + |x, y| (x < y).into(), + |_, _| false, + ), + Op::Greater => binary_op( + x, + y, + context_width, + |_, _, _| 1, + |x, y| (x > y).into(), + |_, _| false, + ), + Op::Eq => binary_op( + x, + y, + context_width, + |_, _, _| 1, + |x, y| (x == y).into(), + |_, _| false, + ), + Op::EqWildcard => { + let width = x.width.max(y.width); + let mut ret = true; + for i in 0..width { + let i = i as u64; + let x_bit = x.payload.bit(i); + let y_bit = y.payload.bit(i); + if !y.mask_x.bit(i) && !y.mask_z.bit(i) { + ret = ret && (x_bit == y_bit); + } + } + Value { + payload: ret.into(), + mask_x: 0u32.into(), + mask_z: 0u32.into(), + width: 1, + signed: false, + } + } + Op::Ne => binary_op( + x, + y, + context_width, + |_, _, _| 1, + |x, y| (x != y).into(), + |_, _| false, + ), + Op::NeWildcard => { + let width = x.width.max(y.width); + let mut ret = false; + for i in 0..width { + let i = i as u64; + let x_bit = x.payload.bit(i); + let y_bit = y.payload.bit(i); + if !y.mask_x.bit(i) && !y.mask_z.bit(i) { + ret = ret || (x_bit != y_bit); + } + } + Value { + payload: ret.into(), + mask_x: 0u32.into(), + mask_z: 0u32.into(), + width: 1, + signed: false, + } + } + Op::LogicAnd => binary_op( + x, + y, + context_width, + |_, _, _| 1, + |x, y| ((x != 0u32.into()) & (y != 0u32.into())).into(), + |x, y| x & y, + ), + Op::LogicOr => binary_op( + x, + y, + context_width, + |_, _, _| 1, + |x, y| ((x != 0u32.into()) | (y != 0u32.into())).into(), + |x, y| x & y, + ), + Op::BitAnd => binary_op( + x, + y, + context_width, + |x, y, z| x.max(y).max(z.unwrap_or(0)), + |x, y| x & y, + |x, y| x & y, + ), + Op::BitOr => binary_op( + x, + y, + context_width, + |x, y, z| x.max(y).max(z.unwrap_or(0)), + |x, y| x | y, + |x, y| x & y, + ), + Op::BitXor => binary_op( + x, + y, + context_width, + |x, y, z| x.max(y).max(z.unwrap_or(0)), + |x, y| x ^ y, + |x, y| x & y, + ), + Op::BitXnor => { + let mut ret = binary_op( + x, + y, + context_width, + |x, y, z| x.max(y).max(z.unwrap_or(0)), + |x, y| x ^ y, + |x, y| x & y, + ); + for i in 0..ret.width { + let i = i as u64; + ret.payload.set_bit(i, !ret.payload.bit(i)); + if ret.mask_x.bit(i) | ret.mask_z.bit(i) { + ret.mask_x.set_bit(i, true); + } + } + ret + } + Op::As => Value::new_x(0, false), + _ => unreachable!(), + } + } + Expression::Ternary(x, y, z) => { + let x = x.eval(context_width, map); + let y = y.eval(context_width, map); + let z = z.eval(context_width, map); + let width = y.width.max(z.width); + + let mut ret = if x.payload == 0u32.into() { z } else { y }; + ret.width = width; + ret + } + Expression::Concatenation(x) => { + let mut payload = BigUint::from(0u32); + let mut mask_x = BigUint::from(0u32); + let mut mask_z = BigUint::from(0u32); + let mut width = 0; + for (exp, rep) in x.iter() { + let exp = exp.eval(context_width, map); + + let rep = if let Some(rep) = rep { + let rep = rep.eval(context_width, map); + rep.payload.to_usize().unwrap() + } else { + 1 + }; + + for _ in 0..rep { + payload <<= exp.width; + mask_x <<= exp.width; + mask_z <<= exp.width; + + payload |= exp.payload.clone(); + mask_x |= exp.mask_x.clone(); + mask_z |= exp.mask_z.clone(); + + width += exp.width; + } + } + Value { + payload, + mask_x, + mask_z, + width, + signed: false, + } + } + } + } +} + +fn reduction BigUint>(value: Value, func: T) -> Value { + let mask_x = if value.is_x() | value.is_z() { + 1u32 + } else { + 0u32 + } + .into(); + + let mut tmp = value.payload; + let mut payload = tmp.clone() & BigUint::from(1u32); + for _ in 0..value.width - 1 { + tmp >>= 1; + payload = func(payload, tmp.clone() & BigUint::from(1u32)); + } + + Value { + payload, + mask_x, + mask_z: 0u32.into(), + width: 1, + signed: false, + } +} + +fn binary_op< + T: Fn(usize, usize, Option) -> usize, + U: Fn(BigUint, BigUint) -> BigUint, + V: Fn(bool, bool) -> bool, +>( + x: Value, + y: Value, + context_width: Option, + calc_width: T, + calc_value: U, + calc_signed: V, +) -> Value { + let width = calc_width(x.width, y.width, context_width); + let mask = gen_mask(width); + + let mask_x = if x.is_x() | y.is_x() | x.is_z() | y.is_z() { + mask.clone() + } else { + BigUint::from(0u32) + }; + + let payload = calc_value(x.payload, y.payload) & mask; + let signed = calc_signed(x.signed, y.signed); + + Value { + payload, + mask_x, + mask_z: 0u32.into(), + width, + signed, + } +} + +fn binary_op_signed< + T: Fn(usize, usize, Option) -> usize, + U: Fn(BigInt, BigInt) -> BigInt, + V: Fn(bool, bool) -> bool, +>( + x: Value, + y: Value, + context_width: Option, + calc_width: T, + calc_value: U, + calc_signed: V, +) -> Value { + let width = calc_width(x.width, y.width, context_width); + let mask = gen_mask(width); + + let mask_x = if x.is_x() | y.is_x() | x.is_z() | y.is_z() { + mask.clone() + } else { + BigUint::from(0u32) + }; + + let x_payload = x.to_bigint(); + let y_payload = y.to_bigint(); + + let payload = to_biguint(calc_value(x_payload, y_payload), width) & mask; + let signed = calc_signed(x.signed, y.signed); + + Value { + payload, + mask_x, + mask_z: 0u32.into(), + width, + signed, + } +} + +#[derive(Clone, Debug)] +pub enum Factor { + Variable(VarId, Option