diff --git a/examples/alignof.c b/examples/alignof.c index 6e12fb7..5e36459 100644 --- a/examples/alignof.c +++ b/examples/alignof.c @@ -1,3 +1,3 @@ int main() { - return _Alignof(const int); + return _Alignof(const int) == 4; } diff --git a/examples/bar.c b/examples/bar.c index 140aad2..4cd8b0b 100644 --- a/examples/bar.c +++ b/examples/bar.c @@ -4,3 +4,7 @@ int bar(int x, int y, int z){ if (x == y) { return y; } else { return z; } } + +int main() { + return 1; +} diff --git a/examples/comma.c b/examples/comma.c index ddb618c..294bf93 100644 --- a/examples/comma.c +++ b/examples/comma.c @@ -2,5 +2,5 @@ int main() { int y = 2; int x = (y += 2, 2, y + 3); - return x; + return x == 7; } diff --git a/examples/cond.c b/examples/cond.c index 900be5e..e12f409 100644 --- a/examples/cond.c +++ b/examples/cond.c @@ -2,5 +2,5 @@ int main() { int y = 1; int x = 0; - return (x == y) ? 2 : 5; + return ((x == y) ? 2 : 5) == 5; } diff --git a/examples/fib2.c b/examples/fib2.c index 61f1d78..94b0cda 100644 --- a/examples/fib2.c +++ b/examples/fib2.c @@ -5,3 +5,7 @@ int (fibonacci)(int n) { return fibonacci(n - 2) + fibonacci(n - 1); } + +int main() { + return fibonacci(9) == 34; +} diff --git a/examples/fib3.c b/examples/fib3.c index a2aa1f7..c2d2b14 100644 --- a/examples/fib3.c +++ b/examples/fib3.c @@ -16,5 +16,5 @@ int fibonacci(int n) { } int main() { - return fibonacci(9); + return fibonacci(9) == 34; } diff --git a/examples/fib4.c b/examples/fib4.c index ecd45ed..9186084 100644 --- a/examples/fib4.c +++ b/examples/fib4.c @@ -18,5 +18,5 @@ int fibonacci(int n) { } int main() { - return fibonacci(9); + return fibonacci(9) == 34; } diff --git a/examples/fib5.c b/examples/fib5.c index 534c526..08b4546 100644 --- a/examples/fib5.c +++ b/examples/fib5.c @@ -18,5 +18,5 @@ int fibonacci(int n) { } int main() { - return fibonacci(9); + return fibonacci(9) == 34; } diff --git a/examples/fibonacci.c b/examples/fibonacci.c index f0767de..a65fe3a 100644 --- a/examples/fibonacci.c +++ b/examples/fibonacci.c @@ -7,5 +7,5 @@ int fibonacci(int n) { } int main() { - return fibonacci(9); + return fibonacci(9) == 34; } diff --git a/examples/foo.c b/examples/foo.c index b831a1a..879caed 100644 --- a/examples/foo.c +++ b/examples/foo.c @@ -4,5 +4,5 @@ int foo(int x, int y, int z){ } int main() { - return foo(0, 1, -1); + return foo(0, 1, -1) == -1; } diff --git a/examples/foo2.c b/examples/foo2.c index 801ffdd..150600b 100644 --- a/examples/foo2.c +++ b/examples/foo2.c @@ -5,5 +5,5 @@ int main() { int k = 0; } - return 0; + return 1; } diff --git a/examples/foo3.c b/examples/foo3.c index a5ebf07..1392714 100644 --- a/examples/foo3.c +++ b/examples/foo3.c @@ -5,7 +5,7 @@ int foo(int, int k); int main() { int i = g; - return foo(i, i); + return foo(i, i) == 30; } int foo(int i, int j) { diff --git a/examples/foo4.c b/examples/foo4.c index c690400..bbe4a38 100644 --- a/examples/foo4.c +++ b/examples/foo4.c @@ -11,5 +11,5 @@ int (* (* foo3())())(int, int, int){ } int main() { - return foo3()()(2, 2, 2); + return foo3()()(2, 2, 2) == 6; } diff --git a/examples/for_continue_break.c b/examples/for_continue_break.c new file mode 100644 index 0000000..f15b59a --- /dev/null +++ b/examples/for_continue_break.c @@ -0,0 +1,19 @@ +int foo() { + int sum = 0; + + for(int i = 0; ;) { + if(i == 5) break; + if(i == 3) { + i++; + continue; + } + sum += i; + i++; + } + + return sum; +} + +int main() { + return foo() == 7; +} diff --git a/examples/temp2.c b/examples/hw1/temp2.c similarity index 100% rename from examples/temp2.c rename to examples/hw1/temp2.c diff --git a/examples/negate.c b/examples/negate.c index 25356be..d38f42d 100644 --- a/examples/negate.c +++ b/examples/negate.c @@ -4,5 +4,5 @@ int foo(int x, int y, int z){ } int main() { - return foo(0, 1, -1); + return foo(0, 1, -1) == 1; } diff --git a/examples/pointer.c b/examples/pointer.c index 39067cd..21bebce 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -11,5 +11,5 @@ int main(){ *&*foo(*p2) += 1; *foo(p3) += 1; - return a; + return a == 3; } diff --git a/examples/return_void.c b/examples/return_void.c index 93f284c..fc64e3d 100644 --- a/examples/return_void.c +++ b/examples/return_void.c @@ -3,5 +3,5 @@ void foo() { int main() { foo(); - return 0; + return 1; } diff --git a/examples/simple.c b/examples/simple.c index a382e8e..29fc1ed 100644 --- a/examples/simple.c +++ b/examples/simple.c @@ -1,4 +1,5 @@ int main() { int x = 1; + return 1; } diff --git a/examples/simple_for.c b/examples/simple_for.c index 552fd1a..6073bcc 100644 --- a/examples/simple_for.c +++ b/examples/simple_for.c @@ -5,5 +5,5 @@ int main() for (i = 0; i < 11; ++i) { sum += i; } - return sum; + return sum == 55; } diff --git a/examples/simple_if.c b/examples/simple_if.c index 4429714..46dd19a 100644 --- a/examples/simple_if.c +++ b/examples/simple_if.c @@ -5,3 +5,7 @@ int (fibonacci)(int n) { return fibonacci(n - 2) + fibonacci(n - 1); } + +int main() { + return 1; +} diff --git a/examples/sizeof.c b/examples/sizeof.c index 2520d24..155c77f 100644 --- a/examples/sizeof.c +++ b/examples/sizeof.c @@ -1,3 +1,3 @@ int main() { - return sizeof(const int); + return sizeof(const int) == 4; } diff --git a/examples/switch.c b/examples/switch.c index e0d2209..8f4164c 100644 --- a/examples/switch.c +++ b/examples/switch.c @@ -16,5 +16,5 @@ int main() { } } - return b; + return b == 2; } diff --git a/examples/temp.c b/examples/temp.c index 6acc0f9..fcc114c 100644 --- a/examples/temp.c +++ b/examples/temp.c @@ -3,3 +3,7 @@ int fibonacci(int n) { return n; } } + +int main() { + return 1; +} diff --git a/examples/while_continue_break.c b/examples/while_continue_break.c new file mode 100644 index 0000000..6e51fb3 --- /dev/null +++ b/examples/while_continue_break.c @@ -0,0 +1,21 @@ +int foo() { + int sum = 0; + int i = 0; + + while(i < 10) { + if(i == 3) { + i++; + continue; + } + sum += i; + i++; + + if(i == 5) break; + } + + return sum; +} + +int main() { + return foo() == 7; +} diff --git a/src/ir.rs b/src/ir.rs index bb8e052..8ac9a1f 100644 --- a/src/ir.rs +++ b/src/ir.rs @@ -1058,7 +1058,7 @@ impl HasDtype for Instruction { } } -#[derive(Debug, PartialEq, Eq, Hash, Clone)] +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] pub struct BlockId(pub usize); impl fmt::Display for BlockId { diff --git a/src/run_ir.rs b/src/run_ir.rs index 511b96c..eb3b786 100644 --- a/src/run_ir.rs +++ b/src/run_ir.rs @@ -78,7 +78,7 @@ pub enum InterpreterError { display = "{}:{}:{} / Undef value cannot be used as an operand", func_name, bid, iid )] - Undef { + Misc { func_name: String, bid: BlockId, iid: usize, @@ -198,6 +198,9 @@ mod calculator { (ast::BinaryOperator::Less, Value::Int(lhs), Value::Int(rhs)) => { Ok(Value::Bool(lhs < rhs)) } + (ast::BinaryOperator::GreaterOrEqual, Value::Int(lhs), Value::Int(rhs)) => { + Ok(Value::Bool(lhs >= rhs)) + } _ => todo!(), } } @@ -214,6 +217,16 @@ mod calculator { _ => todo!(), } } + + pub fn calculate_typecast(value: &Value, dtype: &crate::ir::Dtype) -> Result { + match (value, dtype) { + (Value::Int(_), crate::ir::Dtype::Int { .. }) => Ok(value.clone()), + (Value::Bool(b), crate::ir::Dtype::Int { .. }) => { + Ok(Value::Int(if *b { 1 } else { 0 })) + } + _ => todo!("calculate_typecast ({:?}) {:?}", dtype, value), + } + } } // TODO: allocation fields will be added in the future @@ -250,7 +263,7 @@ impl<'i> State<'i> { // Create State let mut state = State { global_map: GlobalMap::default(), - stack_frame: StackFrame::new(func_def.bid_init.clone(), func_name, func_def), + stack_frame: StackFrame::new(func_def.bid_init, func_name, func_def), stack: Vec::new(), memory: Vec::new(), ir, @@ -351,7 +364,7 @@ impl<'i> State<'i> { .stack_frame .func_def .blocks - .get(&self.stack_frame.pc.bid.clone()) + .get(&self.stack_frame.pc.bid) .expect("block matched with `bid` must be exist"); if block.instructions.len() == self.stack_frame.pc.iid { @@ -378,8 +391,7 @@ impl<'i> State<'i> { self.stack_frame = prev_stack_frame; // create temporary register to write return value - let register = - RegisterId::temp(self.stack_frame.pc.bid.clone(), self.stack_frame.pc.iid); + let register = RegisterId::temp(self.stack_frame.pc.bid, self.stack_frame.pc.iid); self.register_write(register, value); self.stack_frame.pc.increment(); } @@ -392,7 +404,7 @@ impl<'i> State<'i> { ) -> Result, InterpreterError> { match block_exit { BlockExit::Jump { bid } => { - self.stack_frame.pc = Pc::new(bid.clone()); + self.stack_frame.pc = Pc::new(*bid); Ok(None) } BlockExit::ConditionalJump { @@ -403,11 +415,7 @@ impl<'i> State<'i> { let value = self.get_value(condition.clone())?; let value = value.get_bool().expect("`condition` must be `Value::Bool`"); - self.stack_frame.pc = Pc::new(if value { - bid_then.clone() - } else { - bid_else.clone() - }); + self.stack_frame.pc = Pc::new(if value { *bid_then } else { *bid_else }); Ok(None) } BlockExit::Switch { @@ -421,10 +429,10 @@ impl<'i> State<'i> { let bid_next = cases .iter() .find(|(c, _)| value == self.constant_to_value(c.clone())) - .map(|(_, bid)| bid.clone()) - .unwrap_or_else(|| default.clone()); + .map(|(_, bid)| bid) + .unwrap_or_else(|| default); - self.stack_frame.pc = Pc::new(bid_next); + self.stack_frame.pc = Pc::new(*bid_next); Ok(None) } @@ -443,9 +451,9 @@ impl<'i> State<'i> { let rhs = self.get_value(rhs.clone())?; calculator::calculate_binary_operator_expression(&op, lhs, rhs).map_err(|_| { - InterpreterError::Undef { + InterpreterError::Misc { func_name: self.stack_frame.func_name.clone(), - bid: self.stack_frame.pc.bid.clone(), + bid: self.stack_frame.pc.bid, iid: self.stack_frame.pc.iid, } })? @@ -454,9 +462,9 @@ impl<'i> State<'i> { let operand = self.get_value(operand.clone())?; calculator::calculate_unary_operator_expression(&op, operand).map_err(|_| { - InterpreterError::Undef { + InterpreterError::Misc { func_name: self.stack_frame.func_name.clone(), - bid: self.stack_frame.pc.bid.clone(), + bid: self.stack_frame.pc.bid, iid: self.stack_frame.pc.iid, } })? @@ -502,7 +510,7 @@ impl<'i> State<'i> { let args = self.preprocess_args(func_signature, args)?; - let stack_frame = StackFrame::new(func_def.bid_init.clone(), callee_name, func_def); + let stack_frame = StackFrame::new(func_def.bid_init, callee_name, func_def); let prev_stack_frame = mem::replace(&mut self.stack_frame, stack_frame); self.stack.push(prev_stack_frame); @@ -512,10 +520,22 @@ impl<'i> State<'i> { return Ok(None); } - _ => todo!("{:?} will be supported in the future", instruction), + Instruction::TypeCast { + value, + target_dtype, + } => { + let value = self.get_value(value.clone())?; + calculator::calculate_typecast(&value, target_dtype).map_err(|_| { + InterpreterError::Misc { + func_name: self.stack_frame.func_name.clone(), + bid: self.stack_frame.pc.bid, + iid: self.stack_frame.pc.iid, + } + })? + } }; - let register = RegisterId::temp(self.stack_frame.pc.bid.clone(), self.stack_frame.pc.iid); + let register = RegisterId::temp(self.stack_frame.pc.bid, self.stack_frame.pc.iid); self.register_write(register, result); self.stack_frame.pc.increment(); diff --git a/src/write_ir.rs b/src/write_ir.rs index dd2937a..51151c5 100644 --- a/src/write_ir.rs +++ b/src/write_ir.rs @@ -104,7 +104,7 @@ impl WriteLine for (&BlockId, &Block) { writeln!( write, "{}:{} = {}", - RegisterId::temp(self.0.clone(), i), + RegisterId::temp(*self.0, i), instr.dtype(), instr.write_string() )?; diff --git a/tests/ast_printer_test.rs b/tests/ast_printer_test.rs deleted file mode 100644 index e071c68..0000000 --- a/tests/ast_printer_test.rs +++ /dev/null @@ -1,21 +0,0 @@ -use std::path::Path; - -use kecc::*; - -#[test] -fn ast_printer_test() { - let mut parse = Parse::default(); - let dir_path = Path::new("examples/"); - let dir = dir_path.read_dir().expect("read_dir call failed"); - for entry in dir { - let test_file = ok_or!(entry, continue); - let test_unit = parse.translate(&test_file.path().as_path()).expect( - &format!( - "parse failed {:?}", - test_file.path().into_os_string().to_str().unwrap() - ) - .to_owned(), - ); - write_c_test(&test_unit); - } -} diff --git a/tests/fuzz.py b/tests/fuzz.py index d5f7c21..da9ff98 100644 --- a/tests/fuzz.py +++ b/tests/fuzz.py @@ -22,6 +22,7 @@ REPLACE_DICT = { "int16_t": "int", "int32_t": "int", "uint": "unsigned int", + "static ": "", } CSMITH_DIR = "csmith-2.3.0" @@ -44,7 +45,12 @@ def generate(tests_dir, bin_file, runtime, file_name): A developer may customize the options to meet one's needs for testing. """ global CSMITH_DIR - options = ["--no-builtins", "--no-safe-math", "--no-unions"] + options = [ + "--no-argc", "--no-arrays", "--no-checksum", + "--no-jumps", "--no-longlong", "--no-int8", + "--no-uint8", "--no-safe-math", "--no-pointers", + "--no-structs", "--no-unions", "--no-builtins" + ] args = [bin_file] + options dst_path = os.path.join(runtime, file_name) diff --git a/tests/ir_test.rs b/tests/ir_test.rs deleted file mode 100644 index 2b63e94..0000000 --- a/tests/ir_test.rs +++ /dev/null @@ -1,68 +0,0 @@ -use kecc::run_ir::*; -use kecc::*; -use std::path::Path; - -// TODO: cover all examples in the future -#[test] -fn ir_interpreter_test() { - // Test toy example - assert_eq!(run_example("examples/foo.c"), Ok(Value::Int(-1))); - - // Test toy example with negate unary operator - assert_eq!(run_example("examples/negate.c"), Ok(Value::Int(1))); - - // Test fibonacci function with for-loop - assert_eq!(run_example("examples/fib3.c"), Ok(Value::Int(34))); - - // Test fibonacci function with while-loop - assert_eq!(run_example("examples/fib4.c"), Ok(Value::Int(34))); - - // Test fibonacci function with do-while-loop - assert_eq!(run_example("examples/fib5.c"), Ok(Value::Int(34))); - - // Test fibonacci function with recursive function call - assert_eq!(run_example("examples/fibonacci.c"), Ok(Value::Int(34))); - - // Test example with global variable - assert_eq!(run_example("examples/foo3.c"), Ok(Value::Int(30))); - - // Test example with comma expressions - assert_eq!(run_example("examples/comma.c"), Ok(Value::Int(7))); - - // Test example with complex function call - assert_eq!(run_example("examples/foo4.c"), Ok(Value::Int(6))); - - // Test example with pointer - assert_eq!(run_example("examples/pointer.c"), Ok(Value::Int(3))); - - // Test example with sizeof - assert_eq!(run_example("examples/sizeof.c"), Ok(Value::Int(4))); - - // Test example with alignof - assert_eq!(run_example("examples/alignof.c"), Ok(Value::Int(4))); - - // Test example with simple for statement - assert_eq!(run_example("examples/simple_for.c"), Ok(Value::Int(55))); - - // Test example with conditional expression - assert_eq!(run_example("examples/cond.c"), Ok(Value::Int(5))); - - // Test example with switch statement - assert_eq!(run_example("examples/switch.c"), Ok(Value::Int(2))); -} - -fn run_example(example_path: &str) -> Result { - let example_path = Path::new(example_path); - let unit = Parse::default() - .translate(&example_path) - .expect("parse failed"); - let ir = Irgen::default() - .translate(&unit) - .expect("failed to generate ir"); - - // TODO: consider command line arguments in the future - // TODO: randomly generate argument values - let args = Vec::new(); - - run_ir(&ir, args) -} diff --git a/tests/test_examples.rs b/tests/test_examples.rs new file mode 100644 index 0000000..1e5d98d --- /dev/null +++ b/tests/test_examples.rs @@ -0,0 +1,47 @@ +use std::path::Path; + +use lang_c::ast::*; + +use kecc::run_ir::*; +use kecc::*; + +fn test_dir(path: &Path, f: F) +where + F: Fn(&TranslationUnit), +{ + let mut parse = Parse::default(); + let dir = path.read_dir().expect("read_dir call failed"); + for entry in dir { + let entry = ok_or!(entry, continue); + let path = entry.path(); + if path.is_dir() { + continue; + } + + println!("[testing {:?}]", path); + let test_unit = parse.translate(&path.as_path()).expect( + &format!("parse failed {:?}", path.into_os_string().to_str().unwrap()).to_owned(), + ); + f(&test_unit); + } +} + +#[test] +fn test_examples_write_c() { + test_dir(Path::new("examples/"), write_c_test); + test_dir(Path::new("examples/hw1"), write_c_test); +} + +#[test] +fn test_examples_irgen() { + test_dir(Path::new("examples/"), |test_unit| { + let ir = Irgen::default() + .translate(test_unit) + .expect("failed to generate ir"); + + // TODO: insert randomly generated command line arguments + let args = Vec::new(); + + assert_eq!(run_ir(&ir, args), Ok(Value::Int(1))); + }); +}