This commit is contained in:
Jeehoon Kang
2021-06-21 18:45:39 +00:00
parent 2d8d1e7fb4
commit 4535b2ef6f
28 changed files with 696 additions and 370 deletions

View File

@@ -12,14 +12,20 @@ use itertools::izip;
use crate::ir::*;
use crate::some_or;
/// TODO(document)
#[derive(Debug, PartialEq, Fail)]
pub enum DtypeError {
/// For uncommon error
#[fail(display = "{}", message)]
Misc { message: String },
Misc {
/// TODO(document)
message: String,
},
}
/// TODO(document)
pub trait HasDtype {
/// TODO(document)
fn dtype(&self) -> Dtype;
}
@@ -34,40 +40,77 @@ struct BaseDtype {
is_typedef: bool,
}
/// TODO(document)
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum Dtype {
/// TODO(document)
Unit {
/// TODO(document)
is_const: bool,
},
/// TODO(document)
Int {
/// TODO(document)
width: usize,
/// TODO(document)
is_signed: bool,
/// TODO(document)
is_const: bool,
},
/// TODO(document)
Float {
/// TODO(document)
width: usize,
/// TODO(document)
is_const: bool,
},
/// TODO(document)
Pointer {
/// TODO(document)
inner: Box<Dtype>,
/// TODO(document)
is_const: bool,
},
/// TODO(document)
Array {
/// TODO(document)
inner: Box<Dtype>,
/// TODO(document)
size: usize,
},
/// TODO(document)
Struct {
/// TODO(document)
name: Option<String>,
/// TODO(document)
fields: Option<Vec<Named<Dtype>>>,
/// TODO(document)
is_const: bool,
/// TODO(document)
size_align_offsets: Option<(usize, usize, Vec<usize>)>,
},
/// TODO(document)
Function {
/// TODO(document)
ret: Box<Dtype>,
/// TODO(document)
params: Vec<Dtype>,
},
/// TODO(document)
Typedef {
/// TODO(document)
name: String,
/// TODO(document)
is_const: bool,
},
}
@@ -201,6 +244,7 @@ impl BaseDtype {
ast::SpecifierQualifier::TypeQualifier(type_qualifier) => {
self.apply_type_qualifier(&type_qualifier.node)?
}
ast::SpecifierQualifier::Extension(_) => panic!("unsupported specifier qualifier"),
}
Ok(())
@@ -464,40 +508,73 @@ impl TryFrom<&ast::ParameterDeclaration> for Dtype {
}
impl Dtype {
/// TODO(document)
pub const BITS_OF_BYTE: usize = 8;
/// TODO(document)
pub const SIZE_OF_BYTE: usize = 1;
/// TODO(document)
// TODO: consider architecture dependency (current: 64-bit architecture)
pub const SIZE_OF_POINTER: usize = 8;
/// TODO(document)
pub const SIZE_OF_CHAR: usize = 1;
/// TODO(document)
pub const SIZE_OF_SHORT: usize = 2;
/// TODO(document)
pub const SIZE_OF_INT: usize = 4;
/// TODO(document)
pub const SIZE_OF_LONG: usize = 8;
/// TODO(document)
pub const SIZE_OF_LONGLONG: usize = 8;
/// TODO(document)
pub const SIZE_OF_FLOAT: usize = 4;
/// TODO(document)
pub const SIZE_OF_DOUBLE: usize = 8;
/// TODO(document)
// signed option cannot be applied to boolean value
pub const BOOL: Self = Self::Int {
width: 1,
is_signed: false,
is_const: false,
};
/// TODO(document)
pub const CHAR: Self = Self::int(Self::SIZE_OF_CHAR * Self::BITS_OF_BYTE);
/// TODO(document)
pub const SHORT: Self = Self::int(Self::SIZE_OF_SHORT * Self::BITS_OF_BYTE);
/// TODO(document)
pub const INT: Self = Self::int(Self::SIZE_OF_INT * Self::BITS_OF_BYTE);
/// TODO(document)
pub const LONG: Self = Self::int(Self::SIZE_OF_LONG * Self::BITS_OF_BYTE);
/// TODO(document)
pub const LONGLONG: Self = Self::int(Self::SIZE_OF_LONGLONG * Self::BITS_OF_BYTE);
/// TODO(document)
pub const FLOAT: Self = Self::float(Self::SIZE_OF_FLOAT * Self::BITS_OF_BYTE);
/// TODO(document)
pub const DOUBLE: Self = Self::float(Self::SIZE_OF_DOUBLE * Self::BITS_OF_BYTE);
/// TODO(document)
#[inline]
pub const fn unit() -> Self {
Self::Unit { is_const: false }
}
/// TODO(document)
#[inline]
pub const fn int(width: usize) -> Self {
Self::Int {
@@ -507,6 +584,7 @@ impl Dtype {
}
}
/// TODO(document)
#[inline]
pub const fn float(width: usize) -> Self {
Self::Float {
@@ -515,6 +593,7 @@ impl Dtype {
}
}
/// TODO(document)
#[inline]
pub fn pointer(inner: Dtype) -> Self {
Self::Pointer {
@@ -523,9 +602,14 @@ impl Dtype {
}
}
// Suppose the C declaration is `int *a[2][3]`. Then `a`'s `ir::Dtype` should be `[2 x [3 x int*]]`.
// But in the AST, it is parsed as `Array(3, Array(2, Pointer(int)))`, reversing the order of `2` and `3`.
// In the recursive translation of declaration into Dtype, we need to insert `3` inside `[2 * int*]`.
/// TODO(document)
///
/// # Examples
///
/// Suppose the C declaration is `int *a[2][3]`. Then `a`'s `ir::Dtype` should be `[2 x [3 x
/// int*]]`. But in the AST, it is parsed as `Array(3, Array(2, Pointer(int)))`, reversing the
/// order of `2` and `3`. In the recursive translation of declaration into Dtype, we need to
/// insert `3` inside `[2 * int*]`.
pub fn array(base_dtype: Dtype, size: usize) -> Self {
match base_dtype {
Self::Array {
@@ -547,6 +631,7 @@ impl Dtype {
}
}
/// TODO(document)
#[inline]
pub fn structure(name: Option<String>, fields: Option<Vec<Named<Self>>>) -> Self {
Self::Struct {
@@ -1344,7 +1429,7 @@ fn check_no_duplicate_field(fields: &[Named<Dtype>], field_names: &mut HashSet<S
.expect("`field_dtype` must be struct type")
.as_ref()
.expect("struct type must have its definition");
if !check_no_duplicate_field(&fields, field_names) {
if !check_no_duplicate_field(fields, field_names) {
return false;
}
}

View File

@@ -4,7 +4,6 @@ use itertools::izip;
use crate::ir::*;
use crate::utils::IsEquiv;
use crate::*;
impl IsEquiv for TranslationUnit {
fn is_equiv(&self, other: &Self) -> bool {
@@ -30,7 +29,7 @@ impl IsEquiv for TranslationUnit {
}
}
impl IsEquiv for ir::Declaration {
impl IsEquiv for Declaration {
fn is_equiv(&self, other: &Self) -> bool {
match (self, other) {
(
@@ -328,7 +327,7 @@ fn is_equiv_arg(lhs: &JumpArg, rhs: &JumpArg, map: &HashMap<BlockId, BlockId>) -
true
}
impl IsEquiv for ir::FunctionDefinition {
impl IsEquiv for FunctionDefinition {
fn is_equiv(&self, other: &Self) -> bool {
if self.allocations != other.allocations {
return false;
@@ -348,7 +347,7 @@ impl IsEquiv for ir::FunctionDefinition {
let mut map = HashMap::new();
for (f, t) in izip!(&preorder, &preorder_other) {
map.insert(*f, *t);
let _ = map.insert(*f, *t);
}
if map.get(&self.bid_init) != Some(&other.bid_init) {

View File

@@ -703,7 +703,7 @@ mod calculator {
let value = (-(value as i128)) as u128;
trim_unnecessary_bits(value, width as u128)
};
Ok(Value::int(result as u128, width, is_signed))
Ok(Value::int(result, width, is_signed))
}
ast::UnaryOperator::Negate => {
// Check if it is boolean
@@ -781,11 +781,11 @@ mod calculator {
if value == 0 {
Ok(Value::pointer(None, 0, inner.deref().clone()))
} else {
panic!(format!(
panic!(
"calculate_typecast: not support case \
typecast int to pointer when `value` is {}",
typecast int to pointer when `value` is {}",
value
))
)
}
}
(
@@ -1028,7 +1028,7 @@ impl Byte {
let size = value.dtype().size_align_of(structs).unwrap().0;
let value_bits: u128 = match size {
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,
Dtype::SIZE_OF_DOUBLE => (float_value.into_inner()).to_bits() as u128,
_ => panic!("value_to_bytes: {} is not a valid float size", size),
};
@@ -1073,7 +1073,7 @@ impl Byte {
izip!(fields, offsets).for_each(|(f, o)| {
let result = Self::value_to_bytes(f.deref(), structs);
let size_of_data = f.deref().dtype().size_align_of(structs).unwrap().0;
values.splice(*o..(*o + size_of_data), result.iter().cloned());
let _ = values.splice(*o..(*o + size_of_data), result.iter().cloned());
});
values
@@ -1143,7 +1143,7 @@ impl Memory {
let block = self.inner[bid].as_mut().unwrap();
if 0 <= offset && end <= block.len() {
block.splice(offset as usize..end, bytes.iter().cloned());
let _ = block.splice(offset as usize..end, bytes.iter().cloned());
Ok(())
} else {
Err(())
@@ -1163,16 +1163,16 @@ struct State<'i> {
}
impl<'i> State<'i> {
fn new(ir: &'i TranslationUnit, args: Vec<Value>) -> Result<State, InterpreterError> {
fn new(ir: &'i TranslationUnit, args: Vec<Value>) -> Result<State<'_>, InterpreterError> {
// Interpreter starts with the main function
let func_name = String::from("main");
let func = ir
.decls
.get(&func_name)
.ok_or_else(|| InterpreterError::NoMainFunction)?;
.ok_or(InterpreterError::NoMainFunction)?;
let (_, func_def) = func
.get_function()
.ok_or_else(|| InterpreterError::NoMainFunction)?;
.ok_or(InterpreterError::NoMainFunction)?;
let func_def = func_def
.as_ref()
.ok_or_else(|| InterpreterError::NoFunctionDefinition {
@@ -1218,7 +1218,7 @@ impl<'i> State<'i> {
},
)?
} else {
Value::default_from_dtype(&dtype, &self.ir.structs)
Value::default_from_dtype(dtype, &self.ir.structs)
.expect("default value must be derived from `dtype`")
};
@@ -1244,7 +1244,7 @@ impl<'i> State<'i> {
fn alloc_local_variables(&mut self) -> Result<(), InterpreterError> {
// add alloc register
for (id, allocation) in self.stack_frame.func_def.allocations.iter().enumerate() {
let bid = self.memory.alloc(&allocation, &self.ir.structs)?;
let bid = self.memory.alloc(allocation, &self.ir.structs)?;
let ptr = Value::pointer(Some(bid), 0, allocation.deref().clone());
let rid = RegisterId::local(id);
@@ -1407,7 +1407,7 @@ impl<'i> State<'i> {
let lhs = self.interp_operand(lhs.clone())?;
let rhs = self.interp_operand(rhs.clone())?;
calculator::calculate_binary_operator_expression(&op, lhs, rhs).map_err(|_| {
calculator::calculate_binary_operator_expression(op, lhs, rhs).map_err(|_| {
InterpreterError::Misc {
func_name: self.stack_frame.func_name.clone(),
pc: self.stack_frame.pc,
@@ -1418,7 +1418,7 @@ impl<'i> State<'i> {
Instruction::UnaryOp { op, operand, .. } => {
let operand = self.interp_operand(operand.clone())?;
calculator::calculate_unary_operator_expression(&op, operand).map_err(|_| {
calculator::calculate_unary_operator_expression(op, operand).map_err(|_| {
InterpreterError::Misc {
func_name: self.stack_frame.func_name.clone(),
pc: self.stack_frame.pc,
@@ -1517,7 +1517,7 @@ impl<'i> State<'i> {
let offset = prev_offset + value as isize;
assert!(0 <= offset);
Value::pointer(*bid, offset as isize, inner_dtype.clone())
Value::pointer(*bid, offset, inner_dtype.clone())
}
};

View File

@@ -1,6 +1,9 @@
//! The intermediate representation.
mod dtype;
mod equiv;
mod interp;
#[allow(clippy::all)]
mod parse;
mod write_ir;
@@ -247,11 +250,7 @@ impl HasDtype for Instruction {
impl Instruction {
pub fn is_pure(&self) -> bool {
match self {
Self::Store { .. } => false,
Self::Call { .. } => false,
_ => true,
}
!matches!(self, Self::Store { .. } | Self::Call { .. })
}
}
@@ -526,6 +525,7 @@ impl TryFrom<&ast::Constant> for Constant {
ast::IntegerBase::Decimal => Self::DECIMAL,
ast::IntegerBase::Octal => Self::OCTAL,
ast::IntegerBase::Hexadecimal => Self::HEXADECIMAL,
ast::IntegerBase::Binary => Self::BINARY,
};
let value = if integer.suffix.unsigned {
@@ -636,14 +636,11 @@ impl Constant {
const DECIMAL: u32 = 10;
const OCTAL: u32 = 8;
const HEXADECIMAL: u32 = 16;
const BINARY: u32 = 2;
#[inline]
pub fn is_integer_constant(&self) -> bool {
if let Self::Int { .. } = self {
true
} else {
false
}
matches!(self, Self::Int { .. })
}
#[inline]
@@ -730,17 +727,13 @@ impl Constant {
}
_ => panic!(
"constant value generated by `Constant::from_ast_expression` \
must be `Constant{{Int, Float}}`"
must be `Constant(Int, Float)`"
),
}
}
pub fn is_undef(&self) -> bool {
if let Self::Undef { .. } = self {
true
} else {
false
}
matches!(self, Self::Undef { .. })
}
pub fn typecast(self, target_dtype: Dtype) -> Self {

View File

@@ -660,7 +660,7 @@ pub enum Error {
ResolveError,
}
#[derive(Default)]
#[derive(Default, Debug)]
pub struct Parse {}
impl<P: AsRef<Path>> Translate<P> for Parse {