From 8938a7ad8ff86f1f6f46bbe765794eadd2aaf762 Mon Sep 17 00:00:00 2001 From: Jeehoon Kang Date: Thu, 26 Mar 2020 03:38:20 +0900 Subject: [PATCH] Update homework 1 and 2 --- README.md | 34 +- bin/fuzz.rs | 8 +- bin/fuzz_cli.yml | 4 + bin/kecc.rs | 10 +- examples/.gitignore | 1 + examples/hw1/complete_cond.c | 3205 +++++++++++++++++++ examples/hw1/cond_and_loop.c | 13 + examples/hw1/gcd.c | 15 + examples/meta/make_cond.py | 53 + examples/simple_cond.c | 10 + scripts/copy-to-kecc-public.sh | 3 + scripts/make-public.py | 9 +- src/{asm.rs => asm/mod.rs} | 2 + src/asm/write_asm.rs | 10 + src/{codegen.rs => asmgen/mod.rs} | 6 +- src/{assert_ast_equiv.rs => c/ast_equiv.rs} | 2 +- src/c/mod.rs | 6 + src/{ => c}/parse.rs | 30 +- src/{ => c}/write_c.rs | 6 +- src/ir.rs | 1096 ------- src/ir/dtype.rs | 612 ++++ src/{run_ir.rs => ir/interp.rs} | 362 ++- src/ir/mod.rs | 578 ++++ src/{ => ir}/write_ir.rs | 14 +- src/{irgen.rs => irgen/mod.rs} | 2 +- src/lib.rs | 41 +- src/opt/gvn.rs | 11 + src/opt/mem2reg.rs | 11 + src/opt/mod.rs | 55 + src/opt/simplify_cfg.rs | 48 + src/optimize.rs | 31 - src/tests.rs | 56 + src/utils.rs | 35 - src/write_asm.rs | 5 - src/write_base.rs | 4 + src/write_c_test.rs | 20 - tests/.gitignore | 2 + tests/fuzz.py | 232 +- tests/reduce-criteria-template.sh | 3 + tests/test_examples.rs | 30 +- 40 files changed, 5171 insertions(+), 1504 deletions(-) create mode 100644 examples/.gitignore create mode 100644 examples/hw1/complete_cond.c create mode 100644 examples/hw1/cond_and_loop.c create mode 100644 examples/hw1/gcd.c create mode 100644 examples/meta/make_cond.py create mode 100644 examples/simple_cond.c create mode 100755 scripts/copy-to-kecc-public.sh rename src/{asm.rs => asm/mod.rs} (62%) create mode 100644 src/asm/write_asm.rs rename src/{codegen.rs => asmgen/mod.rs} (70%) rename src/{assert_ast_equiv.rs => c/ast_equiv.rs} (99%) create mode 100644 src/c/mod.rs rename src/{ => c}/parse.rs (96%) rename src/{ => c}/write_c.rs (88%) delete mode 100644 src/ir.rs create mode 100644 src/ir/dtype.rs rename src/{run_ir.rs => ir/interp.rs} (68%) create mode 100644 src/ir/mod.rs rename src/{ => ir}/write_ir.rs (96%) rename src/{irgen.rs => irgen/mod.rs} (97%) create mode 100644 src/opt/gvn.rs create mode 100644 src/opt/mem2reg.rs create mode 100644 src/opt/mod.rs create mode 100644 src/opt/simplify_cfg.rs delete mode 100644 src/optimize.rs create mode 100644 src/tests.rs delete mode 100644 src/write_asm.rs delete mode 100644 src/write_c_test.rs create mode 100644 tests/reduce-criteria-template.sh diff --git a/README.md b/README.md index 705a10d..09c11bb 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ cargo test --release # release build test cargo test # run a particular test ``` -`` can be `test_ast_print`, `ir_smoke`, ... +`` can be `test_examples_write_c`, `test_examples_irgen`, ... ## Fuzzing @@ -44,10 +44,7 @@ cargo test # run a particular test ```sh # Ubuntu 18.04 or higher apt install -y make cmake python3 - -# MacOS -xcode-select install -brew install cmake python3 +apt install -y csmith libcsmith-dev creduce ``` ### Run @@ -59,5 +56,28 @@ python3 tests/fuzz.py --help # print options python3 tests/fuzz.py --print -n10 # test C AST printer for 10 times ``` -We use [Csmith](https://embed.cs.utah.edu/csmith/) to randomly generate C source codes. Csmith will -be automatically downloaded and built by the test script. +We use `csmith` to randomly generate C source codes. `csmith` will be automatically downloaded and +built by the test script. For more information, we refer to the +[Csmith](https://embed.cs.utah.edu/csmith/) homepage. + +### Reduce + +When the fuzzer finds a buggy input program for your compiler, it is highly likely that the input +program is too big to manually inspect. We use `creduce` that reduces the buggy input program as +much as possible. + +Suppose `tests/test_polished.c` is the buggy input program. Then the following script reduces the +program to `tests/test_reduced.c`: + +```sh +python3 tests/fuzz.py --reduce +``` + +`` can be `--print` or `--irgen`. It shall be the one used in [Run](#run). + +### How it reduces test case? + +The script performs unguided test-case reduction using `creduce`: given a buggy program, it randomly +reduces the program; check if the reduced program still fails on the test, and if so, replaces the +given program with the reduced one; repeat until you get a small enough buggy program. For more +information, we refer to the [Creduce](https://embed.cs.utah.edu/creduce/) homepage. diff --git a/bin/fuzz.rs b/bin/fuzz.rs index a1a4b18..ed8d08e 100644 --- a/bin/fuzz.rs +++ b/bin/fuzz.rs @@ -6,6 +6,7 @@ use clap::{crate_authors, crate_description, crate_version, App}; extern crate kecc; use kecc::{Parse, Translate}; +use std::path::Path; fn main() { let yaml = load_yaml!("fuzz_cli.yml"); @@ -20,7 +21,10 @@ fn main() { let unit = ok_or_exit!(Parse::default().translate(&input), 1); if matches.is_present("print") { - kecc::write_c_test(&unit); - return; + kecc::test_write_c(&unit, Path::new(&input)); + } + + if matches.is_present("irgen") { + kecc::test_irgen(&unit, Path::new(&input)); } } diff --git a/bin/fuzz_cli.yml b/bin/fuzz_cli.yml index 7b15e7a..3d1f324 100644 --- a/bin/fuzz_cli.yml +++ b/bin/fuzz_cli.yml @@ -4,6 +4,10 @@ args: short: p long: print help: Fuzzes C AST printer + - irgen: + short: i + long: irgen + help: Fuzzes irgen - INPUT: help: Sets the input file to use required: true diff --git a/bin/kecc.rs b/bin/kecc.rs index ca2ec6e..bda3ae0 100644 --- a/bin/kecc.rs +++ b/bin/kecc.rs @@ -5,7 +5,7 @@ use clap::{crate_authors, crate_description, crate_version, App}; #[macro_use] extern crate kecc; -use kecc::{Codegen, Irgen, Optimize, Parse, Translate, O1}; +use kecc::{write, Asmgen, Irgen, Optimize, Parse, Translate, O1}; fn main() { let yaml = load_yaml!("kecc_cli.yml"); @@ -27,7 +27,7 @@ fn main() { }; if matches.is_present("print") { - kecc::write_c(&unit, &mut output).unwrap(); + write(&unit, &mut output).unwrap(); return; } @@ -39,7 +39,7 @@ fn main() { } }; if matches.is_present("irgen") { - kecc::write_ir(&ir, &mut output).unwrap(); + write(&ir, &mut output).unwrap(); return; } @@ -47,6 +47,6 @@ fn main() { O1::default().optimize(&mut ir); } - let asm = ok_or_exit!(Codegen::default().translate(&ir), 1); - kecc::write_asm(&asm, &mut output); + let asm = ok_or_exit!(Asmgen::default().translate(&ir), 1); + write(&asm, &mut output).unwrap(); } diff --git a/examples/.gitignore b/examples/.gitignore new file mode 100644 index 0000000..b883f1f --- /dev/null +++ b/examples/.gitignore @@ -0,0 +1 @@ +*.exe diff --git a/examples/hw1/complete_cond.c b/examples/hw1/complete_cond.c new file mode 100644 index 0000000..a97c55d --- /dev/null +++ b/examples/hw1/complete_cond.c @@ -0,0 +1,3205 @@ +int func_0() +{ + int a = 0; + int b = 1; + int c = 1; + int d = 1; + int e = 0; + int f = 0; + int g = 0; + int h = 0; + int i = 1; + int j = 0; + int k = 1; + int l = 1; + int m = 1; + int n = 0; + int o = 1; + int p = 0; + int q = 1; + int r = 0; + int s = 1; + int t = 1; + int u = 0; + int v = 0; + int w = 1; + int x = 0; + int y = 1; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_1() +{ + int a = 1; + int b = 1; + int c = 1; + int d = 0; + int e = 1; + int f = 0; + int g = 1; + int h = 0; + int i = 1; + int j = 0; + int k = 1; + int l = 1; + int m = 1; + int n = 0; + int o = 1; + int p = 1; + int q = 1; + int r = 1; + int s = 0; + int t = 1; + int u = 0; + int v = 1; + int w = 0; + int x = 0; + int y = 0; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_2() +{ + int a = 1; + int b = 0; + int c = 0; + int d = 0; + int e = 1; + int f = 0; + int g = 1; + int h = 0; + int i = 0; + int j = 1; + int k = 0; + int l = 1; + int m = 1; + int n = 0; + int o = 0; + int p = 1; + int q = 0; + int r = 1; + int s = 1; + int t = 1; + int u = 1; + int v = 0; + int w = 0; + int x = 0; + int y = 0; + int z = 0; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_3() +{ + int a = 0; + int b = 0; + int c = 0; + int d = 1; + int e = 0; + int f = 0; + int g = 0; + int h = 0; + int i = 1; + int j = 0; + int k = 0; + int l = 1; + int m = 1; + int n = 0; + int o = 0; + int p = 1; + int q = 0; + int r = 0; + int s = 1; + int t = 1; + int u = 0; + int v = 1; + int w = 0; + int x = 0; + int y = 0; + int z = 0; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_4() +{ + int a = 1; + int b = 0; + int c = 1; + int d = 0; + int e = 1; + int f = 0; + int g = 0; + int h = 0; + int i = 1; + int j = 1; + int k = 0; + int l = 0; + int m = 0; + int n = 1; + int o = 0; + int p = 1; + int q = 1; + int r = 0; + int s = 0; + int t = 1; + int u = 1; + int v = 1; + int w = 1; + int x = 1; + int y = 1; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_5() +{ + int a = 1; + int b = 0; + int c = 0; + int d = 0; + int e = 0; + int f = 1; + int g = 1; + int h = 1; + int i = 1; + int j = 0; + int k = 0; + int l = 1; + int m = 1; + int n = 0; + int o = 1; + int p = 1; + int q = 1; + int r = 1; + int s = 1; + int t = 1; + int u = 0; + int v = 1; + int w = 0; + int x = 1; + int y = 0; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_6() +{ + int a = 0; + int b = 1; + int c = 0; + int d = 0; + int e = 1; + int f = 0; + int g = 0; + int h = 0; + int i = 0; + int j = 0; + int k = 1; + int l = 1; + int m = 1; + int n = 0; + int o = 1; + int p = 1; + int q = 0; + int r = 1; + int s = 1; + int t = 0; + int u = 0; + int v = 0; + int w = 0; + int x = 1; + int y = 0; + int z = 0; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_7() +{ + int a = 0; + int b = 0; + int c = 1; + int d = 1; + int e = 1; + int f = 1; + int g = 0; + int h = 0; + int i = 0; + int j = 1; + int k = 1; + int l = 0; + int m = 1; + int n = 0; + int o = 0; + int p = 1; + int q = 0; + int r = 1; + int s = 0; + int t = 1; + int u = 0; + int v = 0; + int w = 1; + int x = 0; + int y = 0; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_8() +{ + int a = 0; + int b = 0; + int c = 0; + int d = 1; + int e = 1; + int f = 1; + int g = 0; + int h = 0; + int i = 1; + int j = 0; + int k = 1; + int l = 0; + int m = 1; + int n = 1; + int o = 1; + int p = 0; + int q = 0; + int r = 1; + int s = 0; + int t = 1; + int u = 1; + int v = 0; + int w = 1; + int x = 0; + int y = 1; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_9() +{ + int a = 0; + int b = 1; + int c = 1; + int d = 0; + int e = 1; + int f = 1; + int g = 1; + int h = 1; + int i = 1; + int j = 0; + int k = 0; + int l = 0; + int m = 0; + int n = 0; + int o = 0; + int p = 1; + int q = 0; + int r = 0; + int s = 0; + int t = 1; + int u = 1; + int v = 1; + int w = 0; + int x = 0; + int y = 0; + int z = 0; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_10() +{ + int a = 0; + int b = 0; + int c = 0; + int d = 0; + int e = 0; + int f = 0; + int g = 0; + int h = 0; + int i = 0; + int j = 1; + int k = 0; + int l = 0; + int m = 1; + int n = 1; + int o = 1; + int p = 1; + int q = 1; + int r = 1; + int s = 1; + int t = 1; + int u = 0; + int v = 1; + int w = 0; + int x = 0; + int y = 1; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_11() +{ + int a = 1; + int b = 0; + int c = 1; + int d = 0; + int e = 0; + int f = 1; + int g = 0; + int h = 1; + int i = 1; + int j = 0; + int k = 0; + int l = 0; + int m = 1; + int n = 1; + int o = 0; + int p = 1; + int q = 0; + int r = 0; + int s = 0; + int t = 0; + int u = 0; + int v = 1; + int w = 1; + int x = 0; + int y = 0; + int z = 0; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_12() +{ + int a = 0; + int b = 1; + int c = 0; + int d = 0; + int e = 0; + int f = 0; + int g = 1; + int h = 0; + int i = 1; + int j = 1; + int k = 1; + int l = 1; + int m = 1; + int n = 0; + int o = 0; + int p = 0; + int q = 1; + int r = 0; + int s = 0; + int t = 0; + int u = 0; + int v = 1; + int w = 0; + int x = 0; + int y = 1; + int z = 0; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_13() +{ + int a = 0; + int b = 0; + int c = 1; + int d = 1; + int e = 0; + int f = 0; + int g = 1; + int h = 1; + int i = 0; + int j = 1; + int k = 0; + int l = 0; + int m = 1; + int n = 0; + int o = 1; + int p = 1; + int q = 1; + int r = 0; + int s = 1; + int t = 1; + int u = 0; + int v = 1; + int w = 0; + int x = 0; + int y = 1; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_14() +{ + int a = 1; + int b = 0; + int c = 0; + int d = 0; + int e = 1; + int f = 0; + int g = 1; + int h = 1; + int i = 1; + int j = 1; + int k = 0; + int l = 1; + int m = 0; + int n = 1; + int o = 1; + int p = 0; + int q = 0; + int r = 1; + int s = 0; + int t = 0; + int u = 0; + int v = 0; + int w = 0; + int x = 1; + int y = 0; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_15() +{ + int a = 1; + int b = 0; + int c = 0; + int d = 1; + int e = 0; + int f = 1; + int g = 1; + int h = 0; + int i = 0; + int j = 1; + int k = 1; + int l = 1; + int m = 0; + int n = 0; + int o = 1; + int p = 1; + int q = 1; + int r = 1; + int s = 0; + int t = 1; + int u = 0; + int v = 1; + int w = 1; + int x = 0; + int y = 1; + int z = 0; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_16() +{ + int a = 0; + int b = 0; + int c = 1; + int d = 1; + int e = 0; + int f = 0; + int g = 1; + int h = 1; + int i = 1; + int j = 0; + int k = 1; + int l = 0; + int m = 1; + int n = 1; + int o = 1; + int p = 1; + int q = 0; + int r = 0; + int s = 1; + int t = 0; + int u = 1; + int v = 0; + int w = 0; + int x = 0; + int y = 0; + int z = 0; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_17() +{ + int a = 0; + int b = 1; + int c = 1; + int d = 0; + int e = 0; + int f = 1; + int g = 1; + int h = 0; + int i = 0; + int j = 1; + int k = 0; + int l = 1; + int m = 1; + int n = 0; + int o = 1; + int p = 1; + int q = 0; + int r = 1; + int s = 0; + int t = 0; + int u = 1; + int v = 0; + int w = 1; + int x = 0; + int y = 1; + int z = 0; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_18() +{ + int a = 1; + int b = 1; + int c = 0; + int d = 0; + int e = 1; + int f = 0; + int g = 1; + int h = 1; + int i = 1; + int j = 0; + int k = 0; + int l = 0; + int m = 1; + int n = 1; + int o = 1; + int p = 0; + int q = 0; + int r = 1; + int s = 0; + int t = 0; + int u = 0; + int v = 0; + int w = 0; + int x = 0; + int y = 1; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_19() +{ + int a = 0; + int b = 0; + int c = 1; + int d = 1; + int e = 1; + int f = 0; + int g = 1; + int h = 0; + int i = 1; + int j = 1; + int k = 0; + int l = 0; + int m = 0; + int n = 0; + int o = 1; + int p = 1; + int q = 0; + int r = 0; + int s = 1; + int t = 1; + int u = 1; + int v = 1; + int w = 0; + int x = 0; + int y = 0; + int z = 0; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_20() +{ + int a = 1; + int b = 0; + int c = 1; + int d = 1; + int e = 0; + int f = 1; + int g = 0; + int h = 1; + int i = 1; + int j = 1; + int k = 1; + int l = 1; + int m = 1; + int n = 0; + int o = 1; + int p = 1; + int q = 0; + int r = 1; + int s = 0; + int t = 0; + int u = 0; + int v = 0; + int w = 1; + int x = 0; + int y = 0; + int z = 0; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_21() +{ + int a = 1; + int b = 1; + int c = 0; + int d = 0; + int e = 0; + int f = 0; + int g = 0; + int h = 0; + int i = 0; + int j = 0; + int k = 1; + int l = 0; + int m = 0; + int n = 1; + int o = 0; + int p = 0; + int q = 0; + int r = 1; + int s = 1; + int t = 1; + int u = 1; + int v = 1; + int w = 1; + int x = 1; + int y = 0; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_22() +{ + int a = 0; + int b = 0; + int c = 0; + int d = 1; + int e = 1; + int f = 1; + int g = 1; + int h = 0; + int i = 0; + int j = 0; + int k = 1; + int l = 0; + int m = 1; + int n = 0; + int o = 0; + int p = 0; + int q = 1; + int r = 0; + int s = 0; + int t = 1; + int u = 0; + int v = 1; + int w = 0; + int x = 0; + int y = 1; + int z = 0; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_23() +{ + int a = 1; + int b = 1; + int c = 1; + int d = 0; + int e = 1; + int f = 0; + int g = 0; + int h = 1; + int i = 0; + int j = 0; + int k = 1; + int l = 0; + int m = 1; + int n = 1; + int o = 1; + int p = 0; + int q = 1; + int r = 0; + int s = 0; + int t = 1; + int u = 1; + int v = 1; + int w = 0; + int x = 0; + int y = 1; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_24() +{ + int a = 0; + int b = 1; + int c = 0; + int d = 1; + int e = 0; + int f = 1; + int g = 1; + int h = 1; + int i = 1; + int j = 1; + int k = 1; + int l = 1; + int m = 0; + int n = 0; + int o = 1; + int p = 0; + int q = 0; + int r = 1; + int s = 0; + int t = 0; + int u = 1; + int v = 0; + int w = 1; + int x = 1; + int y = 1; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_25() +{ + int a = 1; + int b = 1; + int c = 1; + int d = 0; + int e = 1; + int f = 1; + int g = 0; + int h = 0; + int i = 1; + int j = 1; + int k = 1; + int l = 1; + int m = 1; + int n = 1; + int o = 0; + int p = 1; + int q = 0; + int r = 1; + int s = 1; + int t = 1; + int u = 0; + int v = 1; + int w = 1; + int x = 0; + int y = 1; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_26() +{ + int a = 0; + int b = 0; + int c = 0; + int d = 0; + int e = 1; + int f = 1; + int g = 0; + int h = 0; + int i = 1; + int j = 0; + int k = 1; + int l = 1; + int m = 0; + int n = 0; + int o = 0; + int p = 1; + int q = 1; + int r = 1; + int s = 0; + int t = 0; + int u = 0; + int v = 0; + int w = 0; + int x = 0; + int y = 0; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_27() +{ + int a = 0; + int b = 1; + int c = 0; + int d = 0; + int e = 1; + int f = 1; + int g = 1; + int h = 1; + int i = 0; + int j = 1; + int k = 0; + int l = 0; + int m = 1; + int n = 1; + int o = 0; + int p = 0; + int q = 0; + int r = 0; + int s = 0; + int t = 0; + int u = 1; + int v = 1; + int w = 0; + int x = 1; + int y = 1; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_28() +{ + int a = 0; + int b = 0; + int c = 1; + int d = 1; + int e = 1; + int f = 0; + int g = 0; + int h = 0; + int i = 1; + int j = 0; + int k = 0; + int l = 1; + int m = 0; + int n = 0; + int o = 1; + int p = 0; + int q = 0; + int r = 0; + int s = 0; + int t = 1; + int u = 0; + int v = 0; + int w = 1; + int x = 0; + int y = 0; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_29() +{ + int a = 1; + int b = 1; + int c = 0; + int d = 0; + int e = 1; + int f = 0; + int g = 1; + int h = 1; + int i = 0; + int j = 1; + int k = 1; + int l = 1; + int m = 0; + int n = 0; + int o = 1; + int p = 1; + int q = 0; + int r = 0; + int s = 0; + int t = 1; + int u = 0; + int v = 0; + int w = 0; + int x = 0; + int y = 0; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_30() +{ + int a = 0; + int b = 1; + int c = 0; + int d = 1; + int e = 1; + int f = 0; + int g = 1; + int h = 0; + int i = 0; + int j = 1; + int k = 0; + int l = 0; + int m = 0; + int n = 1; + int o = 1; + int p = 0; + int q = 1; + int r = 0; + int s = 1; + int t = 0; + int u = 1; + int v = 0; + int w = 0; + int x = 1; + int y = 0; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_31() +{ + int a = 1; + int b = 0; + int c = 0; + int d = 0; + int e = 1; + int f = 0; + int g = 1; + int h = 1; + int i = 1; + int j = 1; + int k = 0; + int l = 0; + int m = 0; + int n = 1; + int o = 0; + int p = 1; + int q = 0; + int r = 0; + int s = 0; + int t = 0; + int u = 0; + int v = 1; + int w = 0; + int x = 0; + int y = 0; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_32() +{ + int a = 1; + int b = 1; + int c = 0; + int d = 1; + int e = 0; + int f = 1; + int g = 1; + int h = 1; + int i = 1; + int j = 1; + int k = 1; + int l = 1; + int m = 1; + int n = 0; + int o = 1; + int p = 1; + int q = 0; + int r = 0; + int s = 1; + int t = 0; + int u = 0; + int v = 1; + int w = 1; + int x = 0; + int y = 1; + int z = 0; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_33() +{ + int a = 0; + int b = 0; + int c = 0; + int d = 1; + int e = 1; + int f = 1; + int g = 0; + int h = 0; + int i = 1; + int j = 1; + int k = 0; + int l = 1; + int m = 0; + int n = 1; + int o = 0; + int p = 0; + int q = 0; + int r = 1; + int s = 0; + int t = 0; + int u = 0; + int v = 0; + int w = 1; + int x = 1; + int y = 0; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_34() +{ + int a = 0; + int b = 1; + int c = 0; + int d = 0; + int e = 1; + int f = 1; + int g = 0; + int h = 0; + int i = 0; + int j = 1; + int k = 0; + int l = 1; + int m = 1; + int n = 0; + int o = 1; + int p = 0; + int q = 1; + int r = 0; + int s = 0; + int t = 1; + int u = 1; + int v = 1; + int w = 1; + int x = 1; + int y = 0; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_35() +{ + int a = 0; + int b = 0; + int c = 1; + int d = 1; + int e = 0; + int f = 1; + int g = 0; + int h = 0; + int i = 1; + int j = 1; + int k = 0; + int l = 0; + int m = 1; + int n = 1; + int o = 0; + int p = 0; + int q = 1; + int r = 0; + int s = 1; + int t = 0; + int u = 1; + int v = 0; + int w = 1; + int x = 0; + int y = 1; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_36() +{ + int a = 1; + int b = 0; + int c = 0; + int d = 1; + int e = 1; + int f = 1; + int g = 1; + int h = 0; + int i = 0; + int j = 0; + int k = 1; + int l = 0; + int m = 1; + int n = 1; + int o = 1; + int p = 1; + int q = 1; + int r = 0; + int s = 0; + int t = 0; + int u = 0; + int v = 0; + int w = 0; + int x = 0; + int y = 1; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_37() +{ + int a = 1; + int b = 0; + int c = 1; + int d = 0; + int e = 1; + int f = 1; + int g = 1; + int h = 0; + int i = 1; + int j = 0; + int k = 1; + int l = 1; + int m = 1; + int n = 1; + int o = 1; + int p = 0; + int q = 0; + int r = 0; + int s = 0; + int t = 0; + int u = 0; + int v = 0; + int w = 0; + int x = 1; + int y = 0; + int z = 0; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_38() +{ + int a = 1; + int b = 1; + int c = 0; + int d = 1; + int e = 0; + int f = 1; + int g = 0; + int h = 1; + int i = 1; + int j = 1; + int k = 1; + int l = 0; + int m = 1; + int n = 1; + int o = 0; + int p = 1; + int q = 0; + int r = 0; + int s = 1; + int t = 0; + int u = 1; + int v = 0; + int w = 0; + int x = 0; + int y = 0; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_39() +{ + int a = 1; + int b = 1; + int c = 0; + int d = 1; + int e = 1; + int f = 1; + int g = 1; + int h = 1; + int i = 1; + int j = 1; + int k = 1; + int l = 0; + int m = 1; + int n = 0; + int o = 1; + int p = 1; + int q = 1; + int r = 1; + int s = 1; + int t = 0; + int u = 0; + int v = 0; + int w = 0; + int x = 1; + int y = 1; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_40() +{ + int a = 0; + int b = 1; + int c = 0; + int d = 0; + int e = 0; + int f = 1; + int g = 0; + int h = 1; + int i = 0; + int j = 0; + int k = 1; + int l = 0; + int m = 0; + int n = 1; + int o = 0; + int p = 0; + int q = 0; + int r = 1; + int s = 0; + int t = 0; + int u = 1; + int v = 0; + int w = 1; + int x = 0; + int y = 0; + int z = 0; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_41() +{ + int a = 0; + int b = 1; + int c = 0; + int d = 1; + int e = 0; + int f = 0; + int g = 0; + int h = 0; + int i = 1; + int j = 0; + int k = 0; + int l = 1; + int m = 1; + int n = 1; + int o = 1; + int p = 0; + int q = 0; + int r = 0; + int s = 1; + int t = 0; + int u = 1; + int v = 1; + int w = 1; + int x = 0; + int y = 1; + int z = 0; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_42() +{ + int a = 1; + int b = 1; + int c = 1; + int d = 1; + int e = 1; + int f = 0; + int g = 0; + int h = 1; + int i = 0; + int j = 1; + int k = 0; + int l = 1; + int m = 1; + int n = 1; + int o = 1; + int p = 1; + int q = 0; + int r = 0; + int s = 0; + int t = 0; + int u = 1; + int v = 0; + int w = 0; + int x = 1; + int y = 1; + int z = 0; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_43() +{ + int a = 1; + int b = 0; + int c = 1; + int d = 1; + int e = 0; + int f = 0; + int g = 0; + int h = 1; + int i = 0; + int j = 1; + int k = 0; + int l = 1; + int m = 1; + int n = 1; + int o = 0; + int p = 0; + int q = 1; + int r = 0; + int s = 0; + int t = 1; + int u = 1; + int v = 1; + int w = 1; + int x = 1; + int y = 0; + int z = 0; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_44() +{ + int a = 0; + int b = 0; + int c = 1; + int d = 1; + int e = 1; + int f = 0; + int g = 1; + int h = 1; + int i = 0; + int j = 0; + int k = 1; + int l = 1; + int m = 0; + int n = 1; + int o = 1; + int p = 0; + int q = 0; + int r = 1; + int s = 0; + int t = 0; + int u = 0; + int v = 1; + int w = 0; + int x = 0; + int y = 0; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_45() +{ + int a = 0; + int b = 0; + int c = 1; + int d = 1; + int e = 1; + int f = 0; + int g = 0; + int h = 1; + int i = 1; + int j = 0; + int k = 1; + int l = 0; + int m = 1; + int n = 1; + int o = 1; + int p = 0; + int q = 1; + int r = 1; + int s = 0; + int t = 0; + int u = 1; + int v = 1; + int w = 0; + int x = 0; + int y = 1; + int z = 0; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_46() +{ + int a = 1; + int b = 1; + int c = 1; + int d = 0; + int e = 0; + int f = 0; + int g = 1; + int h = 1; + int i = 0; + int j = 0; + int k = 1; + int l = 0; + int m = 1; + int n = 1; + int o = 1; + int p = 1; + int q = 1; + int r = 0; + int s = 1; + int t = 1; + int u = 0; + int v = 1; + int w = 1; + int x = 1; + int y = 1; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_47() +{ + int a = 1; + int b = 1; + int c = 0; + int d = 1; + int e = 1; + int f = 1; + int g = 0; + int h = 1; + int i = 1; + int j = 1; + int k = 1; + int l = 1; + int m = 1; + int n = 1; + int o = 1; + int p = 1; + int q = 0; + int r = 0; + int s = 0; + int t = 0; + int u = 0; + int v = 0; + int w = 0; + int x = 1; + int y = 0; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_48() +{ + int a = 1; + int b = 0; + int c = 1; + int d = 1; + int e = 1; + int f = 1; + int g = 1; + int h = 1; + int i = 1; + int j = 0; + int k = 1; + int l = 0; + int m = 0; + int n = 1; + int o = 0; + int p = 0; + int q = 1; + int r = 1; + int s = 1; + int t = 0; + int u = 1; + int v = 0; + int w = 1; + int x = 1; + int y = 0; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_49() +{ + int a = 0; + int b = 1; + int c = 1; + int d = 1; + int e = 0; + int f = 1; + int g = 0; + int h = 1; + int i = 0; + int j = 1; + int k = 1; + int l = 1; + int m = 1; + int n = 1; + int o = 0; + int p = 1; + int q = 1; + int r = 0; + int s = 0; + int t = 1; + int u = 1; + int v = 0; + int w = 0; + int x = 1; + int y = 1; + int z = 0; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_50() +{ + int a = 0; + int b = 1; + int c = 0; + int d = 1; + int e = 0; + int f = 0; + int g = 0; + int h = 0; + int i = 1; + int j = 1; + int k = 0; + int l = 1; + int m = 0; + int n = 1; + int o = 1; + int p = 1; + int q = 1; + int r = 0; + int s = 1; + int t = 0; + int u = 1; + int v = 0; + int w = 1; + int x = 1; + int y = 0; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_51() +{ + int a = 1; + int b = 1; + int c = 0; + int d = 1; + int e = 1; + int f = 1; + int g = 0; + int h = 0; + int i = 1; + int j = 1; + int k = 1; + int l = 1; + int m = 0; + int n = 1; + int o = 1; + int p = 1; + int q = 1; + int r = 0; + int s = 0; + int t = 1; + int u = 0; + int v = 1; + int w = 0; + int x = 0; + int y = 0; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_52() +{ + int a = 1; + int b = 0; + int c = 1; + int d = 0; + int e = 1; + int f = 1; + int g = 0; + int h = 0; + int i = 0; + int j = 0; + int k = 0; + int l = 1; + int m = 1; + int n = 1; + int o = 0; + int p = 1; + int q = 1; + int r = 1; + int s = 0; + int t = 0; + int u = 0; + int v = 1; + int w = 0; + int x = 0; + int y = 1; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_53() +{ + int a = 0; + int b = 1; + int c = 0; + int d = 0; + int e = 0; + int f = 1; + int g = 0; + int h = 0; + int i = 1; + int j = 1; + int k = 0; + int l = 1; + int m = 0; + int n = 1; + int o = 1; + int p = 0; + int q = 0; + int r = 0; + int s = 1; + int t = 0; + int u = 1; + int v = 0; + int w = 1; + int x = 1; + int y = 1; + int z = 0; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_54() +{ + int a = 1; + int b = 0; + int c = 0; + int d = 0; + int e = 0; + int f = 1; + int g = 0; + int h = 1; + int i = 1; + int j = 0; + int k = 0; + int l = 1; + int m = 0; + int n = 0; + int o = 0; + int p = 0; + int q = 1; + int r = 0; + int s = 0; + int t = 1; + int u = 1; + int v = 0; + int w = 0; + int x = 1; + int y = 0; + int z = 0; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_55() +{ + int a = 1; + int b = 1; + int c = 0; + int d = 0; + int e = 1; + int f = 1; + int g = 1; + int h = 0; + int i = 1; + int j = 0; + int k = 1; + int l = 1; + int m = 1; + int n = 0; + int o = 0; + int p = 0; + int q = 0; + int r = 1; + int s = 1; + int t = 0; + int u = 0; + int v = 0; + int w = 1; + int x = 0; + int y = 1; + int z = 0; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_56() +{ + int a = 0; + int b = 1; + int c = 0; + int d = 0; + int e = 1; + int f = 0; + int g = 1; + int h = 1; + int i = 1; + int j = 1; + int k = 0; + int l = 0; + int m = 0; + int n = 0; + int o = 1; + int p = 1; + int q = 1; + int r = 0; + int s = 0; + int t = 0; + int u = 0; + int v = 0; + int w = 1; + int x = 1; + int y = 0; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_57() +{ + int a = 0; + int b = 1; + int c = 0; + int d = 1; + int e = 1; + int f = 0; + int g = 1; + int h = 0; + int i = 1; + int j = 1; + int k = 0; + int l = 1; + int m = 1; + int n = 1; + int o = 0; + int p = 0; + int q = 0; + int r = 0; + int s = 0; + int t = 1; + int u = 0; + int v = 0; + int w = 1; + int x = 0; + int y = 1; + int z = 0; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_58() +{ + int a = 0; + int b = 0; + int c = 0; + int d = 0; + int e = 0; + int f = 0; + int g = 1; + int h = 1; + int i = 1; + int j = 0; + int k = 0; + int l = 0; + int m = 1; + int n = 1; + int o = 0; + int p = 1; + int q = 1; + int r = 1; + int s = 0; + int t = 1; + int u = 1; + int v = 0; + int w = 0; + int x = 0; + int y = 1; + int z = 0; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_59() +{ + int a = 1; + int b = 1; + int c = 1; + int d = 1; + int e = 1; + int f = 1; + int g = 0; + int h = 0; + int i = 0; + int j = 0; + int k = 0; + int l = 0; + int m = 1; + int n = 0; + int o = 0; + int p = 0; + int q = 1; + int r = 1; + int s = 1; + int t = 0; + int u = 1; + int v = 0; + int w = 1; + int x = 0; + int y = 1; + int z = 0; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_60() +{ + int a = 0; + int b = 0; + int c = 0; + int d = 1; + int e = 0; + int f = 0; + int g = 0; + int h = 0; + int i = 1; + int j = 0; + int k = 1; + int l = 0; + int m = 1; + int n = 1; + int o = 0; + int p = 1; + int q = 0; + int r = 0; + int s = 1; + int t = 1; + int u = 1; + int v = 0; + int w = 1; + int x = 1; + int y = 0; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_61() +{ + int a = 0; + int b = 1; + int c = 1; + int d = 0; + int e = 0; + int f = 0; + int g = 1; + int h = 1; + int i = 1; + int j = 0; + int k = 0; + int l = 1; + int m = 0; + int n = 1; + int o = 1; + int p = 0; + int q = 1; + int r = 1; + int s = 0; + int t = 0; + int u = 0; + int v = 1; + int w = 1; + int x = 1; + int y = 0; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_62() +{ + int a = 0; + int b = 1; + int c = 0; + int d = 1; + int e = 1; + int f = 0; + int g = 0; + int h = 0; + int i = 1; + int j = 0; + int k = 1; + int l = 0; + int m = 1; + int n = 0; + int o = 0; + int p = 1; + int q = 1; + int r = 1; + int s = 0; + int t = 1; + int u = 1; + int v = 1; + int w = 1; + int x = 0; + int y = 0; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_63() +{ + int a = 1; + int b = 0; + int c = 0; + int d = 1; + int e = 0; + int f = 0; + int g = 1; + int h = 1; + int i = 0; + int j = 1; + int k = 0; + int l = 0; + int m = 0; + int n = 0; + int o = 1; + int p = 1; + int q = 0; + int r = 1; + int s = 1; + int t = 1; + int u = 1; + int v = 0; + int w = 0; + int x = 1; + int y = 0; + int z = 0; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_64() +{ + int a = 1; + int b = 1; + int c = 1; + int d = 1; + int e = 1; + int f = 1; + int g = 1; + int h = 1; + int i = 1; + int j = 0; + int k = 0; + int l = 0; + int m = 1; + int n = 0; + int o = 1; + int p = 1; + int q = 1; + int r = 1; + int s = 1; + int t = 0; + int u = 0; + int v = 0; + int w = 1; + int x = 0; + int y = 1; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_65() +{ + int a = 1; + int b = 1; + int c = 1; + int d = 1; + int e = 0; + int f = 1; + int g = 0; + int h = 1; + int i = 1; + int j = 0; + int k = 1; + int l = 0; + int m = 1; + int n = 0; + int o = 0; + int p = 1; + int q = 1; + int r = 0; + int s = 0; + int t = 1; + int u = 0; + int v = 0; + int w = 0; + int x = 0; + int y = 1; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_66() +{ + int a = 1; + int b = 0; + int c = 1; + int d = 1; + int e = 0; + int f = 0; + int g = 0; + int h = 1; + int i = 0; + int j = 0; + int k = 1; + int l = 0; + int m = 0; + int n = 0; + int o = 1; + int p = 1; + int q = 0; + int r = 1; + int s = 1; + int t = 0; + int u = 1; + int v = 0; + int w = 1; + int x = 0; + int y = 1; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_67() +{ + int a = 0; + int b = 1; + int c = 1; + int d = 1; + int e = 1; + int f = 1; + int g = 1; + int h = 1; + int i = 0; + int j = 0; + int k = 1; + int l = 0; + int m = 1; + int n = 1; + int o = 1; + int p = 1; + int q = 1; + int r = 1; + int s = 0; + int t = 1; + int u = 0; + int v = 0; + int w = 1; + int x = 1; + int y = 1; + int z = 0; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_68() +{ + int a = 0; + int b = 0; + int c = 1; + int d = 1; + int e = 1; + int f = 0; + int g = 1; + int h = 1; + int i = 0; + int j = 0; + int k = 0; + int l = 0; + int m = 1; + int n = 1; + int o = 1; + int p = 0; + int q = 0; + int r = 1; + int s = 1; + int t = 1; + int u = 1; + int v = 0; + int w = 0; + int x = 0; + int y = 1; + int z = 0; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_69() +{ + int a = 0; + int b = 0; + int c = 0; + int d = 1; + int e = 0; + int f = 1; + int g = 1; + int h = 0; + int i = 1; + int j = 0; + int k = 1; + int l = 1; + int m = 1; + int n = 1; + int o = 0; + int p = 0; + int q = 0; + int r = 1; + int s = 0; + int t = 0; + int u = 0; + int v = 0; + int w = 1; + int x = 0; + int y = 1; + int z = 0; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_70() +{ + int a = 1; + int b = 0; + int c = 0; + int d = 0; + int e = 0; + int f = 0; + int g = 1; + int h = 0; + int i = 0; + int j = 1; + int k = 1; + int l = 1; + int m = 0; + int n = 0; + int o = 0; + int p = 1; + int q = 0; + int r = 0; + int s = 1; + int t = 0; + int u = 1; + int v = 1; + int w = 1; + int x = 1; + int y = 0; + int z = 0; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_71() +{ + int a = 0; + int b = 0; + int c = 1; + int d = 0; + int e = 0; + int f = 1; + int g = 0; + int h = 0; + int i = 0; + int j = 1; + int k = 1; + int l = 1; + int m = 0; + int n = 0; + int o = 1; + int p = 0; + int q = 1; + int r = 0; + int s = 0; + int t = 0; + int u = 0; + int v = 1; + int w = 1; + int x = 0; + int y = 0; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_72() +{ + int a = 1; + int b = 1; + int c = 0; + int d = 0; + int e = 1; + int f = 0; + int g = 1; + int h = 0; + int i = 1; + int j = 0; + int k = 0; + int l = 0; + int m = 1; + int n = 1; + int o = 1; + int p = 0; + int q = 1; + int r = 0; + int s = 0; + int t = 1; + int u = 1; + int v = 1; + int w = 0; + int x = 1; + int y = 0; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_73() +{ + int a = 1; + int b = 1; + int c = 1; + int d = 1; + int e = 1; + int f = 1; + int g = 1; + int h = 0; + int i = 0; + int j = 1; + int k = 0; + int l = 1; + int m = 0; + int n = 1; + int o = 0; + int p = 1; + int q = 0; + int r = 1; + int s = 0; + int t = 0; + int u = 1; + int v = 1; + int w = 0; + int x = 0; + int y = 0; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_74() +{ + int a = 0; + int b = 0; + int c = 0; + int d = 1; + int e = 1; + int f = 1; + int g = 1; + int h = 0; + int i = 1; + int j = 0; + int k = 0; + int l = 0; + int m = 1; + int n = 1; + int o = 0; + int p = 0; + int q = 1; + int r = 0; + int s = 1; + int t = 1; + int u = 0; + int v = 0; + int w = 0; + int x = 0; + int y = 1; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_75() +{ + int a = 0; + int b = 0; + int c = 1; + int d = 0; + int e = 0; + int f = 0; + int g = 0; + int h = 0; + int i = 0; + int j = 0; + int k = 0; + int l = 0; + int m = 0; + int n = 1; + int o = 0; + int p = 0; + int q = 1; + int r = 0; + int s = 1; + int t = 1; + int u = 1; + int v = 0; + int w = 0; + int x = 0; + int y = 1; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_76() +{ + int a = 0; + int b = 1; + int c = 1; + int d = 1; + int e = 0; + int f = 1; + int g = 1; + int h = 1; + int i = 1; + int j = 0; + int k = 1; + int l = 0; + int m = 0; + int n = 1; + int o = 1; + int p = 1; + int q = 0; + int r = 0; + int s = 1; + int t = 1; + int u = 0; + int v = 1; + int w = 0; + int x = 1; + int y = 0; + int z = 0; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_77() +{ + int a = 1; + int b = 1; + int c = 0; + int d = 1; + int e = 1; + int f = 0; + int g = 0; + int h = 0; + int i = 0; + int j = 0; + int k = 1; + int l = 0; + int m = 1; + int n = 1; + int o = 1; + int p = 0; + int q = 0; + int r = 0; + int s = 0; + int t = 0; + int u = 1; + int v = 0; + int w = 0; + int x = 0; + int y = 0; + int z = 0; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_78() +{ + int a = 1; + int b = 1; + int c = 0; + int d = 0; + int e = 0; + int f = 1; + int g = 1; + int h = 1; + int i = 0; + int j = 0; + int k = 1; + int l = 1; + int m = 1; + int n = 0; + int o = 0; + int p = 1; + int q = 0; + int r = 0; + int s = 1; + int t = 0; + int u = 0; + int v = 1; + int w = 1; + int x = 0; + int y = 1; + int z = 0; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_79() +{ + int a = 0; + int b = 0; + int c = 1; + int d = 0; + int e = 0; + int f = 0; + int g = 0; + int h = 0; + int i = 0; + int j = 0; + int k = 1; + int l = 1; + int m = 1; + int n = 1; + int o = 1; + int p = 1; + int q = 0; + int r = 0; + int s = 0; + int t = 0; + int u = 0; + int v = 1; + int w = 1; + int x = 0; + int y = 0; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_80() +{ + int a = 1; + int b = 1; + int c = 0; + int d = 1; + int e = 0; + int f = 1; + int g = 1; + int h = 1; + int i = 0; + int j = 1; + int k = 0; + int l = 1; + int m = 0; + int n = 1; + int o = 1; + int p = 0; + int q = 0; + int r = 1; + int s = 0; + int t = 1; + int u = 0; + int v = 0; + int w = 0; + int x = 1; + int y = 0; + int z = 0; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_81() +{ + int a = 0; + int b = 0; + int c = 0; + int d = 1; + int e = 0; + int f = 0; + int g = 1; + int h = 1; + int i = 0; + int j = 0; + int k = 1; + int l = 1; + int m = 0; + int n = 0; + int o = 1; + int p = 0; + int q = 0; + int r = 0; + int s = 1; + int t = 1; + int u = 1; + int v = 1; + int w = 1; + int x = 1; + int y = 1; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_82() +{ + int a = 1; + int b = 0; + int c = 1; + int d = 0; + int e = 0; + int f = 0; + int g = 1; + int h = 0; + int i = 1; + int j = 1; + int k = 0; + int l = 0; + int m = 1; + int n = 1; + int o = 1; + int p = 1; + int q = 1; + int r = 1; + int s = 0; + int t = 1; + int u = 1; + int v = 1; + int w = 1; + int x = 0; + int y = 0; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_83() +{ + int a = 1; + int b = 0; + int c = 0; + int d = 1; + int e = 1; + int f = 1; + int g = 0; + int h = 0; + int i = 0; + int j = 1; + int k = 0; + int l = 1; + int m = 1; + int n = 1; + int o = 1; + int p = 1; + int q = 0; + int r = 1; + int s = 1; + int t = 1; + int u = 0; + int v = 1; + int w = 1; + int x = 0; + int y = 0; + int z = 0; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_84() +{ + int a = 0; + int b = 1; + int c = 0; + int d = 1; + int e = 0; + int f = 0; + int g = 0; + int h = 1; + int i = 0; + int j = 0; + int k = 1; + int l = 0; + int m = 1; + int n = 1; + int o = 1; + int p = 1; + int q = 1; + int r = 1; + int s = 1; + int t = 1; + int u = 1; + int v = 0; + int w = 1; + int x = 1; + int y = 1; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_85() +{ + int a = 0; + int b = 0; + int c = 0; + int d = 1; + int e = 0; + int f = 1; + int g = 0; + int h = 0; + int i = 1; + int j = 1; + int k = 1; + int l = 0; + int m = 0; + int n = 0; + int o = 1; + int p = 0; + int q = 0; + int r = 1; + int s = 0; + int t = 1; + int u = 1; + int v = 0; + int w = 1; + int x = 1; + int y = 0; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_86() +{ + int a = 0; + int b = 0; + int c = 1; + int d = 1; + int e = 0; + int f = 0; + int g = 1; + int h = 1; + int i = 0; + int j = 1; + int k = 0; + int l = 1; + int m = 0; + int n = 0; + int o = 1; + int p = 1; + int q = 1; + int r = 0; + int s = 1; + int t = 0; + int u = 1; + int v = 0; + int w = 1; + int x = 1; + int y = 0; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_87() +{ + int a = 0; + int b = 1; + int c = 1; + int d = 1; + int e = 0; + int f = 0; + int g = 0; + int h = 0; + int i = 0; + int j = 0; + int k = 1; + int l = 0; + int m = 0; + int n = 0; + int o = 0; + int p = 0; + int q = 1; + int r = 0; + int s = 1; + int t = 1; + int u = 0; + int v = 0; + int w = 1; + int x = 1; + int y = 1; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_88() +{ + int a = 1; + int b = 0; + int c = 1; + int d = 1; + int e = 0; + int f = 1; + int g = 1; + int h = 1; + int i = 0; + int j = 0; + int k = 1; + int l = 0; + int m = 0; + int n = 1; + int o = 1; + int p = 0; + int q = 0; + int r = 1; + int s = 0; + int t = 1; + int u = 1; + int v = 0; + int w = 1; + int x = 1; + int y = 1; + int z = 0; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_89() +{ + int a = 0; + int b = 0; + int c = 1; + int d = 1; + int e = 1; + int f = 0; + int g = 1; + int h = 0; + int i = 1; + int j = 1; + int k = 0; + int l = 1; + int m = 1; + int n = 0; + int o = 0; + int p = 0; + int q = 1; + int r = 0; + int s = 0; + int t = 1; + int u = 0; + int v = 0; + int w = 1; + int x = 0; + int y = 1; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_90() +{ + int a = 1; + int b = 0; + int c = 1; + int d = 0; + int e = 0; + int f = 1; + int g = 0; + int h = 1; + int i = 0; + int j = 1; + int k = 1; + int l = 0; + int m = 0; + int n = 0; + int o = 1; + int p = 1; + int q = 1; + int r = 0; + int s = 1; + int t = 1; + int u = 1; + int v = 1; + int w = 0; + int x = 0; + int y = 0; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_91() +{ + int a = 0; + int b = 0; + int c = 1; + int d = 0; + int e = 1; + int f = 0; + int g = 1; + int h = 0; + int i = 1; + int j = 0; + int k = 1; + int l = 0; + int m = 0; + int n = 1; + int o = 0; + int p = 1; + int q = 1; + int r = 1; + int s = 0; + int t = 1; + int u = 0; + int v = 1; + int w = 0; + int x = 0; + int y = 1; + int z = 1; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_92() +{ + int a = 0; + int b = 1; + int c = 1; + int d = 1; + int e = 0; + int f = 0; + int g = 1; + int h = 0; + int i = 0; + int j = 1; + int k = 1; + int l = 0; + int m = 1; + int n = 1; + int o = 1; + int p = 1; + int q = 1; + int r = 0; + int s = 1; + int t = 1; + int u = 0; + int v = 0; + int w = 0; + int x = 0; + int y = 1; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_93() +{ + int a = 1; + int b = 0; + int c = 1; + int d = 0; + int e = 1; + int f = 1; + int g = 1; + int h = 1; + int i = 0; + int j = 1; + int k = 1; + int l = 0; + int m = 0; + int n = 1; + int o = 0; + int p = 0; + int q = 1; + int r = 1; + int s = 1; + int t = 0; + int u = 1; + int v = 0; + int w = 1; + int x = 1; + int y = 0; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_94() +{ + int a = 0; + int b = 1; + int c = 1; + int d = 0; + int e = 0; + int f = 1; + int g = 1; + int h = 1; + int i = 0; + int j = 0; + int k = 0; + int l = 0; + int m = 1; + int n = 1; + int o = 0; + int p = 1; + int q = 1; + int r = 0; + int s = 1; + int t = 0; + int u = 1; + int v = 1; + int w = 0; + int x = 0; + int y = 0; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_95() +{ + int a = 0; + int b = 0; + int c = 1; + int d = 1; + int e = 1; + int f = 1; + int g = 0; + int h = 1; + int i = 0; + int j = 1; + int k = 1; + int l = 0; + int m = 0; + int n = 1; + int o = 1; + int p = 0; + int q = 0; + int r = 0; + int s = 0; + int t = 1; + int u = 1; + int v = 1; + int w = 0; + int x = 0; + int y = 0; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int func_96() +{ + int a = 1; + int b = 0; + int c = 0; + int d = 1; + int e = 1; + int f = 0; + int g = 1; + int h = 1; + int i = 0; + int j = 1; + int k = 1; + int l = 0; + int m = 1; + int n = 0; + int o = 0; + int p = 0; + int q = 0; + int r = 1; + int s = 1; + int t = 1; + int u = 0; + int v = 0; + int w = 0; + int x = 1; + int y = 1; + int z = 1; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_97() +{ + int a = 1; + int b = 0; + int c = 1; + int d = 0; + int e = 0; + int f = 0; + int g = 0; + int h = 0; + int i = 0; + int j = 1; + int k = 1; + int l = 1; + int m = 0; + int n = 1; + int o = 1; + int p = 1; + int q = 0; + int r = 1; + int s = 1; + int t = 1; + int u = 0; + int v = 1; + int w = 0; + int x = 0; + int y = 1; + int z = 0; + int A = 1; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_98() +{ + int a = 0; + int b = 1; + int c = 0; + int d = 0; + int e = 0; + int f = 1; + int g = 0; + int h = 1; + int i = 0; + int j = 1; + int k = 0; + int l = 1; + int m = 1; + int n = 0; + int o = 1; + int p = 1; + int q = 0; + int r = 0; + int s = 1; + int t = 1; + int u = 0; + int v = 1; + int w = 0; + int x = 0; + int y = 1; + int z = 0; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 0; +} + +int func_99() +{ + int a = 1; + int b = 1; + int c = 1; + int d = 1; + int e = 0; + int f = 1; + int g = 0; + int h = 0; + int i = 1; + int j = 1; + int k = 0; + int l = 0; + int m = 0; + int n = 0; + int o = 1; + int p = 1; + int q = 1; + int r = 0; + int s = 0; + int t = 1; + int u = 1; + int v = 0; + int w = 1; + int x = 1; + int y = 1; + int z = 0; + int A = 0; + return (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == 1; +} + +int main() +{ + return (func_0() && func_1() && func_2() && func_3() && func_4() && func_5() && func_6() && func_7() && func_8() && func_9() && func_10() && func_11() && func_12() && func_13() && func_14() && func_15() && func_16() && func_17() && func_18() && func_19() && func_20() && func_21() && func_22() && func_23() && func_24() && func_25() && func_26() && func_27() && func_28() && func_29() && func_30() && func_31() && func_32() && func_33() && func_34() && func_35() && func_36() && func_37() && func_38() && func_39() && func_40() && func_41() && func_42() && func_43() && func_44() && func_45() && func_46() && func_47() && func_48() && func_49() && func_50() && func_51() && func_52() && func_53() && func_54() && func_55() && func_56() && func_57() && func_58() && func_59() && func_60() && func_61() && func_62() && func_63() && func_64() && func_65() && func_66() && func_67() && func_68() && func_69() && func_70() && func_71() && func_72() && func_73() && func_74() && func_75() && func_76() && func_77() && func_78() && func_79() && func_80() && func_81() && func_82() && func_83() && func_84() && func_85() && func_86() && func_87() && func_88() && func_89() && func_90() && func_91() && func_92() && func_93() && func_94() && func_95() && func_96() && func_97() && func_98() && func_99()) == 1; +} + diff --git a/examples/hw1/cond_and_loop.c b/examples/hw1/cond_and_loop.c new file mode 100644 index 0000000..a902561 --- /dev/null +++ b/examples/hw1/cond_and_loop.c @@ -0,0 +1,13 @@ +int main() { + int i; + int p = 2; + int q = 5; + int r = (0 ? ((p > q) ? (p -= 2) : (p += 2)) : (p + q)); + + for (i = 0; i < 11; ((i % 2) ? (i += 2) : ++i)) { + if (i % 2) { p += q; } + else { p += r; } + } + + return p == 34; +} diff --git a/examples/hw1/gcd.c b/examples/hw1/gcd.c new file mode 100644 index 0000000..7c64ed6 --- /dev/null +++ b/examples/hw1/gcd.c @@ -0,0 +1,15 @@ +int gcd(int a, int b) { + a = (a > 0) ? a : -a; + b = (b > 0) ? b : -b; + + while(a != b) { + if(a > b) { a -= b; } + else { b -= a; } + } + + return a; +} + +int main() { + return gcd(18, 21) == 3; +} diff --git a/examples/meta/make_cond.py b/examples/meta/make_cond.py new file mode 100644 index 0000000..4cf8b22 --- /dev/null +++ b/examples/meta/make_cond.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 + +"""Make c program which uses complicated conditional expression + +To make c program, execute `python3 make_cond.py > file_name.c` +""" + +import random + +def eval_cond(arr_cond): + """Evaluate conditional expression + """ + if len(arr_cond) == 1: + return arr_cond[0] + new_arr_cond = [] + for cond_start in range(len(arr_cond) // 3): + cond_val = arr_cond[3*cond_start + 1] if arr_cond[3*cond_start] else arr_cond[3*cond_start + 2] + new_arr_cond.append(cond_val) + return eval_cond(new_arr_cond) + +def make_func(i): + """Make a function that contains a conditional expression + """ + func_signature = "int " + "func_" + str(i) + "()" + variables = "abcdefghijklmnopqrstuvwxyzA" + func_inner = [] + val_bitmap = [] + + # Variable initializiation + for var in variables: + val = random.randint(0, 1) + val_bitmap.append(val) + decl = "\tint " + var + " = " + str(val) + ";" + func_inner.append(decl) + + expr_val = eval_cond(val_bitmap) + func_inner.append("\treturn (((a ? b : c) ? (d ? e : f) : (g ? h : i)) ? ((j ? k : l) ? (m ? n : o) : (p ? q : r)) : ((s ? t : u) ? (v ? w : x) : (y ? z : A))) == " + str(expr_val) + ";") + + return "\n".join([func_signature, "{"] + func_inner + ["}"]) + +if __name__ == "__main__": + src = "" + return_stmt = "\treturn (" + NUM_FUNC = 100 + for i in range(NUM_FUNC): + src += make_func(i) + src += "\n\n" + return_stmt += "func_" + str(i) + "()" + return_stmt += " && " if i != (NUM_FUNC - 1) else ") == " + return_stmt += "1;" + src += "int main()\n{\n" + return_stmt + "\n}\n" + + print(src) diff --git a/examples/simple_cond.c b/examples/simple_cond.c new file mode 100644 index 0000000..30c4a12 --- /dev/null +++ b/examples/simple_cond.c @@ -0,0 +1,10 @@ +int f(int x) { + return x + 8; +} + +int main() { + int x = 0; + int y = (x++ == 1) ? 1 : 2; + + return f((x < y) ? x : 2) == 9; +} diff --git a/scripts/copy-to-kecc-public.sh b/scripts/copy-to-kecc-public.sh new file mode 100755 index 0000000..b679503 --- /dev/null +++ b/scripts/copy-to-kecc-public.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +rsync --exclude=".git" --delete --archive ./ ../kecc-public diff --git a/scripts/make-public.py b/scripts/make-public.py index dac0c63..7210d27 100755 --- a/scripts/make-public.py +++ b/scripts/make-public.py @@ -11,8 +11,9 @@ import sys import re if __name__ == "__main__": - for fullname in os.listdir("src"): - (filename, ext) = os.path.splitext(fullname) + for root, dir, files in os.walk("src"): + for f in files: + (filename, ext) = os.path.splitext(f) - if ext == ".public": - os.rename(os.path.join("src", fullname), os.path.join("src", filename)) + if ext == ".public": + os.rename(os.path.join(root, f), os.path.join(root, filename)) diff --git a/src/asm.rs b/src/asm/mod.rs similarity index 62% rename from src/asm.rs rename to src/asm/mod.rs index 7af62f9..4f8b963 100644 --- a/src/asm.rs +++ b/src/asm/mod.rs @@ -1,2 +1,4 @@ +mod write_asm; + /// TODO pub struct Asm {} diff --git a/src/asm/write_asm.rs b/src/asm/write_asm.rs new file mode 100644 index 0000000..16839cc --- /dev/null +++ b/src/asm/write_asm.rs @@ -0,0 +1,10 @@ +use std::io::{Result, Write}; + +use crate::asm::Asm; +use crate::write_base::WriteLine; + +impl WriteLine for Asm { + fn write_line(&self, _indent: usize, _write: &mut dyn Write) -> Result<()> { + todo!() + } +} diff --git a/src/codegen.rs b/src/asmgen/mod.rs similarity index 70% rename from src/codegen.rs rename to src/asmgen/mod.rs index 20ee581..1171193 100644 --- a/src/codegen.rs +++ b/src/asmgen/mod.rs @@ -3,13 +3,13 @@ use crate::ir; use crate::Translate; #[derive(Default)] -pub struct Codegen {} +pub struct Asmgen {} -impl Translate for Codegen { +impl Translate for Asmgen { type Target = Asm; type Error = (); fn translate(&mut self, _source: &ir::TranslationUnit) -> Result { - unimplemented!() + todo!() } } diff --git a/src/assert_ast_equiv.rs b/src/c/ast_equiv.rs similarity index 99% rename from src/assert_ast_equiv.rs rename to src/c/ast_equiv.rs index 8f9a566..dcb8ae5 100644 --- a/src/assert_ast_equiv.rs +++ b/src/c/ast_equiv.rs @@ -3,7 +3,7 @@ use lang_c::ast::*; use lang_c::span::Node; -use std::ops::Deref; +use core::ops::Deref; use itertools::izip; diff --git a/src/c/mod.rs b/src/c/mod.rs new file mode 100644 index 0000000..106f998 --- /dev/null +++ b/src/c/mod.rs @@ -0,0 +1,6 @@ +mod ast_equiv; +mod parse; +mod write_c; + +pub use ast_equiv::assert_ast_equiv; +pub use parse::Parse; diff --git a/src/parse.rs b/src/c/parse.rs similarity index 96% rename from src/parse.rs rename to src/c/parse.rs index bc2c953..ee6ceac 100644 --- a/src/parse.rs +++ b/src/c/parse.rs @@ -1,4 +1,4 @@ -use std::ops::Deref; +use core::ops::Deref; use std::path::Path; use lang_c::ast::*; @@ -10,6 +10,7 @@ use crate::Translate; #[derive(Debug)] pub enum Error { ParseError(ParseError), + #[allow(dead_code)] Unsupported, } @@ -101,7 +102,9 @@ impl AssertSupported for FunctionDefinition { impl AssertSupported for DeclarationSpecifier { fn assert_supported(&self) { match self { - Self::StorageClass(_) => panic!("DeclarationSpecifier::StorageClass"), + Self::StorageClass(storage_class_specifier) => { + storage_class_specifier.assert_supported() + } Self::TypeSpecifier(type_specifier) => type_specifier.assert_supported(), Self::TypeQualifier(type_qualifier) => type_qualifier.assert_supported(), Self::Function(_) => panic!("DeclarationSpecifier::Function"), @@ -111,6 +114,15 @@ impl AssertSupported for DeclarationSpecifier { } } +impl AssertSupported for StorageClassSpecifier { + fn assert_supported(&self) { + match self { + Self::Typedef => (), + _ => panic!("StorageClassifier other than Typedef"), + } + } +} + impl AssertSupported for TypeSpecifier { fn assert_supported(&self) { match self { @@ -128,7 +140,7 @@ impl AssertSupported for TypeSpecifier { Self::Atomic(_) => panic!("TypeSpecifier::Atomic"), Self::Struct(struct_type) => struct_type.assert_supported(), Self::Enum(_) => panic!("TypeSpecifier::Enum"), - Self::TypedefName(_) => panic!("TypeSpecifier::TypedefName"), + Self::TypedefName(_) => (), Self::TypeOf(_) => panic!("TypeSpecifier::TypeOf"), Self::TS18661Float(_) => panic!("TypeSpecifier::TS18661Float"), } @@ -271,7 +283,7 @@ impl AssertSupported for ParameterDeclaration { impl AssertSupported for DeclaratorKind { fn assert_supported(&self) { match self { - Self::Abstract => panic!("DeclaratorKind::Abstract"), + Self::Abstract => (), Self::Identifier(_) => (), Self::Declarator(decl) => decl.assert_supported(), } @@ -415,8 +427,8 @@ impl AssertSupported for Expression { match self { Self::Identifier(_) => (), Self::Constant(constant) => constant.assert_supported(), - Self::StringLiteral(_) => panic!("Expression:StringLiteral"), - Self::GenericSelection(_) => panic!("Expression:GenericSelection"), + Self::StringLiteral(_) => panic!("Expression::StringLiteral"), + Self::GenericSelection(_) => panic!("Expression::GenericSelection"), Self::Member(member) => member.assert_supported(), Self::Call(call) => call.assert_supported(), Self::CompoundLiteral(_) => panic!("Expression::CompoundLiteral"), @@ -531,11 +543,7 @@ impl AssertSupported for FloatFormat { } impl AssertSupported for UnaryOperator { - fn assert_supported(&self) { - if let Self::SizeOf = self { - panic!("UnaryOperaotr::SizeOf") - } - } + fn assert_supported(&self) {} } impl AssertSupported for BinaryOperator { diff --git a/src/write_c.rs b/src/c/write_c.rs similarity index 88% rename from src/write_c.rs rename to src/c/write_c.rs index bbb5878..a701c2b 100644 --- a/src/write_c.rs +++ b/src/c/write_c.rs @@ -1,8 +1,8 @@ use lang_c::ast::*; use lang_c::span::Node; +use core::ops::Deref; use std::io::{Result, Write}; -use std::ops::Deref; use crate::write_base::*; @@ -45,7 +45,3 @@ impl WriteLine for TranslationUnit { todo!("homework 1") } } - -pub fn write_c(unit: &TranslationUnit, write: &mut dyn Write) -> Result<()> { - unit.write_line(0, write) -} diff --git a/src/ir.rs b/src/ir.rs deleted file mode 100644 index 8ac9a1f..0000000 --- a/src/ir.rs +++ /dev/null @@ -1,1096 +0,0 @@ -use core::fmt; -use itertools::izip; -use lang_c::ast; -use lang_c::span::Node; -use std::collections::HashMap; -use std::hash::{Hash, Hasher}; -use std::ops::Deref; - -use failure::Fail; - -pub trait HasDtype { - fn dtype(&self) -> Dtype; -} - -#[derive(Debug, PartialEq, Fail)] -pub enum DtypeError { - /// For uncommon error - #[fail(display = "{}", message)] - Misc { message: String }, -} - -#[derive(Debug, PartialEq)] -pub struct TranslationUnit { - pub decls: HashMap, -} - -#[derive(Debug, PartialEq, Clone)] -pub enum Declaration { - Variable { - dtype: Dtype, - initializer: Option, - }, - Function { - signature: FunctionSignature, - definition: Option, - }, -} - -impl Declaration { - /// Create an appropriate declaration according to `dtype`. - /// - /// # Example - /// - /// If `int g = 0;` is declared, `dtype` is - /// `ir::Dtype::Int{ width:32, is_signed:true, is_const:false }`. - /// In this case, `ir::Declaration::Variable{ dtype, initializer: Some(Constant::I32(1)) }` - /// is generated. - /// - /// Conversely, if `int foo();` is declared, `dtype` is - /// `ir::Dtype::Function{ret: Scalar(Int), params: []}`. - /// Thus, in this case, `ir::Declaration::Function` is generated. - pub fn from_dtype(dtype: Dtype) -> Result { - match &dtype { - Dtype::Unit { .. } => Err(DtypeError::Misc { - message: "storage size of `void` isn't known".to_string(), - }), - Dtype::Int { .. } | Dtype::Float { .. } | Dtype::Pointer { .. } => { - Ok(Declaration::Variable { - dtype, - initializer: None, - }) - } - Dtype::Function { .. } => Ok(Declaration::Function { - signature: FunctionSignature::new(dtype), - definition: None, - }), - } - } - - pub fn get_variable(&self) -> Option<(&Dtype, &Option)> { - if let Self::Variable { dtype, initializer } = self { - Some((dtype, initializer)) - } else { - None - } - } - - pub fn get_function(&self) -> Option<(&FunctionSignature, &Option)> { - if let Self::Function { - signature, - definition, - } = self - { - Some((signature, definition)) - } else { - None - } - } - - /// Check if type is conflicting for pre-declared one - /// - /// In case of `Variable`, need to check if the two types are exactly the same. - /// On the other hand, in the case of `Function`, outermost `const` of return type and - /// parameters one is not an issue of concern. - pub fn is_compatible(&self, other: &Declaration) -> bool { - match (self, other) { - (Self::Variable { dtype, .. }, Self::Variable { dtype: other, .. }) => dtype == other, - ( - Self::Function { signature, .. }, - Self::Function { - signature: other, .. - }, - ) => signature.dtype().is_compatible(&other.dtype()), - _ => false, - } - } -} - -impl HasDtype for Declaration { - fn dtype(&self) -> Dtype { - match self { - Self::Variable { dtype, .. } => dtype.clone(), - Self::Function { signature, .. } => signature.dtype(), - } - } -} - -#[derive(Debug, PartialEq, Clone)] -pub struct FunctionDefinition { - /// Element that must allocate memory before a function can be executed - pub allocations: Vec, - pub blocks: HashMap, - pub bid_init: BlockId, -} - -#[derive(Debug, PartialEq, Clone)] -pub struct FunctionSignature { - pub ret: Dtype, - pub params: Vec, -} - -impl FunctionSignature { - pub fn new(dtype: Dtype) -> Self { - let (ret, params) = dtype - .get_function_inner() - .expect("function signature's dtype must be function type"); - Self { - ret: ret.clone(), - params: params.clone(), - } - } -} - -impl HasDtype for FunctionSignature { - fn dtype(&self) -> Dtype { - Dtype::function(self.ret.clone(), self.params.clone()) - } -} - -#[derive(Default)] -struct Specifier { - scalar: Option, - signed_option: Option, - is_const: bool, -} - -impl Specifier { - #[inline] - fn analyze_ast_type_specifiers( - &mut self, - type_specifier: &ast::TypeSpecifier, - ) -> Result<(), DtypeError> { - match type_specifier { - ast::TypeSpecifier::Unsigned | ast::TypeSpecifier::Signed => { - if self.signed_option.is_some() { - return Err(DtypeError::Misc { - message: "duplicate signed option".to_string(), - }); - } - self.signed_option = Some(type_specifier.clone()); - } - ast::TypeSpecifier::Void - | ast::TypeSpecifier::Char - | ast::TypeSpecifier::Int - | ast::TypeSpecifier::Float => { - if self.scalar.is_some() { - return Err(DtypeError::Misc { - message: "two or more scalar types in declaration specifiers".to_string(), - }); - } - self.scalar = Some(type_specifier.clone()); - } - _ => todo!("support more like `double` in the future"), - } - - Ok(()) - } - - #[inline] - fn analyze_ast_type_qualifier( - &mut self, - type_qualifier: &ast::TypeQualifier, - ) -> Result<(), DtypeError> { - match type_qualifier { - ast::TypeQualifier::Const => { - // duplicate `const` is allowed - self.is_const = true; - } - _ => panic!("type qualifier is unsupported except `const`"), - } - - Ok(()) - } - - pub fn from_ast_typename_specifier( - &mut self, - typename_specifier: &ast::SpecifierQualifier, - ) -> Result<(), DtypeError> { - match typename_specifier { - ast::SpecifierQualifier::TypeSpecifier(type_specifier) => { - self.analyze_ast_type_specifiers(&type_specifier.node)? - } - ast::SpecifierQualifier::TypeQualifier(type_qualifier) => { - self.analyze_ast_type_qualifier(&type_qualifier.node)? - } - } - - Ok(()) - } - - pub fn from_ast_declaration_specifier( - &mut self, - declaration_specifier: &ast::DeclarationSpecifier, - ) -> Result<(), DtypeError> { - match declaration_specifier { - // TODO: `dtype` must be defined taking into account all specifier information. - ast::DeclarationSpecifier::StorageClass(_storage_class_spec) => { - todo!("analyze storage class specifier keyword to create correct `dtype`") - } - ast::DeclarationSpecifier::TypeSpecifier(type_specifier) => { - self.analyze_ast_type_specifiers(&type_specifier.node)? - } - ast::DeclarationSpecifier::TypeQualifier(type_qualifier) => { - self.analyze_ast_type_qualifier(&type_qualifier.node)? - } - _ => panic!("is_unsupported"), - } - - Ok(()) - } - - pub fn from_ast_typename_specifiers( - typename_specifiers: &[Node], - ) -> Result { - let mut specifier = Specifier::default(); - - for ast_spec in typename_specifiers { - specifier.from_ast_typename_specifier(&ast_spec.node)?; - } - - Ok(specifier) - } - - pub fn from_ast_declaration_specifiers( - declaration_specifiers: &[Node], - ) -> Result { - let mut specifier = Specifier::default(); - - for ast_spec in declaration_specifiers { - specifier.from_ast_declaration_specifier(&ast_spec.node)?; - } - - Ok(specifier) - } -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub enum Dtype { - Unit { - is_const: bool, - }, - Int { - width: usize, - is_signed: bool, - is_const: bool, - }, - Float { - width: usize, - is_const: bool, - }, - Pointer { - inner: Box, - is_const: bool, - }, - Function { - ret: Box, - params: Vec, - }, -} - -impl Dtype { - pub const BOOL: Self = Self::int(1); - pub const CHAR: Self = Self::int(8); - pub const SHORT: Self = Self::int(16); - pub const INT: Self = Self::int(32); - pub const LONG: Self = Self::int(64); - pub const LONGLONG: Self = Self::int(64); - - pub const FLOAT: Self = Self::float(32); - pub const DOUBLE: Self = Self::float(64); - - const WIDTH_OF_BYTE: usize = 8; - // TODO: consider architecture dependency in the future - const WIDTH_OF_POINTER: usize = 32; - - #[inline] - pub fn unit() -> Self { - Self::Unit { is_const: false } - } - - #[inline] - const fn int(width: usize) -> Self { - Self::Int { - width, - is_signed: true, - is_const: false, - } - } - - #[inline] - const fn float(width: usize) -> Self { - Self::Float { - width, - is_const: false, - } - } - - #[inline] - pub fn pointer(inner: Dtype) -> Self { - Self::Pointer { - inner: Box::new(inner), - is_const: false, - } - } - - #[inline] - pub fn function(ret: Dtype, params: Vec) -> Self { - Self::Function { - ret: Box::new(ret), - params, - } - } - - #[inline] - pub fn get_int_width(&self) -> Option { - if let Self::Int { width, .. } = self { - Some(*width) - } else { - None - } - } - - #[inline] - pub fn get_float_width(&self) -> Option { - if let Self::Float { width, .. } = self { - Some(*width) - } else { - None - } - } - - #[inline] - pub fn get_pointer_inner(&self) -> Option<&Dtype> { - if let Self::Pointer { inner, .. } = self { - Some(inner.deref()) - } else { - None - } - } - - #[inline] - pub fn get_function_inner(&self) -> Option<(&Dtype, &Vec)> { - if let Self::Function { ret, params } = self { - Some((ret.deref(), params)) - } else { - None - } - } - - #[inline] - pub fn is_scalar(&self) -> bool { - match self { - Self::Unit { .. } => todo!(), - Self::Int { .. } => true, - Self::Float { .. } => true, - _ => false, - } - } - - #[inline] - pub fn is_signed(&self) -> bool { - match self { - Self::Int { is_signed, .. } => *is_signed, - _ => panic!("only `Dtype::Int` can be judged whether it is sigend"), - } - } - - #[inline] - pub fn is_const(&self) -> bool { - match self { - Self::Unit { is_const } => *is_const, - Self::Int { is_const, .. } => *is_const, - Self::Float { is_const, .. } => *is_const, - Self::Pointer { is_const, .. } => *is_const, - Self::Function { .. } => { - panic!("there should be no case that check whether `Function` is `const`") - } - } - } - - /// Derive a data type containing scalar type from type specifier. - pub fn from_ast_type_specifier(type_specifier: &ast::TypeSpecifier) -> Self { - match type_specifier { - ast::TypeSpecifier::Void => Self::unit(), - ast::TypeSpecifier::Unsigned | ast::TypeSpecifier::Signed => { - panic!("signed option to scalar is not supported") - } - ast::TypeSpecifier::Bool => Self::BOOL, - ast::TypeSpecifier::Char => Self::CHAR, - ast::TypeSpecifier::Short => Self::SHORT, - ast::TypeSpecifier::Int => Self::INT, - ast::TypeSpecifier::Long => Self::LONG, - ast::TypeSpecifier::Float => Self::FLOAT, - ast::TypeSpecifier::Double => Self::DOUBLE, - _ => panic!("is unsupported"), - } - } - - /// Apply signed option to `Dtype`. - pub fn apply_signed_option( - self, - signed_option: &ast::TypeSpecifier, - ) -> Result { - let is_signed = match signed_option { - ast::TypeSpecifier::Signed => true, - ast::TypeSpecifier::Unsigned => false, - _ => panic!( - "`signed_option` must be `TypeSpecifier::Signed` or `TypeSpecifier::Unsigned`" - ), - }; - - match self { - Self::Unit { .. } => Err(DtypeError::Misc { - message: "`void` cannot matched with signed option".to_string(), - }), - Self::Int { - width, is_const, .. - } => Ok(Self::int(width).set_signed(is_signed).set_const(is_const)), - Self::Float { .. } => Err(DtypeError::Misc { - message: "floating point cannot matched with signed option".to_string(), - }), - Self::Pointer { .. } | Self::Function { .. } => { - panic!("cannot apply signed option to `Self::Pointer` and `Self::Function`") - } - } - } - - pub fn set_const(self, is_const: bool) -> Self { - match self { - Self::Unit { .. } => Self::Unit { is_const }, - Self::Int { - width, is_signed, .. - } => Self::Int { - width, - is_signed, - is_const, - }, - Self::Float { width, .. } => Self::Float { width, is_const }, - Self::Pointer { inner, .. } => Self::Pointer { inner, is_const }, - Self::Function { .. } => panic!("`const` cannot be applied to `Dtype::Function`"), - } - } - - /// Return byte size of `Dtype` - pub fn size_of(&self) -> Result { - // TODO: consider complex type like array, structure in the future - match self { - Self::Unit { .. } => Ok(0), - Self::Int { width, .. } => Ok(*width / Self::WIDTH_OF_BYTE), - Self::Float { width, .. } => Ok(*width / Self::WIDTH_OF_BYTE), - Self::Pointer { .. } => Ok(Self::WIDTH_OF_POINTER / Self::WIDTH_OF_BYTE), - Self::Function { .. } => Err(DtypeError::Misc { - message: "`sizeof` cannot be used with function types".to_string(), - }), - } - } - - /// Return alignment requirements of `Dtype` - pub fn align_of(&self) -> Result { - // TODO: consider complex type like array, structure in the future - // TODO: when considering complex type like a structure, - // the calculation method should be different from `Dtype::size_of`. - match self { - Self::Unit { .. } => Ok(0), - Self::Int { width, .. } => Ok(*width / Self::WIDTH_OF_BYTE), - Self::Float { width, .. } => Ok(*width / Self::WIDTH_OF_BYTE), - Self::Pointer { .. } => Ok(Self::WIDTH_OF_POINTER / Self::WIDTH_OF_BYTE), - Self::Function { .. } => Err(DtypeError::Misc { - message: "`alignof` cannot be used with function types".to_string(), - }), - } - } - - pub fn set_signed(self, is_signed: bool) -> Self { - match self { - Self::Int { - width, is_const, .. - } => Self::Int { - width, - is_signed, - is_const, - }, - _ => panic!("`signed` and `unsigned` only be applied to `Dtype::Int`"), - } - } - - /// Derive a data type from typename. - pub fn from_ast_typename(type_name: &ast::TypeName) -> Result { - let spec = Specifier::from_ast_typename_specifiers(&type_name.specifiers)?; - let base_dtype = Self::from_ast_specifiers(spec)?; - - if let Some(declarator) = &type_name.declarator { - Self::from_ast_declarator(&declarator.node, base_dtype) - } else { - Ok(base_dtype) - } - } - - /// Derive a data type from declaration specifiers. - pub fn from_ast_declaration_specifiers( - specifiers: &[Node], - ) -> Result { - let spec = Specifier::from_ast_declaration_specifiers(specifiers)?; - Self::from_ast_specifiers(spec) - } - - /// Derive a data type containing scalar type from specifiers. - /// - /// # Example - /// - /// For declaration is `const unsigned int * p`, `specifiers` is `const unsigned int`, - /// and the result is `Dtype::Int{ width: 32, is_signed: false, is_const: ture }` - fn from_ast_specifiers(spec: Specifier) -> Result { - // Generate appropriate `Dtype` object if `scalar` is `Some` - let dtype = spec.scalar.map(|t| Dtype::from_ast_type_specifier(&t)); - - // Update `dtype` obtained above or generate appropriate `Dtype` object if - let dtype = match (spec.signed_option, dtype) { - (Some(signed_option), Some(dtype)) => Some(dtype.apply_signed_option(&signed_option)?), - (Some(signed_option), None) => { - // If `signed_option` is used alone, it is used as`type_specifier`. - // For example, `signed` can be replaced with `int` if it used alone. - Some(Dtype::default().apply_signed_option(&signed_option)?) - } - (None, dtype) => dtype, - }; - - // Determining the final form of `dtype` according to the value of `is_const` - let dtype = match (dtype, spec.is_const) { - (Some(dtype), is_const) => { - assert!(!dtype.is_const()); - dtype.set_const(is_const) - } - // If type specifier missing, defaults to `int`. - // For example, `const` can be replaced with `const int` if it used alone. - (None, true) => Dtype::default().set_const(true), - (None, false) => { - panic!("at least one valid declaration specifier is needed to generate `Dtype`") - } - }; - - Ok(dtype) - } - - /// Generate `Dtype` based on pointer qualifiers and `base_dtype` which has scalar type. - /// - /// let's say declaration is `const int * const * const a;`. - /// If `base_dtype` represents `const int *`, - /// `qualifiers` represents `const` between first and second asterisk. - /// - /// The important point here is that `qualifiers` exists between asterisks and asterisks or - /// asterisks and identifiers. - /// - /// # Arguments - /// - /// * `qualifiers` - Pointer qualifiers requiring conversion to 'Dtype' immediately - /// * `base_dtype` - Part that has been converted to 'Dtype' on the declaration - /// - pub fn from_ast_pointer_qualifiers( - qualifiers: &[Node], - base_dtype: Self, - ) -> Result { - let mut specifier = Specifier::default(); - - for qualifier in qualifiers { - match &qualifier.node { - ast::PointerQualifier::TypeQualifier(type_qualifier) => { - specifier.analyze_ast_type_qualifier(&type_qualifier.node)?; - } - ast::PointerQualifier::Extension(_) => { - panic!("ast::PointerQualifier::Extension is unsupported") - } - } - } - - Ok(base_dtype.set_const(specifier.is_const)) - } - - /// Generate `Dtype` based on declarator and `base_dtype` which has scalar type. - /// - /// let's say declaration is `const int * const * const a;`. - /// In general `base_dtype` start with `const int` which has scalar type and - /// `declarator` represents `* const * const` with `ast::Declarator` - /// - /// # Arguments - /// - /// * `declarator` - Parts requiring conversion to 'Dtype' on the declaration - /// * `base_dtype` - Part that has been converted to 'Dtype' on the declaration - /// - pub fn from_ast_declarator( - declarator: &ast::Declarator, - base_dtype: Self, - ) -> Result { - let mut base_dtype = base_dtype; - - for derived_decl in &declarator.derived { - base_dtype = match &derived_decl.node { - ast::DerivedDeclarator::Pointer(pointer_qualifiers) => { - let ptr_dtype = Dtype::pointer(base_dtype); - Self::from_ast_pointer_qualifiers(pointer_qualifiers, ptr_dtype)? - } - ast::DerivedDeclarator::Array(_array_decl) => todo!(), - ast::DerivedDeclarator::Function(func_decl) => { - let params = func_decl - .node - .parameters - .iter() - .map(|p| Self::from_ast_parameter_declaration(&p.node)) - .collect::, _>>()?; - Self::function(base_dtype, params) - } - ast::DerivedDeclarator::KRFunction(kr_func_decl) => { - // K&R function is allowed only when it has no parameter - assert!(kr_func_decl.is_empty()); - Self::function(base_dtype, Vec::new()) - } - }; - } - - let declarator_kind = &declarator.kind; - match &declarator_kind.node { - ast::DeclaratorKind::Abstract => panic!("ast::DeclaratorKind::Abstract is unsupported"), - ast::DeclaratorKind::Identifier(_) => Ok(base_dtype), - ast::DeclaratorKind::Declarator(declarator) => { - Self::from_ast_declarator(&declarator.node, base_dtype) - } - } - } - - /// Generate `Dtype` based on parameter declaration - pub fn from_ast_parameter_declaration( - parameter_decl: &ast::ParameterDeclaration, - ) -> Result { - let spec = Specifier::from_ast_declaration_specifiers(¶meter_decl.specifiers)?; - let base_dtype = Self::from_ast_specifiers(spec)?; - - if let Some(declarator) = ¶meter_decl.declarator { - Self::from_ast_declarator(&declarator.node, base_dtype) - } else { - Ok(base_dtype) - } - } - - /// Check whether type conflict exists between the two `Dtype` objects. - /// - /// let's say expression is `const int a = 0; int b = 0; int c = a + b`. - /// Although `const int` of `a` and `int` of `b` looks different, `Plus`(+) operations between - /// these two types are possible without any type-casting. There is no conflict between - /// `const int` and `int`. - /// - /// However, only the outermost const is ignored. - /// If check equivalence between `const int *const` and `int *`, result is false. Because - /// the second `const` (means left most `const`) of the `const int *const` is missed in `int *`. - /// By the way, outermost `const` (means right most `const`) is not a consideration here. - pub fn is_compatible(&self, other: &Self) -> bool { - match (self, other) { - (Self::Unit { .. }, Self::Unit { .. }) - | (Self::Int { .. }, Self::Int { .. }) - | (Self::Float { .. }, Self::Float { .. }) - | (Self::Pointer { .. }, Self::Pointer { .. }) => { - self.clone().set_const(false) == other.clone().set_const(false) - } - ( - Self::Function { ret, params }, - Self::Function { - ret: other_ret, - params: other_params, - }, - ) => { - ret == other_ret - && params.len() == other_params.len() - && izip!(params, other_params).all(|(l, r)| l.is_compatible(r)) - } - _ => false, - } - } -} - -impl fmt::Display for Dtype { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Unit { is_const } => write!(f, "{}unit", if *is_const { "const " } else { "" }), - Self::Int { - width, - is_signed, - is_const, - } => write!( - f, - "{}{}{}", - if *is_const { "const " } else { "" }, - if *is_signed { "i" } else { "u" }, - width - ), - Self::Float { width, is_const } => { - write!(f, "{}f{}", if *is_const { "const " } else { "" }, width) - } - Self::Pointer { inner, is_const } => { - write!(f, "{}* {}", inner, if *is_const { "const" } else { "" }) - } - Self::Function { ret, params } => write!( - f, - "{} ({})", - ret, - params - .iter() - .map(|p| p.to_string()) - .collect::>() - .join(", ") - ), - } - } -} - -impl Default for Dtype { - fn default() -> Self { - // default dtype is `int`(i32) - Self::INT - } -} - -#[derive(Debug, Eq, Clone)] -pub enum RegisterId { - // `name` field of `Local` is unnecessary, but it is helpful when read printed IR - Local { name: String, id: usize }, - Arg { id: usize }, - Temp { bid: BlockId, iid: usize }, -} - -impl RegisterId { - pub fn local(name: String, id: usize) -> Self { - Self::Local { name, id } - } - - pub fn arg(id: usize) -> Self { - Self::Arg { id } - } - - pub fn temp(bid: BlockId, iid: usize) -> Self { - Self::Temp { bid, iid } - } -} - -impl fmt::Display for RegisterId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Local { name, id } => write!(f, "%(local:{}:{})", name, id), - Self::Arg { id } => write!(f, "%(arg:{})", id), - Self::Temp { bid, iid } => write!(f, "%({}:{})", bid, iid), - } - } -} - -impl PartialEq for RegisterId { - fn eq(&self, other: &RegisterId) -> bool { - match (self, other) { - (Self::Local { id, .. }, Self::Local { id: other_id, .. }) => id == other_id, - (Self::Arg { id }, Self::Arg { id: other_id }) => id == other_id, - ( - Self::Temp { bid, iid }, - Self::Temp { - bid: other_bid, - iid: other_iid, - }, - ) => bid == other_bid && iid == other_iid, - _ => false, - } - } -} - -impl Hash for RegisterId { - fn hash(&self, state: &mut H) { - match self { - Self::Local { id, .. } => id.hash(state), - Self::Arg { id } => id.hash(state), - Self::Temp { bid, iid } => { - bid.hash(state); - iid.hash(state); - } - } - } -} - -#[derive(Debug, PartialEq, Clone)] -pub enum Constant { - Unit, - Int { - value: u128, - width: usize, - is_signed: bool, - }, - Float { - /// `value` may be `f32`, but it is possible to consider it as `f64`. - /// - /// * Casting from an f32 to an f64 is perfect and lossless (f32 -> f64) - /// * Casting from an f64 to an f32 will produce the closest possible value (f64 -> f32) - /// https://doc.rust-lang.org/stable/reference/expressions/operator-expr.html#type-cast-expressions - value: f64, - width: usize, - }, - GlobalVariable { - name: String, - dtype: Dtype, - }, -} - -impl Constant { - #[inline] - pub fn is_integer_constant(&self) -> bool { - if let Self::Int { .. } = self { - true - } else { - false - } - } - - pub fn unit() -> Self { - Constant::Unit - } - - #[inline] - pub fn int(value: u128, dtype: Dtype) -> Self { - let width = dtype.get_int_width().expect("`dtype` must be `Dtype::Int`"); - let is_signed = dtype.is_signed(); - - Constant::Int { - value, - width, - is_signed, - } - } - - #[inline] - pub fn float(value: f64, dtype: Dtype) -> Self { - let width = dtype - .get_float_width() - .expect("`dtype` must be `Dtype::Float`"); - - Constant::Float { value, width } - } - - #[inline] - pub fn global_variable(name: String, dtype: Dtype) -> Self { - Self::GlobalVariable { name, dtype } - } - - pub fn from_ast(constant: &ast::Constant) -> Self { - match constant { - ast::Constant::Integer(integer) => { - let is_signed = !integer.suffix.unsigned; - - let dtype = match integer.suffix.size { - ast::IntegerSize::Int => Dtype::INT, - ast::IntegerSize::Long => Dtype::LONG, - ast::IntegerSize::LongLong => Dtype::LONGLONG, - } - .set_signed(is_signed); - - let value = if is_signed { - integer.number.parse::().unwrap() as u128 - } else { - integer.number.parse::().unwrap() - }; - - Self::int(value, dtype) - } - ast::Constant::Float(float) => { - let (dtype, value) = match float.suffix.format { - ast::FloatFormat::Float => { - // Casting from an f32 to an f64 is perfect and lossless (f32 -> f64) - // https://doc.rust-lang.org/stable/reference/expressions/operator-expr.html#type-cast-expressions - (Dtype::FLOAT, float.number.parse::().unwrap() as f64) - } - ast::FloatFormat::Double => { - (Dtype::DOUBLE, float.number.parse::().unwrap()) - } - ast::FloatFormat::LongDouble => { - panic!("`FloatFormat::LongDouble` is_unsupported") - } - ast::FloatFormat::TS18661Format(_) => { - panic!("`FloatFormat::TS18661Format` is_unsupported") - } - }; - - Self::float(value, dtype) - } - ast::Constant::Character(character) => { - let dtype = Dtype::CHAR; - let value = character.parse::().unwrap() as u128; - - Self::int(value, dtype) - } - } - } - - #[inline] - pub fn from_ast_expression(expr: &ast::Expression) -> Option { - if let ast::Expression::Constant(constant) = expr { - Some(Self::from_ast(&constant.node)) - } else { - None - } - } - - #[inline] - pub fn from_ast_initializer(initializer: &ast::Initializer) -> Option { - if let ast::Initializer::Expression(expr) = &initializer { - Self::from_ast_expression(&expr.node) - } else { - None - } - } -} - -impl fmt::Display for Constant { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Unit => write!(f, "unit"), - Self::Int { value, .. } => write!(f, "{}", value), - Self::Float { value, .. } => write!(f, "{}", value), - Self::GlobalVariable { name, .. } => write!(f, "%{}", name), - } - } -} - -impl HasDtype for Constant { - fn dtype(&self) -> Dtype { - match self { - Self::Unit => Dtype::unit(), - Self::Int { - width, is_signed, .. - } => Dtype::int(*width).set_signed(*is_signed), - Self::Float { width, .. } => Dtype::float(*width), - Self::GlobalVariable { dtype, .. } => Dtype::pointer(dtype.clone()), - } - } -} - -#[derive(Debug, PartialEq, Clone)] -pub enum Operand { - Constant(Constant), - Register { rid: RegisterId, dtype: Dtype }, -} - -impl Operand { - pub fn constant(value: Constant) -> Self { - Self::Constant(value) - } - - pub fn register(rid: RegisterId, dtype: Dtype) -> Self { - Self::Register { rid, dtype } - } - - pub fn get_register(&self) -> Option<(RegisterId, Dtype)> { - if let Self::Register { rid, dtype } = self { - Some((rid.clone(), dtype.clone())) - } else { - None - } - } -} - -impl fmt::Display for Operand { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Constant(value) => write!(f, "{}", value), - Self::Register { rid, .. } => write!(f, "{}", rid), - } - } -} - -impl HasDtype for Operand { - fn dtype(&self) -> Dtype { - match self { - Self::Constant(value) => value.dtype(), - Self::Register { dtype, .. } => dtype.clone(), - } - } -} - -#[derive(Debug, PartialEq, Clone)] -pub enum Instruction { - // TODO: the variants of Instruction will be added in the future - BinOp { - op: ast::BinaryOperator, - lhs: Operand, - rhs: Operand, - dtype: Dtype, - }, - UnaryOp { - op: ast::UnaryOperator, - operand: Operand, - dtype: Dtype, - }, - Store { - ptr: Operand, - value: Operand, - }, - Load { - ptr: Operand, - }, - Call { - callee: Operand, - args: Vec, - return_type: Dtype, - }, - TypeCast { - value: Operand, - target_dtype: Dtype, - }, -} - -impl HasDtype for Instruction { - fn dtype(&self) -> Dtype { - match self { - Self::BinOp { dtype, .. } => dtype.clone(), - Self::UnaryOp { dtype, .. } => dtype.clone(), - Self::Store { .. } => Dtype::unit(), - Self::Load { ptr } => ptr - .dtype() - .get_pointer_inner() - .expect("Load instruction must have pointer value as operand") - .deref() - .clone() - .set_const(false), - Self::Call { return_type, .. } => return_type.clone(), - Self::TypeCast { target_dtype, .. } => target_dtype.clone(), - } - } -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -pub struct BlockId(pub usize); - -impl fmt::Display for BlockId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "b{}", self.0) - } -} - -// TODO -#[derive(Debug, PartialEq, Clone)] -pub enum BlockExit { - Jump { - bid: BlockId, - }, - ConditionalJump { - condition: Operand, - bid_then: BlockId, - bid_else: BlockId, - }, - Switch { - value: Operand, - default: BlockId, - cases: Vec<(Constant, BlockId)>, - }, - Return { - value: Operand, - }, - Unreachable, -} - -#[derive(Debug, PartialEq, Clone)] -pub struct Block { - pub instructions: Vec, - pub exit: BlockExit, -} diff --git a/src/ir/dtype.rs b/src/ir/dtype.rs new file mode 100644 index 0000000..71804ea --- /dev/null +++ b/src/ir/dtype.rs @@ -0,0 +1,612 @@ +use core::convert::TryFrom; +use core::fmt; +use core::ops::Deref; +use itertools::izip; +use lang_c::ast; +use lang_c::span::Node; +use std::hash::Hash; + +use failure::Fail; + +#[derive(Debug, PartialEq, Fail)] +pub enum DtypeError { + /// For uncommon error + #[fail(display = "{}", message)] + Misc { message: String }, +} + +pub trait HasDtype { + fn dtype(&self) -> Dtype; +} + +#[derive(Default)] +struct BaseDtype { + scalar: Option, + signed_option: Option, + is_const: bool, +} + +#[derive(Debug, PartialEq, Eq, Hash, Clone)] +pub enum Dtype { + Unit { + is_const: bool, + }, + Int { + width: usize, + is_signed: bool, + is_const: bool, + }, + Float { + width: usize, + is_const: bool, + }, + Pointer { + inner: Box, + is_const: bool, + }, + Function { + ret: Box, + params: Vec, + }, +} + +impl BaseDtype { + /// Apply `TypeSpecifier` to `BaseDtype` + /// + /// let's say declaration is `const int a;`, if `self` represents `int` + /// and `type_specifier` represents `const`, `self` is transformed to + /// representing `const int` after function performs. + /// + /// # Arguments + /// + /// * `self` - Part that has been converted to 'BaseDtype' on the declaration + /// * `type_qualifier` - type qualifiers requiring apply to 'self' immediately + /// + #[inline] + fn apply_type_specifier( + &mut self, + type_specifier: &ast::TypeSpecifier, + ) -> Result<(), DtypeError> { + match type_specifier { + ast::TypeSpecifier::Unsigned | ast::TypeSpecifier::Signed => { + if self.signed_option.is_some() { + return Err(DtypeError::Misc { + message: "duplicate signed option".to_string(), + }); + } + self.signed_option = Some(type_specifier.clone()); + } + ast::TypeSpecifier::Void + | ast::TypeSpecifier::Char + | ast::TypeSpecifier::Int + | ast::TypeSpecifier::Float => { + if self.scalar.is_some() { + return Err(DtypeError::Misc { + message: "two or more scalar types in declaration specifiers".to_string(), + }); + } + self.scalar = Some(type_specifier.clone()); + } + _ => todo!("support more like `double` in the future"), + } + + Ok(()) + } + + /// Apply `Typequalifier` to `BaseDtype` + /// + /// let's say declaration is `const int a;`, if `self` represents `int` + /// and `type_qualifier` represents `const`, `self` is transformed to + /// representing `const int` after function performs. + /// + /// # Arguments + /// + /// * `self` - Part that has been converted to 'BaseDtype' on the declaration + /// * `type_qualifier` - type qualifiers requiring apply to 'self' immediately + /// + #[inline] + fn apply_type_qualifier( + &mut self, + type_qualifier: &ast::TypeQualifier, + ) -> Result<(), DtypeError> { + match type_qualifier { + ast::TypeQualifier::Const => { + // duplicate `const` is allowed + self.is_const = true; + } + _ => panic!("type qualifier is unsupported except `const`"), + } + + Ok(()) + } + + pub fn apply_typename_specifier( + &mut self, + typename_specifier: &ast::SpecifierQualifier, + ) -> Result<(), DtypeError> { + match typename_specifier { + ast::SpecifierQualifier::TypeSpecifier(type_specifier) => { + self.apply_type_specifier(&type_specifier.node)? + } + ast::SpecifierQualifier::TypeQualifier(type_qualifier) => { + self.apply_type_qualifier(&type_qualifier.node)? + } + } + + Ok(()) + } + + pub fn apply_declaration_specifier( + &mut self, + declaration_specifier: &ast::DeclarationSpecifier, + ) -> Result<(), DtypeError> { + match declaration_specifier { + // TODO: `dtype` must be defined taking into account all specifier information. + ast::DeclarationSpecifier::StorageClass(_storage_class_spec) => { + todo!("analyze storage class specifier keyword to create correct `dtype`") + } + ast::DeclarationSpecifier::TypeSpecifier(type_specifier) => { + self.apply_type_specifier(&type_specifier.node)? + } + ast::DeclarationSpecifier::TypeQualifier(type_qualifier) => { + self.apply_type_qualifier(&type_qualifier.node)? + } + _ => panic!("is_unsupported"), + } + + Ok(()) + } + + /// Apply `PointerQualifier` to `BaseDtype` + /// + /// let's say pointer declarator is `* const` of `const int * const a;`. + /// If `self` represents nothing, and `pointer_qualifier` represents `const` + /// between first and second asterisk, `self` is transformed to + /// representing `const` after function performs. This information is used later + /// when generating `Dtype`. + /// + /// # Arguments + /// + /// * `self` - Part that has been converted to 'BaseDtype' on the pointer declarator + /// * `pointer_qualifier` - Pointer qualifiers requiring apply to 'BaseDtype' immediately + /// + pub fn apply_pointer_qualifier( + &mut self, + pointer_qualifier: &ast::PointerQualifier, + ) -> Result<(), DtypeError> { + match pointer_qualifier { + ast::PointerQualifier::TypeQualifier(type_qualifier) => { + self.apply_type_qualifier(&type_qualifier.node)?; + } + ast::PointerQualifier::Extension(_) => { + panic!("ast::PointerQualifier::Extension is unsupported") + } + } + + Ok(()) + } + + pub fn apply_typename_specifiers( + &mut self, + typename_specifiers: &[Node], + ) -> Result<(), DtypeError> { + for ast_spec in typename_specifiers { + self.apply_typename_specifier(&ast_spec.node)?; + } + + Ok(()) + } + + pub fn apply_declaration_specifiers( + &mut self, + declaration_specifiers: &[Node], + ) -> Result<(), DtypeError> { + for ast_spec in declaration_specifiers { + self.apply_declaration_specifier(&ast_spec.node)?; + } + + Ok(()) + } +} + +impl TryFrom for Dtype { + type Error = DtypeError; + + /// Derive a data type containing scalar type from specifiers. + /// + /// # Example + /// + /// For declaration is `const unsigned int * p`, `specifiers` is `const unsigned int`, + /// and the result is `Dtype::Int{ width: 32, is_signed: false, is_const: ture }` + fn try_from(spec: BaseDtype) -> Result { + assert!( + !(spec.scalar.is_none() && spec.signed_option.is_none() && !spec.is_const), + "BaseDtype is empty" + ); + + // Creates `dtype` from scalar. + let mut dtype = if let Some(t) = spec.scalar { + match t { + ast::TypeSpecifier::Void => Self::unit(), + ast::TypeSpecifier::Unsigned | ast::TypeSpecifier::Signed => { + panic!("Signed option to scalar is not supported") + } + ast::TypeSpecifier::Bool => Self::BOOL, + ast::TypeSpecifier::Char => Self::CHAR, + ast::TypeSpecifier::Short => Self::SHORT, + ast::TypeSpecifier::Int => Self::INT, + ast::TypeSpecifier::Long => Self::LONG, + ast::TypeSpecifier::Float => Self::FLOAT, + ast::TypeSpecifier::Double => Self::DOUBLE, + _ => panic!("Unsupported ast::TypeSpecifier"), + } + } else { + Dtype::default() + }; + + // Applies signedness. + if let Some(signed_option) = spec.signed_option { + let is_signed = match signed_option { + ast::TypeSpecifier::Signed => true, + ast::TypeSpecifier::Unsigned => false, + _ => panic!( + "`signed_option` must be `TypeSpecifier::Signed` or `TypeSpecifier::Unsigned`" + ), + }; + + dtype = dtype.set_signed(is_signed); + } + + // Applies constness. + assert!(!dtype.is_const()); + dtype = dtype.set_const(spec.is_const); + + Ok(dtype) + } +} + +impl TryFrom<&ast::TypeName> for Dtype { + type Error = DtypeError; + + /// Derive a data type from typename. + fn try_from(type_name: &ast::TypeName) -> Result { + let mut spec = BaseDtype::default(); + BaseDtype::apply_typename_specifiers(&mut spec, &type_name.specifiers)?; + let mut dtype = Self::try_from(spec)?; + + if let Some(declarator) = &type_name.declarator { + dtype = dtype.with_ast_declarator(&declarator.node)?; + } + Ok(dtype) + } +} + +impl TryFrom<&ast::ParameterDeclaration> for Dtype { + type Error = DtypeError; + + /// Generate `Dtype` based on parameter declaration + fn try_from(parameter_decl: &ast::ParameterDeclaration) -> Result { + let mut spec = BaseDtype::default(); + BaseDtype::apply_declaration_specifiers(&mut spec, ¶meter_decl.specifiers)?; + let mut dtype = Self::try_from(spec)?; + + if let Some(declarator) = ¶meter_decl.declarator { + dtype = dtype.with_ast_declarator(&declarator.node)?; + } + Ok(dtype) + } +} + +impl Dtype { + pub const BOOL: Self = Self::int(1); + pub const CHAR: Self = Self::int(8); + pub const SHORT: Self = Self::int(16); + pub const INT: Self = Self::int(32); + pub const LONG: Self = Self::int(64); + pub const LONGLONG: Self = Self::int(64); + + pub const FLOAT: Self = Self::float(32); + pub const DOUBLE: Self = Self::float(64); + + const WIDTH_OF_BYTE: usize = 8; + // TODO: consider architecture dependency in the future + const WIDTH_OF_POINTER: usize = 32; + + #[inline] + pub const fn unit() -> Self { + Self::Unit { is_const: false } + } + + #[inline] + pub const fn int(width: usize) -> Self { + Self::Int { + width, + is_signed: true, + is_const: false, + } + } + + #[inline] + pub const fn float(width: usize) -> Self { + Self::Float { + width, + is_const: false, + } + } + + #[inline] + pub fn pointer(inner: Dtype) -> Self { + Self::Pointer { + inner: Box::new(inner), + is_const: false, + } + } + + #[inline] + pub fn function(ret: Dtype, params: Vec) -> Self { + Self::Function { + ret: Box::new(ret), + params, + } + } + + #[inline] + pub fn get_int_width(&self) -> Option { + if let Self::Int { width, .. } = self { + Some(*width) + } else { + None + } + } + + #[inline] + pub fn get_float_width(&self) -> Option { + if let Self::Float { width, .. } = self { + Some(*width) + } else { + None + } + } + + #[inline] + pub fn get_pointer_inner(&self) -> Option<&Dtype> { + if let Self::Pointer { inner, .. } = self { + Some(inner.deref()) + } else { + None + } + } + + #[inline] + pub fn get_function_inner(&self) -> Option<(&Dtype, &Vec)> { + if let Self::Function { ret, params } = self { + Some((ret.deref(), params)) + } else { + None + } + } + + #[inline] + pub fn is_scalar(&self) -> bool { + match self { + Self::Unit { .. } => todo!(), + Self::Int { .. } => true, + Self::Float { .. } => true, + _ => false, + } + } + + #[inline] + pub fn is_int_signed(&self) -> bool { + match self { + Self::Int { is_signed, .. } => *is_signed, + _ => panic!("only `Dtype::Int` can be judged whether it is sigend"), + } + } + + #[inline] + pub fn is_const(&self) -> bool { + match self { + Self::Unit { is_const } => *is_const, + Self::Int { is_const, .. } => *is_const, + Self::Float { is_const, .. } => *is_const, + Self::Pointer { is_const, .. } => *is_const, + Self::Function { .. } => { + panic!("there should be no case that check whether `Function` is `const`") + } + } + } + + pub fn set_const(self, is_const: bool) -> Self { + match self { + Self::Unit { .. } => Self::Unit { is_const }, + Self::Int { + width, is_signed, .. + } => Self::Int { + width, + is_signed, + is_const, + }, + Self::Float { width, .. } => Self::Float { width, is_const }, + Self::Pointer { inner, .. } => Self::Pointer { inner, is_const }, + Self::Function { .. } => panic!("`const` cannot be applied to `Dtype::Function`"), + } + } + + /// Return byte size of `Dtype` + pub fn size_of(&self) -> Result { + // TODO: consider complex type like array, structure in the future + match self { + Self::Unit { .. } => Ok(0), + Self::Int { width, .. } => Ok(*width / Self::WIDTH_OF_BYTE), + Self::Float { width, .. } => Ok(*width / Self::WIDTH_OF_BYTE), + Self::Pointer { .. } => Ok(Self::WIDTH_OF_POINTER / Self::WIDTH_OF_BYTE), + Self::Function { .. } => Err(DtypeError::Misc { + message: "`sizeof` cannot be used with function types".to_string(), + }), + } + } + + /// Return alignment requirements of `Dtype` + pub fn align_of(&self) -> Result { + // TODO: consider complex type like array, structure in the future + // TODO: when considering complex type like a structure, + // the calculation method should be different from `Dtype::size_of`. + match self { + Self::Unit { .. } => Ok(0), + Self::Int { width, .. } => Ok(*width / Self::WIDTH_OF_BYTE), + Self::Float { width, .. } => Ok(*width / Self::WIDTH_OF_BYTE), + Self::Pointer { .. } => Ok(Self::WIDTH_OF_POINTER / Self::WIDTH_OF_BYTE), + Self::Function { .. } => Err(DtypeError::Misc { + message: "`alignof` cannot be used with function types".to_string(), + }), + } + } + + pub fn set_signed(self, is_signed: bool) -> Self { + match self { + Self::Int { + width, is_const, .. + } => Self::Int { + width, + is_signed, + is_const, + }, + _ => panic!("`signed` and `unsigned` only be applied to `Dtype::Int`"), + } + } + + /// Derive a data type from declaration specifiers. + pub fn try_from_ast_declaration_specifiers( + specifiers: &[Node], + ) -> Result { + let mut spec = BaseDtype::default(); + BaseDtype::apply_declaration_specifiers(&mut spec, specifiers)?; + Self::try_from(spec) + } + + /// Generate `Dtype` based on declarator and `base_dtype` which has scalar type. + /// + /// let's say declaration is `const int * const * const a;`. + /// In general `base_dtype` start with `const int` which has scalar type and + /// `declarator` represents `* const * const` with `ast::Declarator` + /// + /// # Arguments + /// + /// * `declarator` - Parts requiring conversion to 'Dtype' on the declaration + /// * `base_dtype` - Part that has been converted to 'Dtype' on the declaration + /// + pub fn with_ast_declarator(mut self, declarator: &ast::Declarator) -> Result { + for derived_decl in &declarator.derived { + self = match &derived_decl.node { + ast::DerivedDeclarator::Pointer(pointer_qualifiers) => { + let mut specifier = BaseDtype::default(); + for qualifier in pointer_qualifiers { + specifier.apply_pointer_qualifier(&qualifier.node)?; + } + Self::pointer(self).set_const(specifier.is_const) + } + ast::DerivedDeclarator::Array(_array_decl) => todo!(), + ast::DerivedDeclarator::Function(func_decl) => { + let params = func_decl + .node + .parameters + .iter() + .map(|p| Self::try_from(&p.node)) + .collect::, _>>()?; + Self::function(self, params) + } + ast::DerivedDeclarator::KRFunction(kr_func_decl) => { + // K&R function is allowed only when it has no parameter + assert!(kr_func_decl.is_empty()); + Self::function(self, Vec::new()) + } + }; + } + + let declarator_kind = &declarator.kind; + match &declarator_kind.node { + ast::DeclaratorKind::Abstract => panic!("ast::DeclaratorKind::Abstract is unsupported"), + ast::DeclaratorKind::Identifier(_) => Ok(self), + ast::DeclaratorKind::Declarator(declarator) => { + self.with_ast_declarator(&declarator.node) + } + } + } + + /// Check whether type conflict exists between the two `Dtype` objects. + /// + /// let's say expression is `const int a = 0; int b = 0; int c = a + b`. + /// Although `const int` of `a` and `int` of `b` looks different, `Plus`(+) operations between + /// these two types are possible without any type-casting. There is no conflict between + /// `const int` and `int`. + /// + /// However, only the outermost const is ignored. + /// If check equivalence between `const int *const` and `int *`, result is false. Because + /// the second `const` (means left most `const`) of the `const int *const` is missed in `int *`. + /// By the way, outermost `const` (means right most `const`) is not a consideration here. + pub fn is_compatible(&self, other: &Self) -> bool { + match (self, other) { + (Self::Unit { .. }, Self::Unit { .. }) + | (Self::Int { .. }, Self::Int { .. }) + | (Self::Float { .. }, Self::Float { .. }) + | (Self::Pointer { .. }, Self::Pointer { .. }) => { + self.clone().set_const(false) == other.clone().set_const(false) + } + ( + Self::Function { ret, params }, + Self::Function { + ret: other_ret, + params: other_params, + }, + ) => { + ret == other_ret + && params.len() == other_params.len() + && izip!(params, other_params).all(|(l, r)| l.is_compatible(r)) + } + _ => false, + } + } +} + +impl fmt::Display for Dtype { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Unit { is_const } => write!(f, "{}unit", if *is_const { "const " } else { "" }), + Self::Int { + width, + is_signed, + is_const, + } => write!( + f, + "{}{}{}", + if *is_const { "const " } else { "" }, + if *is_signed { "i" } else { "u" }, + width + ), + Self::Float { width, is_const } => { + write!(f, "{}f{}", if *is_const { "const " } else { "" }, width) + } + Self::Pointer { inner, is_const } => { + write!(f, "{}* {}", inner, if *is_const { "const" } else { "" }) + } + Self::Function { ret, params } => write!( + f, + "{} ({})", + ret, + params + .iter() + .map(|p| p.to_string()) + .collect::>() + .join(", ") + ), + } + } +} + +impl Default for Dtype { + fn default() -> Self { + // default dtype is `int`(i32) + Self::INT + } +} diff --git a/src/run_ir.rs b/src/ir/interp.rs similarity index 68% rename from src/run_ir.rs rename to src/ir/interp.rs index eb3b786..419275a 100644 --- a/src/run_ir.rs +++ b/src/ir/interp.rs @@ -1,12 +1,13 @@ -use crate::ir::*; -use crate::*; - +use core::fmt; +use core::mem; use failure::Fail; use std::collections::HashMap; -use std::mem; use itertools::izip; +use crate::ir::*; +use crate::*; + // TODO: the variants of Value will be added in the future #[derive(Debug, PartialEq, Clone)] pub enum Value { @@ -74,23 +75,26 @@ pub enum InterpreterError { NoMainFunction, #[fail(display = "ir has no function definition of {} function", func_name)] NoFunctionDefinition { func_name: String }, - #[fail( - display = "{}:{}:{} / Undef value cannot be used as an operand", - func_name, bid, iid - )] + #[fail(display = "{}:{} / {}", func_name, pc, msg)] Misc { func_name: String, - bid: BlockId, - iid: usize, + pc: Pc, + msg: String, }, } -#[derive(Debug, PartialEq, Clone)] -struct Pc { +#[derive(Debug, PartialEq, Clone, Copy)] +pub struct Pc { pub bid: BlockId, pub iid: usize, } +impl fmt::Display for Pc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}:{}", self.bid, self.iid) + } +} + impl Pc { fn new(bid: BlockId) -> Pc { Pc { bid, iid: 0 } @@ -101,16 +105,20 @@ impl Pc { } } -#[derive(Debug, PartialEq, Clone)] +#[derive(Default, Debug, PartialEq, Clone)] struct RegisterMap { inner: HashMap, } impl RegisterMap { - fn new() -> Self { - Self { - inner: HashMap::new(), - } + fn read(&self, rid: RegisterId) -> &Value { + self.inner + .get(&rid) + .expect("`rid` must be assigned before it can be used") + } + + fn write(&mut self, rid: RegisterId, value: Value) { + let _ = self.inner.insert(rid, value); } } @@ -164,7 +172,7 @@ impl<'i> StackFrame<'i> { fn new(bid: BlockId, func_name: String, func_def: &'i FunctionDefinition) -> Self { StackFrame { pc: Pc::new(bid), - registers: RegisterMap::new(), + registers: Default::default(), func_name, func_def, } @@ -229,6 +237,39 @@ mod calculator { } } +#[derive(Default, Debug, PartialEq)] +struct Memory { + // TODO: memory type should change to Vec> + inner: Vec>, +} + +impl Memory { + fn alloc(&mut self, dtype: &Dtype) -> Result { + let memory_block = match dtype { + Dtype::Unit { .. } => vec![], + Dtype::Int { width, .. } => match width { + 32 => vec![Value::Undef], + _ => todo!(), + }, + Dtype::Float { .. } => todo!(), + Dtype::Pointer { .. } => vec![Value::Undef], + Dtype::Function { .. } => vec![], + }; + + self.inner.push(memory_block); + + Ok(self.inner.len() - 1) + } + + fn load(&self, bid: usize, offset: usize) -> &Value { + &self.inner[bid][offset] + } + + fn store(&mut self, bid: usize, offset: usize, value: Value) { + self.inner[bid][offset] = value; + } +} + // TODO: allocation fields will be added in the future // TODO: program fields will be added in the future #[derive(Debug, PartialEq)] @@ -238,8 +279,7 @@ struct State<'i> { pub global_map: GlobalMap, pub stack_frame: StackFrame<'i>, pub stack: Vec>, - // TODO: memory type should change to Vec> - pub memory: Vec>, + pub memory: Memory, pub ir: &'i TranslationUnit, } @@ -265,35 +305,35 @@ impl<'i> State<'i> { global_map: GlobalMap::default(), stack_frame: StackFrame::new(func_def.bid_init, func_name, func_def), stack: Vec::new(), - memory: Vec::new(), + memory: Default::default(), ir, }; - state.alloc_global_variable()?; + state.alloc_global_variables()?; // Initialize state with main function and args - state.pass_arguments(args)?; - state.alloc_local_variable()?; + state.write_args(func_def.bid_init, args)?; + state.alloc_local_variables()?; Ok(state) } - fn alloc_global_variable(&mut self) -> Result<(), InterpreterError> { + fn alloc_global_variables(&mut self) -> Result<(), InterpreterError> { for (name, decl) in &self.ir.decls { // Memory allocation - let bid = self.alloc_memory(&decl.dtype())?; + let bid = self.memory.alloc(&decl.dtype())?; self.global_map.insert(name.clone(), bid)?; // Initialize allocated memory space match decl { Declaration::Variable { dtype, initializer } => { let value = if let Some(constant) = initializer { - self.constant_to_value(constant.clone()) + self.interp_constant(constant.clone()) } else { Value::default_from_dtype(dtype) }; - self.memory[bid][0] = value; + self.memory.store(bid, 0, value); } // If functin declaration, skip initialization Declaration::Function { .. } => (), @@ -303,46 +343,70 @@ impl<'i> State<'i> { Ok(()) } - fn pass_arguments(&mut self, args: Vec) -> Result<(), InterpreterError> { - for (i, value) in args.iter().enumerate() { - self.register_write(RegisterId::arg(i), value.clone()); - } - - Ok(()) - } - - fn alloc_local_variable(&mut self) -> Result<(), InterpreterError> { + fn alloc_local_variables(&mut self) -> Result<(), InterpreterError> { // add alloc register for (id, allocation) in self.stack_frame.func_def.allocations.iter().enumerate() { - let bid = self.alloc_memory(&allocation)?; + let bid = self.memory.alloc(&allocation)?; let ptr = Value::pointer(Some(bid), 0); let rid = RegisterId::local("".to_string(), id); - self.register_write(rid, ptr) + self.stack_frame.registers.write(rid, ptr) } Ok(()) } - fn alloc_memory(&mut self, dtype: &Dtype) -> Result { - // TODO: memory block will be handled as Vec - let memory_block = match dtype { - Dtype::Unit { .. } => vec![], - Dtype::Int { width, .. } => match width { - 32 => vec![Value::Undef], - _ => todo!(), - }, - Dtype::Float { .. } => todo!(), - Dtype::Pointer { .. } => vec![Value::Undef], - Dtype::Function { .. } => vec![], - }; + fn write_args(&mut self, bid_init: BlockId, args: Vec) -> Result<(), InterpreterError> { + for (i, value) in args.iter().enumerate() { + self.stack_frame + .registers + .write(RegisterId::arg(bid_init, i), value.clone()); + } - self.memory.push(memory_block); - - Ok(self.memory.len() - 1) + Ok(()) } - fn preprocess_args( + fn step(&mut self) -> Result, InterpreterError> { + let block = self + .stack_frame + .func_def + .blocks + .get(&self.stack_frame.pc.bid) + .expect("block matched with `bid` must be exist"); + + // If it's time to execute an instruction, do so. + if let Some(instr) = block.instructions.get(self.stack_frame.pc.iid) { + self.interp_instruction(instr)?; + return Ok(None); + } + + // Execute a block exit. + let return_value = some_or!(self.interp_block_exit(&block.exit)?, return Ok(None)); + + // If it's returning from a function, pop the stack frame. + + // TODO: free memory allocated in the callee + + // restore previous state + let prev_stack_frame = some_or!(self.stack.pop(), return Ok(Some(return_value))); + self.stack_frame = prev_stack_frame; + + // create temporary register to write return value + let register = RegisterId::temp(self.stack_frame.pc.bid, self.stack_frame.pc.iid); + self.stack_frame.registers.write(register, return_value); + self.stack_frame.pc.increment(); + Ok(None) + } + + fn run(&mut self) -> Result { + loop { + if let Some(value) = self.step()? { + return Ok(value); + } + } + } + + fn interp_args( &self, signature: &FunctionSignature, args: &[Operand], @@ -355,135 +419,111 @@ impl<'i> State<'i> { } args.iter() - .map(|a| self.get_value(a.clone())) + .map(|a| self.interp_operand(a.clone())) .collect::, _>>() } - fn step(&mut self) -> Result, InterpreterError> { + fn interp_jump(&mut self, arg: &JumpArg) -> Result, InterpreterError> { let block = self .stack_frame .func_def .blocks - .get(&self.stack_frame.pc.bid) - .expect("block matched with `bid` must be exist"); + .get(&arg.bid) + .expect("block matched with `arg.bid` must be exist"); - if block.instructions.len() == self.stack_frame.pc.iid { - self.interpret_block_exit(&block.exit) - } else { - let instr = block - .instructions - .get(self.stack_frame.pc.iid) - .expect("instruction matched with `iid` must be exist"); - - self.interpret_instruction(instr) + assert_eq!(arg.args.len(), block.phinodes.len()); + for (a, d) in izip!(&arg.args, &block.phinodes) { + assert!(a.dtype().is_compatible(&d)); } + + for (i, a) in arg.args.iter().enumerate() { + let v = self.interp_operand(a.clone()).unwrap(); + self.stack_frame + .registers + .inner + .insert(RegisterId::arg(arg.bid, i), v) + .unwrap(); + } + + self.stack_frame.pc = Pc::new(arg.bid); + Ok(None) } - fn run(&mut self) -> Result { - loop { - if let Some(value) = self.step()? { - // TODO: Before return, free memory allocated in a function - - // restore previous state - let prev_stack_frame = some_or!(self.stack.pop(), { - return Ok(value); - }); - self.stack_frame = prev_stack_frame; - - // create temporary register to write return value - let register = RegisterId::temp(self.stack_frame.pc.bid, self.stack_frame.pc.iid); - self.register_write(register, value); - self.stack_frame.pc.increment(); - } - } - } - - fn interpret_block_exit( + fn interp_block_exit( &mut self, block_exit: &BlockExit, ) -> Result, InterpreterError> { match block_exit { - BlockExit::Jump { bid } => { - self.stack_frame.pc = Pc::new(*bid); - Ok(None) - } + BlockExit::Jump { arg } => self.interp_jump(arg), BlockExit::ConditionalJump { condition, - bid_then, - bid_else, + arg_then, + arg_else, } => { - let value = self.get_value(condition.clone())?; + let value = self.interp_operand(condition.clone())?; let value = value.get_bool().expect("`condition` must be `Value::Bool`"); - - self.stack_frame.pc = Pc::new(if value { *bid_then } else { *bid_else }); - Ok(None) + self.interp_jump(if value { arg_then } else { arg_else }) } BlockExit::Switch { value, default, cases, } => { - let value = self.get_value(value.clone())?; + let value = self.interp_operand(value.clone())?; // TODO: consider different integer `width` in the future - let bid_next = cases + let arg = cases .iter() - .find(|(c, _)| value == self.constant_to_value(c.clone())) - .map(|(_, bid)| bid) + .find(|(c, _)| value == self.interp_constant(c.clone())) + .map(|(_, arg)| arg) .unwrap_or_else(|| default); - - self.stack_frame.pc = Pc::new(*bid_next); - - Ok(None) + self.interp_jump(arg) } - BlockExit::Return { value } => Ok(Some(self.get_value(value.clone())?)), + BlockExit::Return { value } => Ok(Some(self.interp_operand(value.clone())?)), BlockExit::Unreachable => Err(InterpreterError::Unreachable), } } - fn interpret_instruction( - &mut self, - instruction: &Instruction, - ) -> Result, InterpreterError> { + fn interp_instruction(&mut self, instruction: &Instruction) -> Result<(), InterpreterError> { let result = match instruction { Instruction::BinOp { op, lhs, rhs, .. } => { - let lhs = self.get_value(lhs.clone())?; - let rhs = self.get_value(rhs.clone())?; + let lhs = self.interp_operand(lhs.clone())?; + let rhs = self.interp_operand(rhs.clone())?; calculator::calculate_binary_operator_expression(&op, lhs, rhs).map_err(|_| { InterpreterError::Misc { func_name: self.stack_frame.func_name.clone(), - bid: self.stack_frame.pc.bid, - iid: self.stack_frame.pc.iid, + pc: self.stack_frame.pc, + msg: "calculate_binary_operator_expression".into(), } })? } Instruction::UnaryOp { op, operand, .. } => { - let operand = self.get_value(operand.clone())?; + let operand = self.interp_operand(operand.clone())?; calculator::calculate_unary_operator_expression(&op, operand).map_err(|_| { InterpreterError::Misc { func_name: self.stack_frame.func_name.clone(), - bid: self.stack_frame.pc.bid, - iid: self.stack_frame.pc.iid, + pc: self.stack_frame.pc, + msg: "calculate_unary_operator_expression".into(), } })? } Instruction::Store { ptr, value, .. } => { - let ptr = self.get_value(ptr.clone())?; - let value = self.get_value(value.clone())?; - - self.memory_store(ptr, value)?; + let ptr = self.interp_operand(ptr.clone())?; + let value = self.interp_operand(value.clone())?; + let (bid, offset) = self.interp_ptr(ptr)?; + self.memory.store(bid, offset, value); Value::Unit } Instruction::Load { ptr, .. } => { - let ptr = self.get_value(ptr.clone())?; - - self.memory_load(ptr)? + let ptr = self.interp_operand(ptr.clone())?; + let (bid, offset) = self.interp_ptr(ptr)?; + self.memory.load(bid, offset).clone() } Instruction::Call { callee, args, .. } => { - let ptr = self.get_value(callee.clone())?; + let ptr = self.interp_operand(callee.clone())?; // Get function name from pointer let (bid, _) = ptr.get_pointer().expect("`ptr` must be `Value::Pointer`"); @@ -508,48 +548,50 @@ impl<'i> State<'i> { func_name: callee_name.clone(), })?; - let args = self.preprocess_args(func_signature, args)?; + let args = self.interp_args(func_signature, args)?; 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); // Initialize state with function obtained by callee and args - self.pass_arguments(args)?; - self.alloc_local_variable()?; + self.write_args(func_def.bid_init, args)?; + self.alloc_local_variables()?; - return Ok(None); + return Ok(()); } Instruction::TypeCast { value, target_dtype, } => { - let value = self.get_value(value.clone())?; + let value = self.interp_operand(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, + pc: self.stack_frame.pc, + msg: "calculate_typecast".into(), } })? } }; let register = RegisterId::temp(self.stack_frame.pc.bid, self.stack_frame.pc.iid); - self.register_write(register, result); + self.stack_frame.registers.write(register, result); self.stack_frame.pc.increment(); - Ok(None) + Ok(()) } - fn get_value(&self, operand: Operand) -> Result { + fn interp_operand(&self, operand: Operand) -> Result { match &operand { - Operand::Constant(value) => Ok(self.constant_to_value(value.clone())), - Operand::Register { rid, .. } => Ok(self.register_read(rid.clone())), + Operand::Constant(value) => Ok(self.interp_constant(value.clone())), + Operand::Register { rid, .. } => { + Ok(self.stack_frame.registers.read(rid.clone()).clone()) + } } } - fn constant_to_value(&self, value: Constant) -> Value { + fn interp_constant(&self, value: Constant) -> Value { match value { Constant::Unit => Value::Unit, // TODO: consider `width` and `is_signed` in the future @@ -570,43 +612,27 @@ impl<'i> State<'i> { } } - fn register_write(&mut self, rid: RegisterId, value: Value) { - let _ = self.stack_frame.registers.inner.insert(rid, value); - } - - fn register_read(&self, rid: RegisterId) -> Value { - self.stack_frame - .registers - .inner - .get(&rid) - .cloned() - .expect("`rid` must be assigned before it can be used") - } - - fn memory_store(&mut self, pointer: Value, value: Value) -> Result<(), InterpreterError> { + fn interp_ptr(&mut self, pointer: Value) -> Result<(usize, usize), InterpreterError> { let (bid, offset) = pointer .get_pointer() - .expect("`pointer` must be `Value::Pointer` to access memory"); + .ok_or_else(|| InterpreterError::Misc { + func_name: self.stack_frame.func_name.clone(), + pc: self.stack_frame.pc, + msg: "Accessing memory with non-pointer".into(), + })?; - let bid = bid.expect("write to memory using constant value address is not allowed"); - self.memory[bid][offset] = value; + let bid = bid.ok_or_else(|| InterpreterError::Misc { + func_name: self.stack_frame.func_name.clone(), + pc: self.stack_frame.pc, + msg: "Accessing memory with constant pointer".into(), + })?; - Ok(()) - } - - fn memory_load(&self, pointer: Value) -> Result { - let (bid, offset) = pointer - .get_pointer() - .expect("`pointer` must be `Value::Pointer` to access memory"); - - let bid = bid.expect("read from memory using constant value address is not allowed"); - - Ok(self.memory[bid][offset].clone()) + Ok((bid, offset)) } } #[inline] -pub fn run_ir(ir: &TranslationUnit, args: Vec) -> Result { +pub fn interp(ir: &TranslationUnit, args: Vec) -> Result { let mut init_state = State::new(ir, args)?; init_state.run() } diff --git a/src/ir/mod.rs b/src/ir/mod.rs new file mode 100644 index 0000000..9229e42 --- /dev/null +++ b/src/ir/mod.rs @@ -0,0 +1,578 @@ +mod dtype; +mod interp; +mod write_ir; + +use core::convert::TryFrom; +use core::fmt; +use core::ops::Deref; +use lang_c::ast; +use std::collections::HashMap; +use std::hash::{Hash, Hasher}; + +pub use dtype::{Dtype, DtypeError, HasDtype}; +pub use interp::{interp, Value}; + +#[derive(Debug, PartialEq)] +pub struct TranslationUnit { + pub decls: HashMap, +} + +#[derive(Debug, PartialEq, Clone)] +pub enum Declaration { + Variable { + dtype: Dtype, + initializer: Option, + }, + Function { + signature: FunctionSignature, + definition: Option, + }, +} + +impl TryFrom for Declaration { + type Error = DtypeError; + + /// Create an appropriate declaration according to `dtype`. + /// + /// # Example + /// + /// If `int g = 0;` is declared, `dtype` is + /// `ir::Dtype::Int{ width:32, is_signed:true, is_const:false }`. + /// In this case, `ir::Declaration::Variable{ dtype, initializer: Some(Constant::I32(1)) }` + /// is generated. + /// + /// Conversely, if `int foo();` is declared, `dtype` is + /// `ir::Dtype::Function{ret: Scalar(Int), params: []}`. + /// Thus, in this case, `ir::Declaration::Function` is generated. + fn try_from(dtype: Dtype) -> Result { + match &dtype { + Dtype::Unit { .. } => Err(DtypeError::Misc { + message: "A variable of type `void` cannot be declared".to_string(), + }), + Dtype::Int { .. } | Dtype::Float { .. } | Dtype::Pointer { .. } => { + Ok(Declaration::Variable { + dtype, + initializer: None, + }) + } + Dtype::Function { .. } => Ok(Declaration::Function { + signature: FunctionSignature::new(dtype), + definition: None, + }), + } + } +} + +impl Declaration { + pub fn get_variable(&self) -> Option<(&Dtype, &Option)> { + if let Self::Variable { dtype, initializer } = self { + Some((dtype, initializer)) + } else { + None + } + } + + pub fn get_function(&self) -> Option<(&FunctionSignature, &Option)> { + if let Self::Function { + signature, + definition, + } = self + { + Some((signature, definition)) + } else { + None + } + } + + pub fn get_function_mut( + &mut self, + ) -> Option<(&mut FunctionSignature, &mut Option)> { + if let Self::Function { + signature, + definition, + } = self + { + Some((signature, definition)) + } else { + None + } + } + + /// Check if type is conflicting for pre-declared one + /// + /// In case of `Variable`, need to check if the two types are exactly the same. + /// On the other hand, in the case of `Function`, outermost `const` of return type and + /// parameters one is not an issue of concern. + pub fn is_compatible(&self, other: &Declaration) -> bool { + match (self, other) { + (Self::Variable { dtype, .. }, Self::Variable { dtype: other, .. }) => dtype == other, + ( + Self::Function { signature, .. }, + Self::Function { + signature: other, .. + }, + ) => signature.dtype().is_compatible(&other.dtype()), + _ => false, + } + } +} + +impl HasDtype for Declaration { + fn dtype(&self) -> Dtype { + match self { + Self::Variable { dtype, .. } => dtype.clone(), + Self::Function { signature, .. } => signature.dtype(), + } + } +} + +#[derive(Debug, PartialEq, Clone)] +pub struct FunctionDefinition { + /// Memory allocations for local variables. The allocation is performed at the beginning of a + /// function invocation. + pub allocations: Vec, + + /// Basic blocks. + pub blocks: HashMap, + + /// The initial block id. + pub bid_init: BlockId, +} + +#[derive(Debug, PartialEq, Clone)] +pub struct FunctionSignature { + pub ret: Dtype, + pub params: Vec, +} + +impl FunctionSignature { + pub fn new(dtype: Dtype) -> Self { + let (ret, params) = dtype + .get_function_inner() + .expect("function signature's dtype must be function type"); + Self { + ret: ret.clone(), + params: params.clone(), + } + } +} + +impl HasDtype for FunctionSignature { + fn dtype(&self) -> Dtype { + Dtype::function(self.ret.clone(), self.params.clone()) + } +} + +#[derive(Debug, Eq, Clone)] +pub enum RegisterId { + /// Registers holding pointers to local allocations. + /// + /// # Fields + /// + /// - `name`: only for debugging purposes. + /// - `id`: local allocation id. + Local { name: String, id: usize }, + + /// Registers holding block arguments. + /// + /// # Fields + /// + /// - `bid`: When it is the initial block id, then it holds a function argument; otherwise, it + /// holds a phinode value. + /// - `aid`: the argument index. + Arg { bid: BlockId, aid: usize }, + + /// Registers holding the results of instructions. + /// + /// # Fields + /// + /// - `bid`: the instruction's block id. + /// - `iid`: the instruction's id in the block. + Temp { bid: BlockId, iid: usize }, +} + +impl RegisterId { + pub fn local(name: String, id: usize) -> Self { + Self::Local { name, id } + } + + pub fn arg(bid: BlockId, aid: usize) -> Self { + Self::Arg { bid, aid } + } + + pub fn temp(bid: BlockId, iid: usize) -> Self { + Self::Temp { bid, iid } + } +} + +impl fmt::Display for RegisterId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Local { name, id } => write!(f, "%(local:{}:{})", name, id), + Self::Arg { bid, aid } => write!(f, "%(arg:{}:{})", bid, aid), + Self::Temp { bid, iid } => write!(f, "%({}:{})", bid, iid), + } + } +} + +impl PartialEq for RegisterId { + fn eq(&self, other: &RegisterId) -> bool { + match (self, other) { + (Self::Local { id, .. }, Self::Local { id: other_id, .. }) => id == other_id, + ( + Self::Arg { bid, aid }, + Self::Arg { + bid: other_bid, + aid: other_aid, + }, + ) => bid == other_bid && aid == other_aid, + ( + Self::Temp { bid, iid }, + Self::Temp { + bid: other_bid, + iid: other_iid, + }, + ) => bid == other_bid && iid == other_iid, + _ => false, + } + } +} + +impl Hash for RegisterId { + fn hash(&self, state: &mut H) { + match self { + Self::Local { id, .. } => id.hash(state), + Self::Arg { bid, aid } => { + // TODO: needs to distinguish arg/temp? + bid.hash(state); + aid.hash(state); + } + Self::Temp { bid, iid } => { + bid.hash(state); + iid.hash(state); + } + } + } +} + +#[derive(Debug, PartialEq, Clone)] +pub enum Constant { + Unit, + Int { + value: u128, + width: usize, + is_signed: bool, + }, + Float { + /// `value` may be `f32`, but it is possible to consider it as `f64`. + /// + /// * Casting from an f32 to an f64 is perfect and lossless (f32 -> f64) + /// * Casting from an f64 to an f32 will produce the closest possible value (f64 -> f32) + /// https://doc.rust-lang.org/stable/reference/expressions/operator-expr.html#type-cast-expressions + value: f64, + width: usize, + }, + GlobalVariable { + name: String, + dtype: Dtype, + }, +} + +impl TryFrom<&ast::Constant> for Constant { + type Error = (); + + fn try_from(constant: &ast::Constant) -> Result { + match constant { + ast::Constant::Integer(integer) => { + let is_signed = !integer.suffix.unsigned; + + let dtype = match integer.suffix.size { + ast::IntegerSize::Int => Dtype::INT, + ast::IntegerSize::Long => Dtype::LONG, + ast::IntegerSize::LongLong => Dtype::LONGLONG, + } + .set_signed(is_signed); + + let value = if is_signed { + integer.number.parse::().unwrap() as u128 + } else { + integer.number.parse::().unwrap() + }; + + Ok(Self::int(value, dtype)) + } + ast::Constant::Float(float) => { + let (dtype, value) = match float.suffix.format { + ast::FloatFormat::Float => { + // Casting from an f32 to an f64 is perfect and lossless (f32 -> f64) + // https://doc.rust-lang.org/stable/reference/expressions/operator-expr.html#type-cast-expressions + (Dtype::FLOAT, float.number.parse::().unwrap() as f64) + } + ast::FloatFormat::Double => { + (Dtype::DOUBLE, float.number.parse::().unwrap()) + } + ast::FloatFormat::LongDouble => { + panic!("`FloatFormat::LongDouble` is_unsupported") + } + ast::FloatFormat::TS18661Format(_) => { + panic!("`FloatFormat::TS18661Format` is_unsupported") + } + }; + + Ok(Self::float(value, dtype)) + } + ast::Constant::Character(character) => { + let dtype = Dtype::CHAR; + let value = character.parse::().unwrap() as u128; + + Ok(Self::int(value, dtype)) + } + } + } +} + +impl TryFrom<&ast::Expression> for Constant { + type Error = (); + + fn try_from(expr: &ast::Expression) -> Result { + if let ast::Expression::Constant(constant) = expr { + Self::try_from(&constant.node) + } else { + Err(()) + } + } +} + +impl TryFrom<&ast::Initializer> for Constant { + type Error = (); + + fn try_from(initializer: &ast::Initializer) -> Result { + if let ast::Initializer::Expression(expr) = &initializer { + Self::try_from(&expr.node) + } else { + Err(()) + } + } +} + +impl Constant { + #[inline] + pub fn is_integer_constant(&self) -> bool { + if let Self::Int { .. } = self { + true + } else { + false + } + } + + pub fn unit() -> Self { + Constant::Unit + } + + #[inline] + pub fn int(value: u128, dtype: Dtype) -> Self { + let width = dtype.get_int_width().expect("`dtype` must be `Dtype::Int`"); + let is_signed = dtype.is_int_signed(); + + Constant::Int { + value, + width, + is_signed, + } + } + + #[inline] + pub fn float(value: f64, dtype: Dtype) -> Self { + let width = dtype + .get_float_width() + .expect("`dtype` must be `Dtype::Float`"); + + Constant::Float { value, width } + } + + #[inline] + pub fn global_variable(name: String, dtype: Dtype) -> Self { + Self::GlobalVariable { name, dtype } + } +} + +impl fmt::Display for Constant { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Unit => write!(f, "unit"), + Self::Int { value, .. } => write!(f, "{}", value), + Self::Float { value, .. } => write!(f, "{}", value), + Self::GlobalVariable { name, .. } => write!(f, "%{}", name), + } + } +} + +impl HasDtype for Constant { + fn dtype(&self) -> Dtype { + match self { + Self::Unit => Dtype::unit(), + Self::Int { + width, is_signed, .. + } => Dtype::int(*width).set_signed(*is_signed), + Self::Float { width, .. } => Dtype::float(*width), + Self::GlobalVariable { dtype, .. } => Dtype::pointer(dtype.clone()), + } + } +} + +#[derive(Debug, PartialEq, Clone)] +pub enum Operand { + Constant(Constant), + Register { rid: RegisterId, dtype: Dtype }, +} + +impl Operand { + pub fn constant(value: Constant) -> Self { + Self::Constant(value) + } + + pub fn register(rid: RegisterId, dtype: Dtype) -> Self { + Self::Register { rid, dtype } + } + + pub fn get_constant(&self) -> Option<&Constant> { + if let Self::Constant(constant) = self { + Some(constant) + } else { + None + } + } + + pub fn get_register(&self) -> Option<(&RegisterId, &Dtype)> { + if let Self::Register { rid, dtype } = self { + Some((rid, dtype)) + } else { + None + } + } +} + +impl fmt::Display for Operand { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Constant(value) => write!(f, "{}", value), + Self::Register { rid, .. } => write!(f, "{}", rid), + } + } +} + +impl HasDtype for Operand { + fn dtype(&self) -> Dtype { + match self { + Self::Constant(value) => value.dtype(), + Self::Register { dtype, .. } => dtype.clone(), + } + } +} + +#[derive(Debug, PartialEq, Clone)] +pub enum Instruction { + // TODO: the variants of Instruction will be added in the future + BinOp { + op: ast::BinaryOperator, + lhs: Operand, + rhs: Operand, + dtype: Dtype, + }, + UnaryOp { + op: ast::UnaryOperator, + operand: Operand, + dtype: Dtype, + }, + Store { + ptr: Operand, + value: Operand, + }, + Load { + ptr: Operand, + }, + Call { + callee: Operand, + args: Vec, + return_type: Dtype, + }, + TypeCast { + value: Operand, + target_dtype: Dtype, + }, +} + +impl HasDtype for Instruction { + fn dtype(&self) -> Dtype { + match self { + Self::BinOp { dtype, .. } => dtype.clone(), + Self::UnaryOp { dtype, .. } => dtype.clone(), + Self::Store { .. } => Dtype::unit(), + Self::Load { ptr } => ptr + .dtype() + .get_pointer_inner() + .expect("Load instruction must have pointer value as operand") + .deref() + .clone() + .set_const(false), + Self::Call { return_type, .. } => return_type.clone(), + Self::TypeCast { target_dtype, .. } => target_dtype.clone(), + } + } +} + +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +pub struct BlockId(pub usize); + +impl fmt::Display for BlockId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "b{}", self.0) + } +} + +#[derive(Debug, PartialEq, Clone)] +pub struct JumpArg { + pub bid: BlockId, + pub args: Vec, +} + +impl JumpArg { + pub fn new(bid: BlockId, args: Vec) -> Self { + Self { bid, args } + } +} + +impl fmt::Display for JumpArg { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}({:?})", self.bid, self.args) + } +} + +// TODO +#[derive(Debug, PartialEq, Clone)] +pub enum BlockExit { + Jump { + arg: JumpArg, + }, + ConditionalJump { + condition: Operand, + arg_then: JumpArg, + arg_else: JumpArg, + }, + Switch { + value: Operand, + default: JumpArg, + cases: Vec<(Constant, JumpArg)>, + }, + Return { + value: Operand, + }, + Unreachable, +} + +#[derive(Debug, PartialEq, Clone)] +pub struct Block { + pub phinodes: Vec, + pub instructions: Vec, + pub exit: BlockExit, +} diff --git a/src/write_ir.rs b/src/ir/write_ir.rs similarity index 96% rename from src/write_ir.rs rename to src/ir/write_ir.rs index 51151c5..95a4ddf 100644 --- a/src/write_ir.rs +++ b/src/ir/write_ir.rs @@ -188,16 +188,16 @@ impl WriteOp for ast::UnaryOperator { impl WriteString for BlockExit { fn write_string(&self) -> String { match self { - BlockExit::Jump { bid } => format!("j {}", bid), + BlockExit::Jump { arg } => format!("j {}", arg), BlockExit::ConditionalJump { condition, - bid_then, - bid_else, + arg_then, + arg_else, } => format!( "br {}, {}, {}", condition.write_string(), - bid_then, - bid_else + arg_then, + arg_else ), BlockExit::Switch { value, @@ -218,7 +218,3 @@ impl WriteString for BlockExit { } } } - -pub fn write_ir(ir: &TranslationUnit, write: &mut dyn Write) -> Result<()> { - ir.write_line(0, write) -} diff --git a/src/irgen.rs b/src/irgen/mod.rs similarity index 97% rename from src/irgen.rs rename to src/irgen/mod.rs index 6508200..b051228 100644 --- a/src/irgen.rs +++ b/src/irgen/mod.rs @@ -1,4 +1,4 @@ -use std::fmt; +use core::fmt; use lang_c::ast::*; diff --git a/src/lib.rs b/src/lib.rs index 6e5fe58..10c35b3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,37 +1,24 @@ #![deny(warnings)] +#![allow(unreachable_code)] +mod tests; mod utils; - -pub mod asm; -pub mod ir; - -mod codegen; -mod irgen; -mod optimize; -mod parse; - -pub mod run_ir; -mod write_asm; mod write_base; -mod write_c; -mod write_ir; -pub mod assert_ast_equiv; -pub mod write_c_test; +mod asm; +mod c; +mod ir; +mod asmgen; +mod irgen; +mod opt; + +pub use tests::*; pub use utils::*; +pub use write_base::write; -pub use asm::Asm; +pub use c::Parse; -pub use codegen::Codegen; +pub use asmgen::Asmgen; pub use irgen::Irgen; -pub use optimize::{O0, O1}; -pub use parse::Parse; -pub use utils::{Optimize, Repeat, Translate}; - -pub use write_asm::write_asm; -pub use write_c::write_c; -pub use write_ir::write_ir; - -pub use assert_ast_equiv::assert_ast_equiv; -pub use write_c_test::write_c_test; +pub use opt::{Gvn, Mem2reg, Optimize, Repeat, SimplifyCfg, Translate, O0, O1}; diff --git a/src/opt/gvn.rs b/src/opt/gvn.rs new file mode 100644 index 0000000..eaab947 --- /dev/null +++ b/src/opt/gvn.rs @@ -0,0 +1,11 @@ +use crate::ir; +use crate::*; + +#[derive(Default)] +pub struct Gvn {} + +impl Optimize for Gvn { + fn optimize(&mut self, _code: &mut ir::TranslationUnit) -> bool { + todo!() + } +} diff --git a/src/opt/mem2reg.rs b/src/opt/mem2reg.rs new file mode 100644 index 0000000..583b01d --- /dev/null +++ b/src/opt/mem2reg.rs @@ -0,0 +1,11 @@ +use crate::ir; +use crate::*; + +#[derive(Default)] +pub struct Mem2reg {} + +impl Optimize for Mem2reg { + fn optimize(&mut self, _code: &mut ir::TranslationUnit) -> bool { + todo!() + } +} diff --git a/src/opt/mod.rs b/src/opt/mod.rs new file mode 100644 index 0000000..9862d14 --- /dev/null +++ b/src/opt/mod.rs @@ -0,0 +1,55 @@ +mod gvn; +mod mem2reg; +mod simplify_cfg; + +pub use gvn::Gvn; +pub use mem2reg::Mem2reg; +pub use simplify_cfg::SimplifyCfg; + +use crate::ir; + +pub trait Translate { + type Target; + type Error; + + fn translate(&mut self, source: &S) -> Result; +} + +pub trait Optimize { + fn optimize(&mut self, code: &mut T) -> bool; +} + +#[derive(Default)] +pub struct Repeat { + inner: O, +} + +#[derive(Default)] +pub struct O0 {} + +pub type O1 = Repeat<(SimplifyCfg, (Mem2reg, Gvn))>; + +impl Optimize for O0 { + fn optimize(&mut self, _code: &mut ir::TranslationUnit) -> bool { + false + } +} + +impl, O2: Optimize> Optimize for (O1, O2) { + fn optimize(&mut self, code: &mut T) -> bool { + let changed1 = self.0.optimize(code); + let changed2 = self.1.optimize(code); + changed1 || changed2 + } +} + +impl> Optimize for Repeat { + fn optimize(&mut self, code: &mut T) -> bool { + if !self.inner.optimize(code) { + return false; + } + + while self.inner.optimize(code) {} + true + } +} diff --git a/src/opt/simplify_cfg.rs b/src/opt/simplify_cfg.rs new file mode 100644 index 0000000..7638d00 --- /dev/null +++ b/src/opt/simplify_cfg.rs @@ -0,0 +1,48 @@ +use crate::ir::*; +use crate::*; + +pub type SimplifyCfg = Repeat<(SimplifyCfgConstProp, (SimplifyCfgReach, SimplifyCfgMerge))>; + +impl Optimize for SimplifyCfg { + fn optimize(&mut self, code: &mut TranslationUnit) -> bool { + code.decls.iter_mut().any(|(_, decl)| self.optimize(decl)) + } +} + +impl Optimize for SimplifyCfg { + fn optimize(&mut self, code: &mut Declaration) -> bool { + let (_fsig, fdef) = some_or!(code.get_function_mut(), return false); + let fdef = some_or!(fdef, return false); + self.optimize(fdef) + } +} + +/// Simplifies block exits by propagating constants. +#[derive(Default)] +pub struct SimplifyCfgConstProp {} + +/// Retains only those blocks that are reachable from the init. +#[derive(Default)] +pub struct SimplifyCfgReach {} + +/// Merges two blocks if a block is pointed to only by another +#[derive(Default)] +pub struct SimplifyCfgMerge {} + +impl Optimize for SimplifyCfgConstProp { + fn optimize(&mut self, _code: &mut FunctionDefinition) -> bool { + todo!("homework 3") + } +} + +impl Optimize for SimplifyCfgReach { + fn optimize(&mut self, _code: &mut FunctionDefinition) -> bool { + todo!("homework 3") + } +} + +impl Optimize for SimplifyCfgMerge { + fn optimize(&mut self, _code: &mut FunctionDefinition) -> bool { + todo!("homework 3") + } +} diff --git a/src/optimize.rs b/src/optimize.rs deleted file mode 100644 index b583ed1..0000000 --- a/src/optimize.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::ir; -use crate::{Optimize, Repeat}; - -#[derive(Default)] -pub struct O0 {} - -#[derive(Default)] -pub struct Mem2reg {} - -#[derive(Default)] -pub struct Gvn {} - -pub type O1 = Repeat<(Mem2reg, Gvn)>; - -impl Optimize for O0 { - fn optimize(&mut self, _code: &mut ir::TranslationUnit) -> bool { - false - } -} - -impl Optimize for Mem2reg { - fn optimize(&mut self, _code: &mut ir::TranslationUnit) -> bool { - unimplemented!() - } -} - -impl Optimize for Gvn { - fn optimize(&mut self, _code: &mut ir::TranslationUnit) -> bool { - unimplemented!() - } -} diff --git a/src/tests.rs b/src/tests.rs new file mode 100644 index 0000000..3380c34 --- /dev/null +++ b/src/tests.rs @@ -0,0 +1,56 @@ +use lang_c::ast::*; +use std::fs::File; +use std::path::Path; +use std::process::Command; +use tempfile::tempdir; + +use crate::*; + +pub fn test_write_c(unit: &TranslationUnit, _path: &Path) { + let temp_dir = tempdir().expect("temp dir creation failed"); + let temp_file_path = temp_dir.path().join("temp.c"); + let mut temp_file = File::create(&temp_file_path).unwrap(); + + crate::write(unit, &mut temp_file).unwrap(); + + let new_unit = c::Parse::default() + .translate(&temp_file_path.as_path()) + .expect("parse failed while parsing the output from implemented printer"); + drop(temp_file); + c::assert_ast_equiv(&unit, &new_unit); + temp_dir.close().expect("temp dir deletion failed"); +} + +pub fn test_irgen(unit: &TranslationUnit, path: &Path) { + // Check if the file has .c extension + assert_eq!(path.extension(), Some(std::ffi::OsStr::new("c"))); + + let file_path = path.display().to_string(); + let bin_path = path.with_extension("exe").as_path().display().to_string(); + + // Compile c file + Command::new("gcc") + .args(&["-O1", &file_path, "-o", &bin_path]) + .output() + .expect("failed to compile the given program"); + + // Execute compiled executable + let status = Command::new(bin_path.clone()) + .status() + .expect("failed to execute the compiled executable") + .code() + .expect("failed to return an exit code"); + + // Remove compiled executable + Command::new("rm") + .arg(bin_path) + .status() + .expect("failed to remove compiled executable"); + + let ir = Irgen::default() + .translate(unit) + .expect("failed to generate ir"); + + let args = Vec::new(); + assert_eq!(ir::interp(&ir, args), Ok(ir::Value::Int(status))); +} diff --git a/src/utils.rs b/src/utils.rs index 369a485..4e550f9 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -44,38 +44,3 @@ macro_rules! some_or_exit { } }}; } - -pub trait Translate { - type Target; - type Error; - - fn translate(&mut self, source: &S) -> Result; -} - -pub trait Optimize { - fn optimize(&mut self, code: &mut T) -> bool; -} - -#[derive(Default)] -pub struct Repeat { - inner: O, -} - -impl, O2: Optimize> Optimize for (O1, O2) { - fn optimize(&mut self, code: &mut T) -> bool { - let changed1 = self.0.optimize(code); - let changed2 = self.1.optimize(code); - changed1 || changed2 - } -} - -impl> Optimize for Repeat { - fn optimize(&mut self, code: &mut T) -> bool { - if !self.inner.optimize(code) { - return false; - } - - while self.inner.optimize(code) {} - true - } -} diff --git a/src/write_asm.rs b/src/write_asm.rs deleted file mode 100644 index a057b20..0000000 --- a/src/write_asm.rs +++ /dev/null @@ -1,5 +0,0 @@ -use crate::asm::Asm; - -pub fn write_asm(_asm: &Asm, _write: &mut dyn ::std::io::Write) { - unimplemented!(); -} diff --git a/src/write_base.rs b/src/write_base.rs index dd5e849..495bc4b 100644 --- a/src/write_base.rs +++ b/src/write_base.rs @@ -16,3 +16,7 @@ pub trait WriteString { pub trait WriteOp { fn write_operation(&self) -> String; } + +pub fn write(t: &T, write: &mut dyn Write) -> Result<()> { + t.write_line(0, write) +} diff --git a/src/write_c_test.rs b/src/write_c_test.rs deleted file mode 100644 index d34ecfa..0000000 --- a/src/write_c_test.rs +++ /dev/null @@ -1,20 +0,0 @@ -use lang_c::ast::*; -use std::fs::File; -use tempfile::tempdir; - -use crate::*; - -pub fn write_c_test(unit: &TranslationUnit) { - let temp_dir = tempdir().expect("temp dir creation failed"); - let temp_file_path = temp_dir.path().join("temp.c"); - let mut temp_file = File::create(&temp_file_path).unwrap(); - - write_c(&unit, &mut temp_file).unwrap(); - - let new_unit = Parse::default() - .translate(&temp_file_path.as_path()) - .expect("parse failed while parsing file from implemented printer"); - drop(temp_file); - assert_ast_equiv(&unit, &new_unit); - temp_dir.close().expect("temp dir deletion failed"); -} diff --git a/tests/.gitignore b/tests/.gitignore index 922dc3d..e76cca5 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,2 +1,4 @@ /platform.info /csmith-* +/test*.c* +/reduce-criteria.sh diff --git a/tests/fuzz.py b/tests/fuzz.py index 485bc03..1b011a5 100644 --- a/tests/fuzz.py +++ b/tests/fuzz.py @@ -13,30 +13,71 @@ import itertools import argparse import sys import re +from pathlib import Path REPLACE_DICT = { - "#include \"csmith.h\"": "", "volatile ": "", - "uint16_t": "unsigned int", - "uint32_t": "unsigned int", - "int16_t": "int", - "int32_t": "int", - "uint": "unsigned int", "static ": "", + "extern ": "", + "__restrict": "", + "long __undefined;": "", + "return 0;": "return crc32_context % 128;", + r"__attribute__ \(\(.*\)\)": "", + "_Float128": "long double", + "union": "struct", + r"enum\s*\{[^\}]*\};": "", + "const char \*const sys_errlist\[\];": "", + r"[^\n]*printf[^;]*;": "", + r"[^\n]*scanf[^;]*;": "", } CSMITH_DIR = "csmith-2.3.0" -def install_csmith(tests_dir, bin_file): +def install_csmith(tests_dir): global CSMITH_DIR - csmith_root_dir = os.path.join(tests_dir, CSMITH_DIR) - if not os.path.exists(bin_file): - subprocess.Popen(["curl", "https://embed.cs.utah.edu/csmith/" + CSMITH_DIR + ".tar.gz", "-o", CSMITH_DIR + ".tar.gz"], cwd=tests_dir).communicate() - subprocess.Popen(["tar", "xzvf", CSMITH_DIR + ".tar.gz"], cwd=tests_dir).communicate() - subprocess.Popen("cmake .; make -j", shell=True, cwd=csmith_root_dir).communicate() - else: - print("Using the existing csmith...") -def generate(tests_dir, bin_file, runtime, file_name): + usr_bin_path = "/usr/bin/csmith" + usr_inc_path = "/usr/include/csmith" + if os.path.exists(usr_bin_path): + assert os.path.exists(usr_inc_path) + return usr_bin_path, usr_inc_path + + bin_path = os.path.abspath(os.path.join(tests_dir, CSMITH_DIR, "src/csmith")) + inc_path = os.path.abspath(os.path.join(tests_dir, CSMITH_DIR, "runtime")) + if not os.path.exists(bin_path): + csmith_filename = "{}.tar.gz".format(CSMITH_DIR) + try: + args = ["curl", "https://embed.cs.utah.edu/csmith/{}".format(csmith_filename), "-o", csmith_filename] + proc = subprocess.Popen(args, cwd=tests_dir) + proc.communicate() + if proc.returncode != 0: + raise Exception("Failed to download Csmith (exit code: {}): `{}`".format(proc.returncode, " ".join(args))) + except subprocess.TimeoutExpired as e: + proc.kill() + raise e + + try: + args = ["tar", "xzvf", csmith_filename] + proc = subprocess.Popen(args, cwd=tests_dir) + proc.communicate() + if proc.returncode != 0: + raise Exception("Failed to extract Csmith (exit code: {}): `{}`".format(proc.returncode, " ".join(args))) + except subprocess.TimeoutExpired as e: + proc.kill() + raise e + + csmith_root_dir = os.path.join(tests_dir, CSMITH_DIR) + try: + proc = subprocess.Popen("cmake . && make -j", shell=True, cwd=csmith_root_dir) + proc.communicate() + if proc.returncode != 0: + raise Exception("Failed to build Csmith (exit code: {})".format(proc.returncode)) + except subprocess.TimeoutExpired as e: + proc.kill() + raise e + + return bin_path, inc_path + +def generate(tests_dir, bin_path): """Feeding options to built Csmith to randomly generate test case. For generality, I disabled most of the features that are enabled by default. @@ -46,54 +87,103 @@ def generate(tests_dir, bin_file, runtime, file_name): """ global CSMITH_DIR options = [ - "--no-argc", "--no-arrays", "--no-checksum", + "--no-argc", "--no-arrays", "--no-jumps", "--no-longlong", "--no-int8", "--no-uint8", "--no-safe-math", "--no-pointers", - "--no-structs", "--no-unions", "--no-builtins" + "--no-structs", "--no-unions", "--no-builtins", ] - args = [bin_file] + options - dst_path = os.path.join(runtime, file_name) + args = [bin_path] + options - with open(dst_path, 'w') as f_dst: - subprocess.Popen(args, cwd=tests_dir, stdout=f_dst).wait() - f_dst.flush() + try: + proc = subprocess.Popen(args, cwd=tests_dir, stdout=subprocess.PIPE) + (src, err) = proc.communicate() + return src.decode() + except subprocess.TimeoutExpired as e: + proc.kill() + raise e - return dst_path - -def preprocess(src_path, file_name): - """Preprocessing test case to fit in kecc parser specification. - - It resolves an issue that arbitrarily included header file to hinder parsing. +def polish(src, inc_path): + """Polishing test case to fit in kecc parser specification. """ global REPLACE_DICT, CSMITH_DIR - with open(src_path, 'r') as src: - src = str(src.read()) - for _from, _to in REPLACE_DICT.items(): - src = src.replace(_from, _to) + try: + args = ["gcc", + "-I", inc_path, + "-E", + "-", + ] + proc = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE) + (src_preprocessed, err) = proc.communicate(src.encode()) + src_preprocessed = src_preprocessed.decode() + except subprocess.TimeoutExpired as e: + proc.kill() + raise e - with open(os.path.join(os.path.dirname(src_path), file_name), 'w') as dst: - dst.write(str(src)) + src_replaced = src_preprocessed + for _from, _to in REPLACE_DICT.items(): + src_replaced = re.sub(_from, _to, src_replaced) -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='Fuzzing KECC.') - parser.add_argument('-n', '--num', type=int, help='The number of tests') - parser.add_argument('-p', '--print', action='store_true', help='Fuzzing C AST printer') - args = parser.parse_args() + return src_replaced - if args.print: - cargo_arg = "-p" - else: - raise "Specify fuzzing argument" +def make_reduce_criteria(tests_dir, fuzz_arg): + """Make executable reduce_criteria.sh + """ + # Make shell script i.e. dependent to KECC path + arg_dict = { + "$PROJECT_DIR": str(Path(tests_dir).parent), + "$FUZZ_ARG": fuzz_arg, + } + with open(os.path.join(tests_dir, "reduce-criteria-template.sh"), "r") as t: + temp = t.read() + for _from, _to in arg_dict.items(): + temp = temp.replace(_from, _to) + with open(os.path.join(tests_dir, "reduce-criteria.sh"), "w") as f: + f.write(temp) - tests_dir = os.path.abspath(os.path.dirname(__file__)) - csmith_bin = os.path.abspath(os.path.join(tests_dir, CSMITH_DIR, "src/csmith")) - csmith_runtime = os.path.abspath(os.path.join(tests_dir, CSMITH_DIR, "runtime/")) - install_csmith(tests_dir, csmith_bin) + # chmod the script executable + try: + args = ["chmod", "u+x", "reduce-criteria.sh"] + proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=tests_dir) + proc.communicate() + if proc.returncode != 0: + raise Exception("`{}` failed with exit code {}.".format(" ".join(args), proc.returncode)) + except subprocess.TimeoutExpired as e: + proc.kill() + raise e - # Run cargo test infinitely - raw_test_file = "raw_test.c" - test_file = "test.c" +def creduce(tests_dir, fuzz_arg): + """Reduce `tests/test_polished.c` to `tests/test_reduced.c` + + First, we copy test_polished.c to test_reduced.c. + Then, when Creduce reduces test_reduced.c, it overwrites partially reduced program to itself. + Original file is moved to test_reduced.c.orig which is then identical to test_polished.c. + """ + make_reduce_criteria(tests_dir, fuzz_arg) + + try: + args = ["cp", "test_polished.c", "test_reduced.c"] + proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=tests_dir) + proc.communicate() + if proc.returncode != 0: + raise Exception("`{}` failed with exit code {}.".format(" ".join(args), proc.returncode)) + except subprocess.TimeoutExpired as e: + proc.kill() + raise e + + try: + args = ["creduce", "./reduce-criteria.sh", "test_reduced.c"] + proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=tests_dir) + (out, err) = proc.communicate() + if proc.returncode != 0: + print(out.decode()) + raise Exception("Reducing test_reduced.c by `{}` failed with exit code {}.".format(" ".join(args), proc.returncode)) + except subprocess.TimeoutExpired as e: + proc.kill() + raise e + +def fuzz(tests_dir, fuzz_arg, num_iter): + csmith_bin, csmith_inc = install_csmith(tests_dir) try: print("Building KECC..") try: @@ -103,27 +193,55 @@ if __name__ == "__main__": proc.kill() raise e - if args.num is None: + if num_iter is None: print("Fuzzing with infinitely many test cases. Please press [ctrl+C] to break.") iterator = itertools.count(0) else: - print("Fuzzing with {} test cases.".format(args.num)) - iterator = range(args.num) + print("Fuzzing with {} test cases.".format(num_iter)) + iterator = range(num_iter) for i in iterator: print("Test case #{}".format(i)) - preprocess(generate(tests_dir, csmith_bin, csmith_runtime, raw_test_file), test_file) - args = ["cargo", "run", "--release", "--bin", "fuzz", "--", cargo_arg, os.path.join(csmith_runtime, test_file)] + src = generate(tests_dir, csmith_bin) + with open(os.path.join(tests_dir, "test.c"), 'w') as dst: + dst.write(src) + + src_polished = polish(src, csmith_inc) + with open(os.path.join(tests_dir, "test_polished.c"), 'w') as dst: + dst.write(src_polished) try: + args = ["cargo", "run", "--release", "--bin", "fuzz", "--", fuzz_arg, os.path.join(tests_dir, "test_polished.c")] proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=tests_dir) - (out, err) = proc.communicate(timeout=10) + proc.communicate(timeout=10) if proc.returncode != 0: raise Exception("Test `{}` failed with exit code {}.".format(" ".join(args), proc.returncode)) except subprocess.TimeoutExpired as e: proc.kill() raise e - except KeyboardInterrupt: proc.terminate() print("\n[Ctrl+C] interrupted") + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Fuzzing KECC.') + parser.add_argument('-n', '--num', type=int, help='The number of tests') + parser.add_argument('-p', '--print', action='store_true', help='Fuzzing C AST printer') + parser.add_argument('-i', '--irgen', action='store_true', help='Fuzzing irgen') + parser.add_argument('-r', '--reduce', action='store_true', help="Reducing input file") + args = parser.parse_args() + + if args.print and args.irgen: + raise Exception("Choose an option used for fuzzing: '--print' or '--irgen', NOT both") + if args.print: + fuzz_arg = "-p" + elif args.irgen: + fuzz_arg = "-i" + else: + raise Exception("Specify fuzzing argument") + + tests_dir = os.path.abspath(os.path.dirname(__file__)) + if args.reduce: + creduce(tests_dir, fuzz_arg) + else: + fuzz(tests_dir, fuzz_arg, args.num) diff --git a/tests/reduce-criteria-template.sh b/tests/reduce-criteria-template.sh new file mode 100644 index 0000000..f6dddd5 --- /dev/null +++ b/tests/reduce-criteria-template.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +! cargo run --manifest-path $PROJECT_DIR/Cargo.toml --release --bin fuzz -- $FUZZ_ARG test_reduced.c diff --git a/tests/test_examples.rs b/tests/test_examples.rs index 1e5d98d..142b8fd 100644 --- a/tests/test_examples.rs +++ b/tests/test_examples.rs @@ -1,47 +1,43 @@ +use std::ffi::OsStr; 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), + F: Fn(&TranslationUnit, &Path), { 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() { + + if !(path.is_file() && path.extension() == Some(&OsStr::new("c"))) { 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(), + &format!( + "parse failed {:?}", + path.clone().into_os_string().to_str().unwrap() + ) + .to_owned(), ); - f(&test_unit); + f(&test_unit, &path); } } #[test] fn test_examples_write_c() { - test_dir(Path::new("examples/"), write_c_test); - test_dir(Path::new("examples/hw1"), write_c_test); + test_dir(Path::new("examples/"), test_write_c); + test_dir(Path::new("examples/hw1"), test_write_c); } #[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))); - }); + test_dir(Path::new("examples/"), test_irgen); }