mirror of
https://github.com/kmc7468/cs420.git
synced 2025-12-14 22:38:46 +00:00
Update skeleton
This commit is contained in:
20
Cargo.lock
generated
20
Cargo.lock
generated
@@ -13,7 +13,7 @@ name = "atty"
|
|||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hermit-abi 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@@ -39,7 +39,7 @@ name = "backtrace-sys"
|
|||||||
version = "0.1.36"
|
version = "0.1.36"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cc 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.50"
|
version = "1.0.52"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -94,7 +94,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.1.11"
|
version = "0.1.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -325,7 +325,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.17"
|
version = "1.0.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -348,7 +348,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -437,14 +437,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum backtrace 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)" = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e"
|
"checksum backtrace 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)" = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e"
|
||||||
"checksum backtrace-sys 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "78848718ee1255a2485d1309ad9cdecfc2e7d0362dd11c6829364c6b35ae1bc7"
|
"checksum backtrace-sys 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "78848718ee1255a2485d1309ad9cdecfc2e7d0362dd11c6829364c6b35ae1bc7"
|
||||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||||
"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd"
|
"checksum cc 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)" = "c3d87b23d6a92cd03af510a5ade527033f6aa6fa92161e2d5863a907d4c5e31d"
|
||||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
||||||
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
|
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
|
||||||
"checksum failure 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b"
|
"checksum failure 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b"
|
||||||
"checksum failure_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231"
|
"checksum failure_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231"
|
||||||
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
||||||
"checksum hermit-abi 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8a0d737e0f947a1864e93d33fdef4af8445a00d1ed8dc0c8ddb73139ea6abf15"
|
"checksum hermit-abi 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "61565ff7aaace3525556587bd2dc31d4a07071957be715e63ce7b1eccf51a8f4"
|
||||||
"checksum hexf 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e54653cc32d838771a36532647afad59c4bf7155745eeeec406f71fd5d7e7538"
|
"checksum hexf 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e54653cc32d838771a36532647afad59c4bf7155745eeeec406f71fd5d7e7538"
|
||||||
"checksum hexf-impl 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "22eadcfadba76a730b2764eaa577d045f35e0ef5174b9c5b46adf1ee42b85e12"
|
"checksum hexf-impl 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "22eadcfadba76a730b2764eaa577d045f35e0ef5174b9c5b46adf1ee42b85e12"
|
||||||
"checksum hexf-parse 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "79296f72d53a89096cbc9a88c9547ee8dfe793388674620e2207593d370550ac"
|
"checksum hexf-parse 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "79296f72d53a89096cbc9a88c9547ee8dfe793388674620e2207593d370550ac"
|
||||||
@@ -471,7 +471,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
|
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
|
||||||
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||||
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
|
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
|
||||||
"checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03"
|
"checksum syn 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "410a7488c0a728c7ceb4ad59b9567eb4053d02e8cc7f5c0e0eeeb39518369213"
|
||||||
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
|
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
|
||||||
"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
|
"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
|
||||||
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
||||||
|
|||||||
30
README.md
30
README.md
@@ -98,5 +98,31 @@ reduces the program; check if the reduced program still fails on the test, and i
|
|||||||
given program with the reduced one; repeat until you get a small enough buggy program. For more
|
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.
|
information, we refer to the [Creduce](https://embed.cs.utah.edu/creduce/) homepage.
|
||||||
|
|
||||||
**[NOTICE]** The fuzzer supports Ubuntu 18.04 only. It may work for other platforms, but if it
|
**[NOTICE]** The fuzzer supports Ubuntu 18.04 or 20.04 only. It may work for other platforms, but if it
|
||||||
doesn't, please run the fuzzer in Ubuntu 18.04.
|
doesn't, please run the fuzzer in Ubuntu 18.04 or 20.04.
|
||||||
|
|
||||||
|
|
||||||
|
## Running RISC-V Binaries
|
||||||
|
|
||||||
|
### Install
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Ubuntu 20.04 or higher
|
||||||
|
apt install gcc-10-riscv64-linux-gnu qemu-user-static
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cross-Compilation and Architecture-Emulation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Compile C source code into RISC-V assembly
|
||||||
|
riscv64-linux-gnu-gcc-10 hello.c -S -o hello.S
|
||||||
|
|
||||||
|
# Link to an RISC-V executable
|
||||||
|
riscv64-linux-gnu-gcc-10 -static hello.S -o hello
|
||||||
|
|
||||||
|
# Emulate the executable
|
||||||
|
qemu-riscv64-static ./hello
|
||||||
|
|
||||||
|
# Check the return value
|
||||||
|
echo $?
|
||||||
|
```
|
||||||
|
|||||||
35
examples/c/float.c
Normal file
35
examples/c/float.c
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
double custom_abs(double a) {
|
||||||
|
return a < 0 ? -a : a;
|
||||||
|
}
|
||||||
|
|
||||||
|
double custom_max(double a, double b) {
|
||||||
|
return a > b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_close(double a, double b, double rel_tol, double abs_tol) {
|
||||||
|
return custom_abs(a - b) <= custom_max(rel_tol * custom_max(custom_abs(a), custom_abs(b)), abs_tol);
|
||||||
|
}
|
||||||
|
|
||||||
|
double average(int len, int a[10]) {
|
||||||
|
int sum = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < len; i++) {
|
||||||
|
sum += a[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return (double) sum / len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int a[10];
|
||||||
|
int len = 10;
|
||||||
|
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
a[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
float avg = average(len, a);
|
||||||
|
|
||||||
|
return is_close(avg, 4.5, 1e-09, 0.1);
|
||||||
|
}
|
||||||
3205
examples/c/float2.c
Normal file
3205
examples/c/float2.c
Normal file
File diff suppressed because it is too large
Load Diff
59
examples/c/float2_gen.py
Normal file
59
examples/c/float2_gen.py
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
"""Make c program which uses floating point variables
|
||||||
|
|
||||||
|
To make c program, execute `python3 float_gen.py > file_name.c`
|
||||||
|
"""
|
||||||
|
|
||||||
|
import random
|
||||||
|
|
||||||
|
def random_operator():
|
||||||
|
ops = ["+", "-", "*", "/"]
|
||||||
|
return ops[random.randint(0, len(ops) - 1)]
|
||||||
|
|
||||||
|
def random_dtype():
|
||||||
|
dtypes = ["float", "double"]
|
||||||
|
return dtypes[random.randint(0, len(dtypes) - 1)]
|
||||||
|
|
||||||
|
def random_suffix():
|
||||||
|
suffixes = ["f", ""]
|
||||||
|
return suffixes[random.randint(0, len(suffixes) - 1)]
|
||||||
|
|
||||||
|
def make_expr(vars):
|
||||||
|
if len(vars) == 1:
|
||||||
|
return vars[0]
|
||||||
|
else:
|
||||||
|
var = vars.pop()
|
||||||
|
return "(" + var + " " + random_operator() + " " + make_expr(vars) + ")"
|
||||||
|
|
||||||
|
def make_func(i):
|
||||||
|
"""Make a function that contains a conditional expression
|
||||||
|
"""
|
||||||
|
func_signature = random_dtype() + " func_" + str(i) + "()"
|
||||||
|
variables = "abcdefghijklmnopqrstuvwxyzA"
|
||||||
|
func_inner = []
|
||||||
|
val_bitmap = []
|
||||||
|
|
||||||
|
# Variable initializiation
|
||||||
|
for var in variables:
|
||||||
|
val = random.gauss(0, 1)
|
||||||
|
val_bitmap.append(val)
|
||||||
|
decl = "\t" + random_dtype() + " " + var + " = " + str(val) + random_suffix() + ";"
|
||||||
|
func_inner.append(decl)
|
||||||
|
|
||||||
|
func_inner.append("\treturn " + make_expr(list(variables)) + ";")
|
||||||
|
|
||||||
|
return "\n".join([func_signature, "{"] + func_inner + ["}"])
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
src = ""
|
||||||
|
return_stmt = "\treturn (int)("
|
||||||
|
NUM_FUNC = 100
|
||||||
|
for i in range(NUM_FUNC):
|
||||||
|
src += make_func(i)
|
||||||
|
src += "\n\n"
|
||||||
|
return_stmt += "func_" + str(i) + "()"
|
||||||
|
return_stmt += " " + random_operator() + " " if i != (NUM_FUNC - 1) else ");"
|
||||||
|
src += "int main()\n{\n" + return_stmt + "\n}\n"
|
||||||
|
|
||||||
|
print(src)
|
||||||
@@ -1,22 +1,23 @@
|
|||||||
struct color { int number; char name; };
|
struct color { int number; char name; };
|
||||||
|
|
||||||
int f(int i, int const a[i]) {
|
int main() {
|
||||||
int temp = 0;
|
int temp = 0;
|
||||||
const float temp2 = 0.f, temp3 = 0.f;
|
temp += sizeof(unsigned char);
|
||||||
temp = sizeof(unsigned char);
|
temp += _Alignof(unsigned char);
|
||||||
temp = _Alignof(unsigned char);
|
|
||||||
|
|
||||||
struct color c;
|
struct color c = {1, 2};
|
||||||
c.name;
|
temp += c.name;
|
||||||
struct color *cp = &c;
|
struct color *cp = &c;
|
||||||
cp->name;
|
temp += cp->name;
|
||||||
|
|
||||||
for(int i = 0, j = 0; i < 10; ++i) {
|
for(int i = 0, j = 0; i < 10; ++i) {
|
||||||
break;
|
if ( i == 2 && j == 0) break;
|
||||||
|
temp += i;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(temp) {
|
switch(temp) {
|
||||||
case 1: {
|
case 1: {
|
||||||
|
temp = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
|||||||
@@ -45,3 +45,9 @@ impl WriteLine for TranslationUnit {
|
|||||||
todo!("homework 1")
|
todo!("homework 1")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl WriteString for Initializer {
|
||||||
|
fn write_string(&self) -> String {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -721,9 +721,22 @@ impl Dtype {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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::Array { .. } => true,
|
||||||
|
Self::Struct { is_const, .. } => *is_const,
|
||||||
|
Self::Function { .. } => true,
|
||||||
|
Self::Typedef { is_const, .. } => *is_const,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Check if `Dtype` is constant. if it is constant, the variable of `Dtype` is not assignable.
|
/// Check if `Dtype` is constant. if it is constant, the variable of `Dtype` is not assignable.
|
||||||
pub fn is_const(&self, structs: &HashMap<String, Option<Dtype>>) -> bool {
|
pub fn is_immutable(&self, structs: &HashMap<String, Option<Dtype>>) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Unit { is_const } => *is_const,
|
Self::Unit { is_const } => *is_const,
|
||||||
Self::Int { is_const, .. } => *is_const,
|
Self::Int { is_const, .. } => *is_const,
|
||||||
@@ -751,9 +764,9 @@ impl Dtype {
|
|||||||
// If an array is wrapped in a struct and the array's inner type is not
|
// If an array is wrapped in a struct and the array's inner type is not
|
||||||
// constant, it is assignable to another object of the same struct type.
|
// constant, it is assignable to another object of the same struct type.
|
||||||
if let Self::Array { inner, .. } = f.deref() {
|
if let Self::Array { inner, .. } = f.deref() {
|
||||||
inner.is_const_for_array_struct_field_inner(structs)
|
inner.is_immutable_for_array_struct_field_inner(structs)
|
||||||
} else {
|
} else {
|
||||||
f.deref().is_const(structs)
|
f.deref().is_immutable(structs)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -762,14 +775,14 @@ impl Dtype {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_const_for_array_struct_field_inner(
|
fn is_immutable_for_array_struct_field_inner(
|
||||||
&self,
|
&self,
|
||||||
structs: &HashMap<String, Option<Dtype>>,
|
structs: &HashMap<String, Option<Dtype>>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if let Self::Array { inner, .. } = self {
|
if let Self::Array { inner, .. } = self {
|
||||||
inner.is_const_for_array_struct_field_inner(structs)
|
inner.is_immutable_for_array_struct_field_inner(structs)
|
||||||
} else {
|
} else {
|
||||||
self.is_const(structs)
|
self.is_immutable(structs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -850,16 +863,23 @@ impl Dtype {
|
|||||||
field_name: &str,
|
field_name: &str,
|
||||||
structs: &HashMap<String, Option<Dtype>>,
|
structs: &HashMap<String, Option<Dtype>>,
|
||||||
) -> Option<(usize, Self)> {
|
) -> Option<(usize, Self)> {
|
||||||
if let Self::Struct {
|
if let Self::Struct { name, .. } = self {
|
||||||
fields,
|
let struct_name = name.as_ref().expect("`self` must have its name");
|
||||||
size_align_offsets,
|
let struct_type = structs
|
||||||
..
|
.get(struct_name)
|
||||||
} = self
|
.expect("`structs` must have value matched with `struct_name`")
|
||||||
{
|
|
||||||
let fields = fields.as_ref().expect("struct should have its definition");
|
|
||||||
let (_, _, offsets) = size_align_offsets
|
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.expect("struct should have `offsets` as `Some`");
|
.expect("`struct_type` must have its definition");
|
||||||
|
let fields = struct_type
|
||||||
|
.get_struct_fields()
|
||||||
|
.expect("`struct_type` must be struct type")
|
||||||
|
.as_ref()
|
||||||
|
.expect("`fields` must be `Some`");
|
||||||
|
let (_, _, offsets) = struct_type
|
||||||
|
.get_struct_size_align_offsets()
|
||||||
|
.expect("`struct_type` must be struct type")
|
||||||
|
.as_ref()
|
||||||
|
.expect("`offsets` must be `Some`");
|
||||||
|
|
||||||
assert_eq!(fields.len(), offsets.len());
|
assert_eq!(fields.len(), offsets.len());
|
||||||
for (field, offset) in izip!(fields, offsets) {
|
for (field, offset) in izip!(fields, offsets) {
|
||||||
@@ -869,19 +889,8 @@ impl Dtype {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let field_dtype = field.deref();
|
let field_dtype = field.deref();
|
||||||
let struct_name = field_dtype
|
|
||||||
.get_struct_name()
|
|
||||||
.expect("`field_dtype` must be struct type")
|
|
||||||
.as_ref()
|
|
||||||
.expect("structure type must have its name");
|
|
||||||
let struct_type = structs
|
|
||||||
.get(struct_name)
|
|
||||||
.expect("`structs` must have value matched with `struct_name`")
|
|
||||||
.as_ref()
|
|
||||||
.expect("`struct_type` must have its definition");
|
|
||||||
|
|
||||||
let (offset_inner, dtype) = some_or!(
|
let (offset_inner, dtype) = some_or!(
|
||||||
struct_type.get_offset_struct_field(field_name, structs),
|
field_dtype.get_offset_struct_field(field_name, structs),
|
||||||
continue
|
continue
|
||||||
);
|
);
|
||||||
return Some((*offset + offset_inner, dtype));
|
return Some((*offset + offset_inner, dtype));
|
||||||
@@ -1115,7 +1124,7 @@ impl Dtype {
|
|||||||
message: format!("unknown type name `{}`", name),
|
message: format!("unknown type name `{}`", name),
|
||||||
})?
|
})?
|
||||||
.clone();
|
.clone();
|
||||||
let is_const = dtype.is_const(structs) || *is_const;
|
let is_const = dtype.is_const() || *is_const;
|
||||||
|
|
||||||
dtype.set_const(is_const)
|
dtype.set_const(is_const)
|
||||||
}
|
}
|
||||||
|
|||||||
460
src/ir/interp.rs
460
src/ir/interp.rs
@@ -2,6 +2,7 @@ use core::fmt;
|
|||||||
use core::iter;
|
use core::iter;
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use failure::Fail;
|
use failure::Fail;
|
||||||
|
use ordered_float::OrderedFloat;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use itertools::izip;
|
use itertools::izip;
|
||||||
@@ -33,7 +34,7 @@ pub enum Value {
|
|||||||
/// * Casting from an f32 to an f64 is perfect and lossless (f32 -> 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)
|
/// * 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
|
/// https://doc.rust-lang.org/stable/reference/expressions/operator-expr.html#type-cast-expressions
|
||||||
value: f64,
|
value: OrderedFloat<f64>,
|
||||||
width: usize,
|
width: usize,
|
||||||
},
|
},
|
||||||
Pointer {
|
Pointer {
|
||||||
@@ -67,10 +68,7 @@ impl TryFrom<Constant> for Value {
|
|||||||
width,
|
width,
|
||||||
is_signed,
|
is_signed,
|
||||||
},
|
},
|
||||||
Constant::Float { value, width } => Self::Float {
|
Constant::Float { value, width } => Self::Float { value, width },
|
||||||
value: value.into_inner(),
|
|
||||||
width,
|
|
||||||
},
|
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -125,7 +123,10 @@ impl Value {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn float(value: f64, width: usize) -> Self {
|
fn float(value: f64, width: usize) -> Self {
|
||||||
Self::Float { value, width }
|
Self::Float {
|
||||||
|
value: value.into(),
|
||||||
|
width,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -421,6 +422,187 @@ mod calculator {
|
|||||||
use super::Value;
|
use super::Value;
|
||||||
use crate::ir::*;
|
use crate::ir::*;
|
||||||
use lang_c::ast;
|
use lang_c::ast;
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
fn calculate_integer_binary_operator_expression(
|
||||||
|
op: &ast::BinaryOperator,
|
||||||
|
lhs: u128,
|
||||||
|
rhs: u128,
|
||||||
|
width: usize,
|
||||||
|
is_signed: bool,
|
||||||
|
) -> Result<Value, ()> {
|
||||||
|
let result = match op {
|
||||||
|
// TODO: explain why plus & minus do not need to consider `is_signed'
|
||||||
|
ast::BinaryOperator::Plus => (lhs as i128 + rhs as i128) as u128,
|
||||||
|
ast::BinaryOperator::Minus => (lhs as i128 - rhs as i128) as u128,
|
||||||
|
ast::BinaryOperator::Multiply => {
|
||||||
|
if is_signed {
|
||||||
|
(lhs as i128 * rhs as i128) as u128
|
||||||
|
} else {
|
||||||
|
lhs * rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::BinaryOperator::Divide => {
|
||||||
|
assert!(rhs != 0);
|
||||||
|
if is_signed {
|
||||||
|
(lhs as i128 / rhs as i128) as u128
|
||||||
|
} else {
|
||||||
|
lhs / rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::BinaryOperator::Modulo => {
|
||||||
|
assert!(rhs != 0);
|
||||||
|
if is_signed {
|
||||||
|
(lhs as i128 % rhs as i128) as u128
|
||||||
|
} else {
|
||||||
|
lhs % rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::BinaryOperator::ShiftLeft => {
|
||||||
|
let rhs = if is_signed {
|
||||||
|
let rhs = rhs as i128;
|
||||||
|
assert!(rhs >= 0);
|
||||||
|
assert!(rhs < (width as i128));
|
||||||
|
rhs as u128
|
||||||
|
} else {
|
||||||
|
assert!(rhs < (width as u128));
|
||||||
|
rhs
|
||||||
|
};
|
||||||
|
|
||||||
|
lhs << rhs
|
||||||
|
}
|
||||||
|
ast::BinaryOperator::ShiftRight => {
|
||||||
|
if is_signed {
|
||||||
|
// arithmetic shift right
|
||||||
|
let rhs = rhs as i128;
|
||||||
|
assert!(rhs >= 0);
|
||||||
|
assert!(rhs < (width as i128));
|
||||||
|
((lhs as i128) >> rhs) as u128
|
||||||
|
} else {
|
||||||
|
// logical shift right
|
||||||
|
assert!(rhs < (width as u128));
|
||||||
|
let bit_mask = (1u128 << width as u128) - 1;
|
||||||
|
let lhs = lhs & bit_mask;
|
||||||
|
lhs >> rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::BinaryOperator::BitwiseAnd => lhs & rhs,
|
||||||
|
ast::BinaryOperator::BitwiseXor => lhs ^ rhs,
|
||||||
|
ast::BinaryOperator::BitwiseOr => lhs | rhs,
|
||||||
|
ast::BinaryOperator::Equals => {
|
||||||
|
let result = if lhs == rhs { 1 } else { 0 };
|
||||||
|
return Ok(Value::int(result, 1, false));
|
||||||
|
}
|
||||||
|
ast::BinaryOperator::NotEquals => {
|
||||||
|
let result = if lhs != rhs { 1 } else { 0 };
|
||||||
|
return Ok(Value::int(result, 1, false));
|
||||||
|
}
|
||||||
|
ast::BinaryOperator::Less => {
|
||||||
|
let condition = if is_signed {
|
||||||
|
(lhs as i128) < (rhs as i128)
|
||||||
|
} else {
|
||||||
|
lhs < rhs
|
||||||
|
};
|
||||||
|
let result = if condition { 1 } else { 0 };
|
||||||
|
return Ok(Value::int(result, 1, false));
|
||||||
|
}
|
||||||
|
ast::BinaryOperator::Greater => {
|
||||||
|
let condition = if is_signed {
|
||||||
|
(lhs as i128) > (rhs as i128)
|
||||||
|
} else {
|
||||||
|
lhs > rhs
|
||||||
|
};
|
||||||
|
let result = if condition { 1 } else { 0 };
|
||||||
|
return Ok(Value::int(result, 1, false));
|
||||||
|
}
|
||||||
|
ast::BinaryOperator::LessOrEqual => {
|
||||||
|
let condition = if is_signed {
|
||||||
|
(lhs as i128) <= (rhs as i128)
|
||||||
|
} else {
|
||||||
|
lhs <= rhs
|
||||||
|
};
|
||||||
|
let result = if condition { 1 } else { 0 };
|
||||||
|
return Ok(Value::int(result, 1, false));
|
||||||
|
}
|
||||||
|
ast::BinaryOperator::GreaterOrEqual => {
|
||||||
|
let condition = if is_signed {
|
||||||
|
(lhs as i128) >= (rhs as i128)
|
||||||
|
} else {
|
||||||
|
lhs >= rhs
|
||||||
|
};
|
||||||
|
let result = if condition { 1 } else { 0 };
|
||||||
|
return Ok(Value::int(result, 1, false));
|
||||||
|
}
|
||||||
|
_ => todo!(
|
||||||
|
"calculate_binary_operator_expression: not supported operator {:?}",
|
||||||
|
op
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = if is_signed {
|
||||||
|
sign_extension(result, width as u128)
|
||||||
|
} else {
|
||||||
|
trim_unnecessary_bits(result, width as u128)
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Value::int(result, width, is_signed))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calculate_float_binary_operator_expression(
|
||||||
|
op: &ast::BinaryOperator,
|
||||||
|
lhs: OrderedFloat<f64>,
|
||||||
|
rhs: OrderedFloat<f64>,
|
||||||
|
width: usize,
|
||||||
|
) -> Result<Value, ()> {
|
||||||
|
let result = match op {
|
||||||
|
ast::BinaryOperator::Plus => lhs.into_inner() + rhs.into_inner(),
|
||||||
|
ast::BinaryOperator::Minus => lhs.into_inner() - rhs.into_inner(),
|
||||||
|
ast::BinaryOperator::Multiply => lhs.into_inner() * rhs.into_inner(),
|
||||||
|
ast::BinaryOperator::Divide => {
|
||||||
|
assert!(rhs.into_inner() != 0.0);
|
||||||
|
lhs.into_inner() / rhs.into_inner()
|
||||||
|
}
|
||||||
|
ast::BinaryOperator::Equals => {
|
||||||
|
let order = lhs
|
||||||
|
.partial_cmp(&rhs)
|
||||||
|
.expect("`lhs` and `rhs` must be not NAN");
|
||||||
|
let result = if Ordering::Equal == order { 1 } else { 0 };
|
||||||
|
return Ok(Value::int(result, 1, false));
|
||||||
|
}
|
||||||
|
ast::BinaryOperator::NotEquals => {
|
||||||
|
let order = lhs
|
||||||
|
.partial_cmp(&rhs)
|
||||||
|
.expect("`lhs` and `rhs` must be not NAN");
|
||||||
|
let result = if Ordering::Equal != order { 1 } else { 0 };
|
||||||
|
return Ok(Value::int(result, 1, false));
|
||||||
|
}
|
||||||
|
ast::BinaryOperator::Less => {
|
||||||
|
let result = if lhs.lt(&rhs) { 1 } else { 0 };
|
||||||
|
return Ok(Value::int(result, 1, false));
|
||||||
|
}
|
||||||
|
ast::BinaryOperator::Greater => {
|
||||||
|
let result = if lhs.gt(&rhs) { 1 } else { 0 };
|
||||||
|
return Ok(Value::int(result, 1, false));
|
||||||
|
}
|
||||||
|
ast::BinaryOperator::LessOrEqual => {
|
||||||
|
let result = if lhs.le(&rhs) { 1 } else { 0 };
|
||||||
|
return Ok(Value::int(result, 1, false));
|
||||||
|
}
|
||||||
|
ast::BinaryOperator::GreaterOrEqual => {
|
||||||
|
let result = if lhs.ge(&rhs) { 1 } else { 0 };
|
||||||
|
return Ok(Value::int(result, 1, false));
|
||||||
|
}
|
||||||
|
_ => todo!(
|
||||||
|
"calculate_binary_operator_expression: not supported case for \
|
||||||
|
{:?} {:?} {:?}",
|
||||||
|
op,
|
||||||
|
lhs,
|
||||||
|
rhs
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Value::float(result, width))
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: change to template function in the future
|
// TODO: change to template function in the future
|
||||||
pub fn calculate_binary_operator_expression(
|
pub fn calculate_binary_operator_expression(
|
||||||
@@ -428,11 +610,10 @@ mod calculator {
|
|||||||
lhs: Value,
|
lhs: Value,
|
||||||
rhs: Value,
|
rhs: Value,
|
||||||
) -> Result<Value, ()> {
|
) -> Result<Value, ()> {
|
||||||
match (op, lhs, rhs) {
|
match (lhs, rhs) {
|
||||||
(_, Value::Undef { .. }, _) => Err(()),
|
(Value::Undef { .. }, _) => Err(()),
|
||||||
(_, _, Value::Undef { .. }) => Err(()),
|
(_, Value::Undef { .. }) => Err(()),
|
||||||
(
|
(
|
||||||
op,
|
|
||||||
Value::Int {
|
Value::Int {
|
||||||
value: lhs,
|
value: lhs,
|
||||||
width: lhs_w,
|
width: lhs_w,
|
||||||
@@ -447,121 +628,38 @@ mod calculator {
|
|||||||
assert_eq!(lhs_w, rhs_w);
|
assert_eq!(lhs_w, rhs_w);
|
||||||
assert_eq!(lhs_s, rhs_s);
|
assert_eq!(lhs_s, rhs_s);
|
||||||
|
|
||||||
let result = match op {
|
calculate_integer_binary_operator_expression(op, lhs, rhs, lhs_w, lhs_s)
|
||||||
// TODO: explain why plus & minus do not need to consider `is_signed'
|
|
||||||
ast::BinaryOperator::Plus => (lhs as i128 + rhs as i128) as u128,
|
|
||||||
ast::BinaryOperator::Minus => (lhs as i128 - rhs as i128) as u128,
|
|
||||||
ast::BinaryOperator::Multiply => {
|
|
||||||
if lhs_s {
|
|
||||||
(lhs as i128 * rhs as i128) as u128
|
|
||||||
} else {
|
|
||||||
lhs * rhs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast::BinaryOperator::Divide => {
|
|
||||||
if lhs_s {
|
|
||||||
(lhs as i128 / rhs as i128) as u128
|
|
||||||
} else {
|
|
||||||
lhs / rhs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast::BinaryOperator::Modulo => {
|
|
||||||
if lhs_s {
|
|
||||||
(lhs as i128 % rhs as i128) as u128
|
|
||||||
} else {
|
|
||||||
lhs % rhs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast::BinaryOperator::ShiftLeft => {
|
|
||||||
let rhs = if lhs_s {
|
|
||||||
let rhs = rhs as i128;
|
|
||||||
assert!(rhs >= 0);
|
|
||||||
assert!(rhs < (lhs_w as i128));
|
|
||||||
rhs as u128
|
|
||||||
} else {
|
|
||||||
assert!(rhs < (lhs_w as u128));
|
|
||||||
rhs
|
|
||||||
};
|
|
||||||
|
|
||||||
lhs << rhs
|
|
||||||
}
|
|
||||||
ast::BinaryOperator::ShiftRight => {
|
|
||||||
if lhs_s {
|
|
||||||
// arithmetic shift right
|
|
||||||
let rhs = rhs as i128;
|
|
||||||
assert!(rhs >= 0);
|
|
||||||
assert!(rhs < (lhs_w as i128));
|
|
||||||
((lhs as i128) >> rhs) as u128
|
|
||||||
} else {
|
|
||||||
// logical shift right
|
|
||||||
assert!(rhs < (lhs_w as u128));
|
|
||||||
let bit_mask = (1u128 << lhs_w as u128) - 1;
|
|
||||||
let lhs = lhs & bit_mask;
|
|
||||||
lhs >> rhs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast::BinaryOperator::BitwiseAnd => lhs & rhs,
|
|
||||||
ast::BinaryOperator::BitwiseXor => lhs ^ rhs,
|
|
||||||
ast::BinaryOperator::BitwiseOr => lhs | rhs,
|
|
||||||
ast::BinaryOperator::Equals => {
|
|
||||||
let result = if lhs == rhs { 1 } else { 0 };
|
|
||||||
return Ok(Value::int(result, 1, false));
|
|
||||||
}
|
|
||||||
ast::BinaryOperator::NotEquals => {
|
|
||||||
let result = if lhs != rhs { 1 } else { 0 };
|
|
||||||
return Ok(Value::int(result, 1, false));
|
|
||||||
}
|
|
||||||
ast::BinaryOperator::Less => {
|
|
||||||
let condition = if lhs_s {
|
|
||||||
(lhs as i128) < (rhs as i128)
|
|
||||||
} else {
|
|
||||||
lhs < rhs
|
|
||||||
};
|
|
||||||
let result = if condition { 1 } else { 0 };
|
|
||||||
return Ok(Value::int(result, 1, false));
|
|
||||||
}
|
|
||||||
ast::BinaryOperator::Greater => {
|
|
||||||
let condition = if lhs_s {
|
|
||||||
(lhs as i128) > (rhs as i128)
|
|
||||||
} else {
|
|
||||||
lhs > rhs
|
|
||||||
};
|
|
||||||
let result = if condition { 1 } else { 0 };
|
|
||||||
return Ok(Value::int(result, 1, false));
|
|
||||||
}
|
|
||||||
ast::BinaryOperator::LessOrEqual => {
|
|
||||||
let condition = if lhs_s {
|
|
||||||
(lhs as i128) <= (rhs as i128)
|
|
||||||
} else {
|
|
||||||
lhs <= rhs
|
|
||||||
};
|
|
||||||
let result = if condition { 1 } else { 0 };
|
|
||||||
return Ok(Value::int(result, 1, false));
|
|
||||||
}
|
|
||||||
ast::BinaryOperator::GreaterOrEqual => {
|
|
||||||
let condition = if lhs_s {
|
|
||||||
(lhs as i128) >= (rhs as i128)
|
|
||||||
} else {
|
|
||||||
lhs >= rhs
|
|
||||||
};
|
|
||||||
let result = if condition { 1 } else { 0 };
|
|
||||||
return Ok(Value::int(result, 1, false));
|
|
||||||
}
|
|
||||||
_ => todo!(
|
|
||||||
"calculate_binary_operator_expression: not supported operator {:?}",
|
|
||||||
op
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = if lhs_s {
|
|
||||||
sign_extension(result, lhs_w as u128)
|
|
||||||
} else {
|
|
||||||
trim_unnecessary_bits(result, lhs_w as u128)
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Value::int(result, lhs_w, lhs_s))
|
|
||||||
}
|
}
|
||||||
(op, lhs, rhs) => todo!(
|
(
|
||||||
|
Value::Float {
|
||||||
|
value: lhs,
|
||||||
|
width: lhs_w,
|
||||||
|
},
|
||||||
|
Value::Float {
|
||||||
|
value: rhs,
|
||||||
|
width: rhs_w,
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
assert_eq!(lhs_w, rhs_w);
|
||||||
|
|
||||||
|
calculate_float_binary_operator_expression(op, lhs, rhs, lhs_w)
|
||||||
|
}
|
||||||
|
(Value::Pointer { bid, .. }, Value::Pointer { bid: other_bid, .. }) => match op {
|
||||||
|
ast::BinaryOperator::Equals => {
|
||||||
|
let result = if bid == other_bid { 1 } else { 0 };
|
||||||
|
Ok(Value::int(result, 1, false))
|
||||||
|
}
|
||||||
|
ast::BinaryOperator::NotEquals => {
|
||||||
|
let result = if bid != other_bid { 1 } else { 0 };
|
||||||
|
Ok(Value::int(result, 1, false))
|
||||||
|
}
|
||||||
|
_ => todo!(
|
||||||
|
"calculate_binary_operator_expression: not supported case for \
|
||||||
|
{:?} between pointer and integer value",
|
||||||
|
op,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
(lhs, rhs) => todo!(
|
||||||
"calculate_binary_operator_expression: not supported case for {:?} {:?} {:?}",
|
"calculate_binary_operator_expression: not supported case for {:?} {:?} {:?}",
|
||||||
op,
|
op,
|
||||||
lhs,
|
lhs,
|
||||||
@@ -574,48 +672,47 @@ mod calculator {
|
|||||||
op: &ast::UnaryOperator,
|
op: &ast::UnaryOperator,
|
||||||
operand: Value,
|
operand: Value,
|
||||||
) -> Result<Value, ()> {
|
) -> Result<Value, ()> {
|
||||||
match (op, operand) {
|
match operand {
|
||||||
(_, Value::Undef { .. }) => Err(()),
|
Value::Undef { .. } => Err(()),
|
||||||
(
|
Value::Int {
|
||||||
ast::UnaryOperator::Plus,
|
value,
|
||||||
Value::Int {
|
width,
|
||||||
value,
|
is_signed,
|
||||||
width,
|
} => {
|
||||||
is_signed,
|
match op {
|
||||||
},
|
ast::UnaryOperator::Plus => Ok(Value::int(value, width, is_signed)),
|
||||||
) => Ok(Value::int(value, width, is_signed)),
|
ast::UnaryOperator::Minus => {
|
||||||
(
|
let result = if is_signed {
|
||||||
ast::UnaryOperator::Minus,
|
(-(value as i128)) as u128
|
||||||
Value::Int {
|
} else {
|
||||||
value,
|
let value = (-(value as i128)) as u128;
|
||||||
width,
|
trim_unnecessary_bits(value, width as u128)
|
||||||
is_signed,
|
};
|
||||||
},
|
Ok(Value::int(result as u128, width, is_signed))
|
||||||
) => {
|
}
|
||||||
// TODO: check what is exact behavior of appling minus to unsigned value
|
ast::UnaryOperator::Negate => {
|
||||||
let result = if is_signed {
|
// Check if it is boolean
|
||||||
(-(value as i128)) as u128
|
assert!(width == 1);
|
||||||
} else {
|
let result = if value == 0 { 1 } else { 0 };
|
||||||
let result = (-(value as i128)) as u128;
|
Ok(Value::int(result, width, is_signed))
|
||||||
let bit_mask = (1u128 << (width as u128)) - 1;
|
}
|
||||||
result & bit_mask
|
_ => todo!(
|
||||||
};
|
"calculate_unary_operator_expression: not supported case for {:?} {:?}",
|
||||||
Ok(Value::int(result as u128, width, is_signed))
|
op,
|
||||||
|
operand,
|
||||||
|
),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
(
|
Value::Float { value, width } => match op {
|
||||||
ast::UnaryOperator::Negate,
|
ast::UnaryOperator::Plus => Ok(Value::float(value.into_inner(), width)),
|
||||||
Value::Int {
|
ast::UnaryOperator::Minus => Ok(Value::float(-value.into_inner(), width)),
|
||||||
value,
|
_ => todo!(
|
||||||
width,
|
"calculate_unary_operator_expression: not supported case for {:?} {:?}",
|
||||||
is_signed,
|
op,
|
||||||
},
|
operand,
|
||||||
) => {
|
),
|
||||||
// Check if it is boolean
|
},
|
||||||
assert!(width == 1);
|
_ => todo!(
|
||||||
let result = if value == 0 { 1 } else { 0 };
|
|
||||||
Ok(Value::int(result, width, is_signed))
|
|
||||||
}
|
|
||||||
(op, operand) => todo!(
|
|
||||||
"calculate_unary_operator_expression: not supported case for {:?} {:?}",
|
"calculate_unary_operator_expression: not supported case for {:?} {:?}",
|
||||||
op,
|
op,
|
||||||
operand,
|
operand,
|
||||||
@@ -630,8 +727,6 @@ mod calculator {
|
|||||||
|
|
||||||
match (value, dtype) {
|
match (value, dtype) {
|
||||||
(Value::Undef { .. }, _) => Err(()),
|
(Value::Undef { .. }, _) => Err(()),
|
||||||
// TODO: distinguish zero/signed extension in the future
|
|
||||||
// TODO: consider truncate in the future
|
|
||||||
(
|
(
|
||||||
Value::Int { value, width, .. },
|
Value::Int { value, width, .. },
|
||||||
Dtype::Int {
|
Dtype::Int {
|
||||||
@@ -640,7 +735,6 @@ mod calculator {
|
|||||||
..
|
..
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
// Other cases
|
|
||||||
let result = if target_signed {
|
let result = if target_signed {
|
||||||
if width >= target_width {
|
if width >= target_width {
|
||||||
// TODO: explain the logic in the future
|
// TODO: explain the logic in the future
|
||||||
@@ -668,6 +762,17 @@ mod calculator {
|
|||||||
};
|
};
|
||||||
Ok(Value::float(casted_value, width))
|
Ok(Value::float(casted_value, width))
|
||||||
}
|
}
|
||||||
|
(Value::Int { value, .. }, Dtype::Pointer { inner, .. }) => {
|
||||||
|
if value == 0 {
|
||||||
|
Ok(Value::pointer(None, 0, inner.deref().clone()))
|
||||||
|
} else {
|
||||||
|
panic!(format!(
|
||||||
|
"calculate_typecast: not support case \
|
||||||
|
typecast int to pointer when `value` is {}",
|
||||||
|
value
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
(
|
(
|
||||||
Value::Float { value, .. },
|
Value::Float { value, .. },
|
||||||
Dtype::Int {
|
Dtype::Int {
|
||||||
@@ -675,14 +780,14 @@ mod calculator {
|
|||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
let casted_value = if is_signed {
|
let casted_value = if is_signed {
|
||||||
value as i128 as u128
|
value.into_inner() as i128 as u128
|
||||||
} else {
|
} else {
|
||||||
value as u128
|
value.into_inner() as u128
|
||||||
};
|
};
|
||||||
Ok(Value::int(casted_value, width, is_signed))
|
Ok(Value::int(casted_value, width, is_signed))
|
||||||
}
|
}
|
||||||
(Value::Float { value, .. }, Dtype::Float { width, .. }) => {
|
(Value::Float { value, .. }, Dtype::Float { width, .. }) => {
|
||||||
Ok(Value::float(value, width))
|
Ok(Value::float(value.into_inner(), width))
|
||||||
}
|
}
|
||||||
(value, dtype) => todo!("calculate_typecast ({:?}) {:?}", value, dtype),
|
(value, dtype) => todo!("calculate_typecast ({:?}) {:?}", value, dtype),
|
||||||
}
|
}
|
||||||
@@ -706,12 +811,15 @@ mod calculator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO: delete `allow(dead_code)`
|
||||||
#[allow(dead_code)]
|
/// Even though `Pointer` variant is constructed and actively used at run-time,
|
||||||
|
/// the rust compiler analyzes it is dead code.
|
||||||
|
/// For this reason, we add `allow(dead_code)` mark.
|
||||||
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
|
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
|
||||||
enum Byte {
|
enum Byte {
|
||||||
Undef,
|
Undef,
|
||||||
Concrete(u8),
|
Concrete(u8),
|
||||||
|
#[allow(dead_code)]
|
||||||
Pointer {
|
Pointer {
|
||||||
bid: Option<usize>,
|
bid: Option<usize>,
|
||||||
offset: isize,
|
offset: isize,
|
||||||
@@ -921,8 +1029,8 @@ impl Byte {
|
|||||||
} => {
|
} => {
|
||||||
let size = value.dtype().size_align_of(structs).unwrap().0;
|
let size = value.dtype().size_align_of(structs).unwrap().0;
|
||||||
let value_bits: u128 = match size {
|
let value_bits: u128 = match size {
|
||||||
Dtype::SIZE_OF_FLOAT => (*float_value as f32).to_bits() as u128,
|
Dtype::SIZE_OF_FLOAT => (float_value.into_inner() as f32).to_bits() as u128,
|
||||||
Dtype::SIZE_OF_DOUBLE => (*float_value as f64).to_bits() as u128,
|
Dtype::SIZE_OF_DOUBLE => (float_value.into_inner() as f64).to_bits() as u128,
|
||||||
_ => panic!("value_to_bytes: {} is not a valid float size", size),
|
_ => panic!("value_to_bytes: {} is not a valid float size", size),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1045,8 +1153,6 @@ impl Memory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: allocation fields will be added in the future
|
|
||||||
// TODO: program fields will be added in the future
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
struct State<'i> {
|
struct State<'i> {
|
||||||
/// A data structure that maps each global variable to a pointer value
|
/// A data structure that maps each global variable to a pointer value
|
||||||
|
|||||||
@@ -186,7 +186,6 @@ pub struct Block {
|
|||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
pub enum Instruction {
|
pub enum Instruction {
|
||||||
// TODO: the variants of Instruction will be added in the future
|
|
||||||
Nop,
|
Nop,
|
||||||
BinOp {
|
BinOp {
|
||||||
op: ast::BinaryOperator,
|
op: ast::BinaryOperator,
|
||||||
@@ -255,7 +254,6 @@ impl Instruction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum BlockExit {
|
pub enum BlockExit {
|
||||||
Jump {
|
Jump {
|
||||||
|
|||||||
@@ -198,7 +198,6 @@ impl WriteString for Operand {
|
|||||||
|
|
||||||
impl WriteOp for ast::BinaryOperator {
|
impl WriteOp for ast::BinaryOperator {
|
||||||
fn write_operation(&self) -> String {
|
fn write_operation(&self) -> String {
|
||||||
// TODO: represent signed & unsigned if necessary
|
|
||||||
match self {
|
match self {
|
||||||
Self::Multiply => "mul",
|
Self::Multiply => "mul",
|
||||||
Self::Divide => "div",
|
Self::Divide => "div",
|
||||||
|
|||||||
10
src/tests.rs
10
src/tests.rs
@@ -8,6 +8,10 @@ use wait_timeout::ChildExt;
|
|||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
|
// Rust sets an exit code of 101 when the process panicked.
|
||||||
|
// So, we decide KECC sets an exit code of 102 after 101 when the test skipped.
|
||||||
|
pub const SKIP_TEST: i32 = 102;
|
||||||
|
|
||||||
pub fn test_write_c(unit: &TranslationUnit, _path: &Path) {
|
pub fn test_write_c(unit: &TranslationUnit, _path: &Path) {
|
||||||
let temp_dir = tempdir().expect("temp dir creation failed");
|
let temp_dir = tempdir().expect("temp dir creation failed");
|
||||||
let temp_file_path = temp_dir.path().join("temp.c");
|
let temp_file_path = temp_dir.path().join("temp.c");
|
||||||
@@ -43,7 +47,7 @@ pub fn test_irgen(unit: &TranslationUnit, path: &Path) {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.success()
|
.success()
|
||||||
{
|
{
|
||||||
return;
|
::std::process::exit(SKIP_TEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute compiled executable
|
// Execute compiled executable
|
||||||
@@ -64,10 +68,10 @@ pub fn test_irgen(unit: &TranslationUnit, path: &Path) {
|
|||||||
println!("timeout occurs");
|
println!("timeout occurs");
|
||||||
child.kill().unwrap();
|
child.kill().unwrap();
|
||||||
child.wait().unwrap();
|
child.wait().unwrap();
|
||||||
return;
|
::std::process::exit(SKIP_TEST);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
let status = some_or!(status.code(), return);
|
let status = some_or_exit!(status.code(), SKIP_TEST);
|
||||||
|
|
||||||
let ir = match Irgen::default().translate(unit) {
|
let ir = match Irgen::default().translate(unit) {
|
||||||
Ok(ir) => ir,
|
Ok(ir) => ir,
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ REPLACE_DICT = {
|
|||||||
"char _unused2[^;]*;": "char _unused2[10];",
|
"char _unused2[^;]*;": "char _unused2[10];",
|
||||||
}
|
}
|
||||||
CSMITH_DIR = "csmith-2.3.0"
|
CSMITH_DIR = "csmith-2.3.0"
|
||||||
|
SKIP_TEST = 102
|
||||||
|
|
||||||
def install_csmith(tests_dir):
|
def install_csmith(tests_dir):
|
||||||
global CSMITH_DIR
|
global CSMITH_DIR
|
||||||
@@ -200,17 +201,20 @@ def creduce(tests_dir, fuzz_arg):
|
|||||||
raise e
|
raise e
|
||||||
|
|
||||||
def fuzz(tests_dir, fuzz_arg, num_iter):
|
def fuzz(tests_dir, fuzz_arg, num_iter):
|
||||||
|
global SKIP_TEST
|
||||||
|
|
||||||
csmith_bin, csmith_inc = install_csmith(tests_dir)
|
csmith_bin, csmith_inc = install_csmith(tests_dir)
|
||||||
try:
|
try:
|
||||||
if num_iter is None:
|
if num_iter is None:
|
||||||
print("Fuzzing with infinitely many test cases. Please press [ctrl+C] to break.")
|
print("Fuzzing with infinitely many test cases. Please press [ctrl+C] to break.")
|
||||||
iterator = itertools.count(0)
|
|
||||||
else:
|
else:
|
||||||
|
assert num_iter > 0
|
||||||
print("Fuzzing with {} test cases.".format(num_iter))
|
print("Fuzzing with {} test cases.".format(num_iter))
|
||||||
iterator = range(num_iter)
|
|
||||||
|
|
||||||
for i in iterator:
|
i = 0
|
||||||
print("Test case #{}".format(i))
|
skip = 0
|
||||||
|
while True:
|
||||||
|
print("Test case #{} (skipped: {})".format(i, skip))
|
||||||
src = generate(tests_dir, csmith_bin)
|
src = generate(tests_dir, csmith_bin)
|
||||||
with open(os.path.join(tests_dir, "test.c"), 'w') as dst:
|
with open(os.path.join(tests_dir, "test.c"), 'w') as dst:
|
||||||
dst.write(src)
|
dst.write(src)
|
||||||
@@ -223,11 +227,20 @@ def fuzz(tests_dir, fuzz_arg, num_iter):
|
|||||||
args = ["cargo", "run", "--release", "--bin", "fuzz", "--", fuzz_arg, os.path.join(tests_dir, "test_polished.c")]
|
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)
|
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=tests_dir)
|
||||||
proc.communicate(timeout=60)
|
proc.communicate(timeout=60)
|
||||||
if proc.returncode != 0:
|
|
||||||
|
# KECC sets an exit code of 102 when the test skipped.
|
||||||
|
if proc.returncode == SKIP_TEST:
|
||||||
|
skip += 1
|
||||||
|
continue
|
||||||
|
elif proc.returncode != 0:
|
||||||
raise Exception("Test `{}` failed with exit code {}.".format(" ".join(args), proc.returncode))
|
raise Exception("Test `{}` failed with exit code {}.".format(" ".join(args), proc.returncode))
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
if num_iter is not None:
|
||||||
|
if i > num_iter: break
|
||||||
except subprocess.TimeoutExpired as e:
|
except subprocess.TimeoutExpired as e:
|
||||||
proc.kill()
|
proc.kill()
|
||||||
raise e
|
skip += 1
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
proc.terminate()
|
proc.terminate()
|
||||||
print("\n[Ctrl+C] interrupted")
|
print("\n[Ctrl+C] interrupted")
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ if
|
|||||||
grep 'non-void function does not return a value' out.txt ||\
|
grep 'non-void function does not return a value' out.txt ||\
|
||||||
grep 'too many arguments in call' out.txt ||\
|
grep 'too many arguments in call' out.txt ||\
|
||||||
grep 'declaration does not declare anything' out.txt ||\
|
grep 'declaration does not declare anything' out.txt ||\
|
||||||
|
grep 'not equal to a null pointer is always true' out.txt ||\
|
||||||
! gcc -Wall -Wextra -O2 test_reduced.c > outa.txt 2>&1 ||\
|
! gcc -Wall -Wextra -O2 test_reduced.c > outa.txt 2>&1 ||\
|
||||||
grep 'uninitialized' outa.txt ||\
|
grep 'uninitialized' outa.txt ||\
|
||||||
grep 'without a cast' outa.txt ||\
|
grep 'without a cast' outa.txt ||\
|
||||||
|
|||||||
Reference in New Issue
Block a user