Update skeleton

This commit is contained in:
Jeehoon Kang
2020-04-29 23:10:15 +09:00
parent 61b2162408
commit 3bef06455e
14 changed files with 3699 additions and 237 deletions

20
Cargo.lock generated
View File

@@ -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"

View File

@@ -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
View 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

File diff suppressed because it is too large Load Diff

59
examples/c/float2_gen.py Normal file
View 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)

View File

@@ -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: {

View File

@@ -45,3 +45,9 @@ impl WriteLine for TranslationUnit {
todo!("homework 1") todo!("homework 1")
} }
} }
impl WriteString for Initializer {
fn write_string(&self) -> String {
todo!()
}
}

View File

@@ -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)
} }

View File

@@ -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

View File

@@ -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 {

View File

@@ -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",

View File

@@ -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,

View File

@@ -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")

View File

@@ -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 ||\