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"
source = "registry+https://github.com/rust-lang/crates.io-index"
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)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -39,7 +39,7 @@ name = "backtrace-sys"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
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)",
]
@@ -50,7 +50,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cc"
version = "1.0.50"
version = "1.0.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -94,7 +94,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"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)",
"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)",
]
@@ -110,7 +110,7 @@ dependencies = [
[[package]]
name = "hermit-abi"
version = "0.1.11"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -325,7 +325,7 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.17"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"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 = [
"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)",
"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)",
]
@@ -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-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 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 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 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 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-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"
@@ -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 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 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 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"

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
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
doesn't, please run the fuzzer in Ubuntu 18.04.
**[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 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; };
int f(int i, int const a[i]) {
int main() {
int temp = 0;
const float temp2 = 0.f, temp3 = 0.f;
temp = sizeof(unsigned char);
temp = _Alignof(unsigned char);
temp += sizeof(unsigned char);
temp += _Alignof(unsigned char);
struct color c;
c.name;
struct color c = {1, 2};
temp += c.name;
struct color *cp = &c;
cp->name;
temp += cp->name;
for(int i = 0, j = 0; i < 10; ++i) {
break;
if ( i == 2 && j == 0) break;
temp += i;
}
switch(temp) {
case 1: {
temp = 0;
break;
}
default: {

View File

@@ -45,3 +45,9 @@ impl WriteLine for TranslationUnit {
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]
/// 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 {
Self::Unit { 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
// constant, it is assignable to another object of the same struct type.
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 {
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,
structs: &HashMap<String, Option<Dtype>>,
) -> bool {
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 {
self.is_const(structs)
self.is_immutable(structs)
}
}
@@ -850,16 +863,23 @@ impl Dtype {
field_name: &str,
structs: &HashMap<String, Option<Dtype>>,
) -> Option<(usize, Self)> {
if let Self::Struct {
fields,
size_align_offsets,
..
} = self
{
let fields = fields.as_ref().expect("struct should have its definition");
let (_, _, offsets) = size_align_offsets
if let Self::Struct { name, .. } = self {
let struct_name = name.as_ref().expect("`self` must have its name");
let struct_type = structs
.get(struct_name)
.expect("`structs` must have value matched with `struct_name`")
.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());
for (field, offset) in izip!(fields, offsets) {
@@ -869,19 +889,8 @@ impl Dtype {
}
} else {
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!(
struct_type.get_offset_struct_field(field_name, structs),
field_dtype.get_offset_struct_field(field_name, structs),
continue
);
return Some((*offset + offset_inner, dtype));
@@ -1115,7 +1124,7 @@ impl Dtype {
message: format!("unknown type name `{}`", name),
})?
.clone();
let is_const = dtype.is_const(structs) || *is_const;
let is_const = dtype.is_const() || *is_const;
dtype.set_const(is_const)
}

View File

@@ -2,6 +2,7 @@ use core::fmt;
use core::iter;
use core::mem;
use failure::Fail;
use ordered_float::OrderedFloat;
use std::collections::HashMap;
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 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,
value: OrderedFloat<f64>,
width: usize,
},
Pointer {
@@ -67,10 +68,7 @@ impl TryFrom<Constant> for Value {
width,
is_signed,
},
Constant::Float { value, width } => Self::Float {
value: value.into_inner(),
width,
},
Constant::Float { value, width } => Self::Float { value, width },
_ => panic!(),
};
@@ -125,7 +123,10 @@ impl Value {
#[inline]
fn float(value: f64, width: usize) -> Self {
Self::Float { value, width }
Self::Float {
value: value.into(),
width,
}
}
#[inline]
@@ -421,6 +422,187 @@ mod calculator {
use super::Value;
use crate::ir::*;
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
pub fn calculate_binary_operator_expression(
@@ -428,11 +610,10 @@ mod calculator {
lhs: Value,
rhs: Value,
) -> Result<Value, ()> {
match (op, lhs, rhs) {
(_, Value::Undef { .. }, _) => Err(()),
(_, _, Value::Undef { .. }) => Err(()),
match (lhs, rhs) {
(Value::Undef { .. }, _) => Err(()),
(_, Value::Undef { .. }) => Err(()),
(
op,
Value::Int {
value: lhs,
width: lhs_w,
@@ -447,121 +628,38 @@ mod calculator {
assert_eq!(lhs_w, rhs_w);
assert_eq!(lhs_s, rhs_s);
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 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))
calculate_integer_binary_operator_expression(op, lhs, rhs, 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 {:?} {:?} {:?}",
op,
lhs,
@@ -574,48 +672,47 @@ mod calculator {
op: &ast::UnaryOperator,
operand: Value,
) -> Result<Value, ()> {
match (op, operand) {
(_, Value::Undef { .. }) => Err(()),
(
ast::UnaryOperator::Plus,
Value::Int {
value,
width,
is_signed,
},
) => Ok(Value::int(value, width, is_signed)),
(
ast::UnaryOperator::Minus,
Value::Int {
value,
width,
is_signed,
},
) => {
// TODO: check what is exact behavior of appling minus to unsigned value
let result = if is_signed {
(-(value as i128)) as u128
} else {
let result = (-(value as i128)) as u128;
let bit_mask = (1u128 << (width as u128)) - 1;
result & bit_mask
};
Ok(Value::int(result as u128, width, is_signed))
match operand {
Value::Undef { .. } => Err(()),
Value::Int {
value,
width,
is_signed,
} => {
match op {
ast::UnaryOperator::Plus => Ok(Value::int(value, width, is_signed)),
ast::UnaryOperator::Minus => {
let result = if is_signed {
(-(value as i128)) as u128
} else {
let value = (-(value as i128)) as u128;
trim_unnecessary_bits(value, width as u128)
};
Ok(Value::int(result as u128, width, is_signed))
}
ast::UnaryOperator::Negate => {
// Check if it is boolean
assert!(width == 1);
let result = if value == 0 { 1 } else { 0 };
Ok(Value::int(result, width, is_signed))
}
_ => todo!(
"calculate_unary_operator_expression: not supported case for {:?} {:?}",
op,
operand,
),
}
}
(
ast::UnaryOperator::Negate,
Value::Int {
value,
width,
is_signed,
},
) => {
// Check if it is boolean
assert!(width == 1);
let result = if value == 0 { 1 } else { 0 };
Ok(Value::int(result, width, is_signed))
}
(op, operand) => todo!(
Value::Float { value, width } => match op {
ast::UnaryOperator::Plus => Ok(Value::float(value.into_inner(), width)),
ast::UnaryOperator::Minus => Ok(Value::float(-value.into_inner(), width)),
_ => todo!(
"calculate_unary_operator_expression: not supported case for {:?} {:?}",
op,
operand,
),
},
_ => todo!(
"calculate_unary_operator_expression: not supported case for {:?} {:?}",
op,
operand,
@@ -630,8 +727,6 @@ mod calculator {
match (value, dtype) {
(Value::Undef { .. }, _) => Err(()),
// TODO: distinguish zero/signed extension in the future
// TODO: consider truncate in the future
(
Value::Int { value, width, .. },
Dtype::Int {
@@ -640,7 +735,6 @@ mod calculator {
..
},
) => {
// Other cases
let result = if target_signed {
if width >= target_width {
// TODO: explain the logic in the future
@@ -668,6 +762,17 @@ mod calculator {
};
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, .. },
Dtype::Int {
@@ -675,14 +780,14 @@ mod calculator {
},
) => {
let casted_value = if is_signed {
value as i128 as u128
value.into_inner() as i128 as u128
} else {
value as u128
value.into_inner() as u128
};
Ok(Value::int(casted_value, width, is_signed))
}
(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),
}
@@ -706,12 +811,15 @@ mod calculator {
}
}
// TODO
#[allow(dead_code)]
// TODO: delete `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)]
enum Byte {
Undef,
Concrete(u8),
#[allow(dead_code)]
Pointer {
bid: Option<usize>,
offset: isize,
@@ -921,8 +1029,8 @@ impl Byte {
} => {
let size = value.dtype().size_align_of(structs).unwrap().0;
let value_bits: u128 = match size {
Dtype::SIZE_OF_FLOAT => (*float_value as f32).to_bits() as u128,
Dtype::SIZE_OF_DOUBLE => (*float_value as f64).to_bits() as u128,
Dtype::SIZE_OF_FLOAT => (float_value.into_inner() as f32).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),
};
@@ -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)]
struct State<'i> {
/// 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)]
#[allow(clippy::large_enum_variant)]
pub enum Instruction {
// TODO: the variants of Instruction will be added in the future
Nop,
BinOp {
op: ast::BinaryOperator,
@@ -255,7 +254,6 @@ impl Instruction {
}
}
// TODO
#[derive(Debug, PartialEq, Clone)]
pub enum BlockExit {
Jump {

View File

@@ -198,7 +198,6 @@ impl WriteString for Operand {
impl WriteOp for ast::BinaryOperator {
fn write_operation(&self) -> String {
// TODO: represent signed & unsigned if necessary
match self {
Self::Multiply => "mul",
Self::Divide => "div",

View File

@@ -8,6 +8,10 @@ use wait_timeout::ChildExt;
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) {
let temp_dir = tempdir().expect("temp dir creation failed");
let temp_file_path = temp_dir.path().join("temp.c");
@@ -43,7 +47,7 @@ pub fn test_irgen(unit: &TranslationUnit, path: &Path) {
.unwrap()
.success()
{
return;
::std::process::exit(SKIP_TEST);
}
// Execute compiled executable
@@ -64,10 +68,10 @@ pub fn test_irgen(unit: &TranslationUnit, path: &Path) {
println!("timeout occurs");
child.kill().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) {
Ok(ir) => ir,

View File

@@ -48,6 +48,7 @@ REPLACE_DICT = {
"char _unused2[^;]*;": "char _unused2[10];",
}
CSMITH_DIR = "csmith-2.3.0"
SKIP_TEST = 102
def install_csmith(tests_dir):
global CSMITH_DIR
@@ -200,17 +201,20 @@ def creduce(tests_dir, fuzz_arg):
raise e
def fuzz(tests_dir, fuzz_arg, num_iter):
global SKIP_TEST
csmith_bin, csmith_inc = install_csmith(tests_dir)
try:
if num_iter is None:
print("Fuzzing with infinitely many test cases. Please press [ctrl+C] to break.")
iterator = itertools.count(0)
else:
assert num_iter > 0
print("Fuzzing with {} test cases.".format(num_iter))
iterator = range(num_iter)
for i in iterator:
print("Test case #{}".format(i))
i = 0
skip = 0
while True:
print("Test case #{} (skipped: {})".format(i, skip))
src = generate(tests_dir, csmith_bin)
with open(os.path.join(tests_dir, "test.c"), 'w') as dst:
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")]
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=tests_dir)
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))
i += 1
if num_iter is not None:
if i > num_iter: break
except subprocess.TimeoutExpired as e:
proc.kill()
raise e
skip += 1
except KeyboardInterrupt:
proc.terminate()
print("\n[Ctrl+C] interrupted")

View File

@@ -29,6 +29,7 @@ if
grep 'non-void function does not return a value' out.txt ||\
grep 'too many arguments in call' 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 ||\
grep 'uninitialized' outa.txt ||\
grep 'without a cast' outa.txt ||\