Prepare for Spring 2025.

This commit is contained in:
Janggun Lee
2025-02-24 17:31:17 +09:00
parent a8e0aa5e69
commit fad9d02fea
53 changed files with 3442 additions and 1679 deletions

View File

@@ -1,16 +1,13 @@
use core::convert::TryFrom;
use core::fmt;
use core::ops::Deref;
use std::collections::{HashMap, HashSet};
use std::hash::Hash;
use itertools::izip;
use lang_c::ast;
use lang_c::span::Node;
use thiserror::Error;
use crate::ir::*;
use crate::some_or;
/// TODO(document)
#[derive(Debug, PartialEq, Eq, Error)]
@@ -227,13 +224,13 @@ impl BaseDtype {
tq => {
return Err(DtypeError::Misc {
message: format!("unsupported typq qualifier: {tq:#?}"),
})
});
}
}
Ok(())
}
pub fn apply_specifier_qualifier(
pub(crate) fn apply_specifier_qualifier(
&mut self,
typename_specifier: &ast::SpecifierQualifier,
) -> Result<(), DtypeError> {
@@ -247,14 +244,14 @@ impl BaseDtype {
sq => {
return Err(DtypeError::Misc {
message: format!("unsupported specifier qualifier: {sq:#?}"),
})
});
}
}
Ok(())
}
pub fn apply_declaration_specifier(
pub(crate) fn apply_declaration_specifier(
&mut self,
declaration_specifier: &ast::DeclarationSpecifier,
) -> Result<(), DtypeError> {
@@ -271,7 +268,7 @@ impl BaseDtype {
ds => {
return Err(DtypeError::Misc {
message: format!("unsupported declaration qualifier: {ds:#?}"),
})
});
}
}
@@ -289,7 +286,7 @@ impl BaseDtype {
///
/// * `self` - Part that has been converted to 'BaseDtype' on the pointer declarator.
/// * `pointer_qualifier` - Pointer qualifiers required to apply to 'BaseDtype' immediately.
pub fn apply_pointer_qualifier(
pub(crate) fn apply_pointer_qualifier(
&mut self,
pointer_qualifier: &ast::PointerQualifier,
) -> Result<(), DtypeError> {
@@ -300,14 +297,14 @@ impl BaseDtype {
pq => {
return Err(DtypeError::Misc {
message: format!("unsupported pointer qualifier: {pq:#?}"),
})
});
}
}
Ok(())
}
pub fn apply_specifier_qualifiers(
pub(crate) fn apply_specifier_qualifiers(
&mut self,
typename_specifiers: &[Node<ast::SpecifierQualifier>],
) -> Result<(), DtypeError> {
@@ -318,7 +315,7 @@ impl BaseDtype {
Ok(())
}
pub fn apply_declaration_specifiers(
pub(crate) fn apply_declaration_specifiers(
&mut self,
declaration_specifiers: &[Node<ast::DeclarationSpecifier>],
) -> Result<(), DtypeError> {
@@ -445,7 +442,7 @@ impl TryFrom<BaseDtype> for Dtype {
_ => {
return Err(DtypeError::Misc {
message: "two or more size modifiers in declaration specifiers".to_string(),
})
});
}
};
@@ -985,17 +982,18 @@ impl Dtype {
.expect("`offsets` must be `Some`");
assert_eq!(fields.len(), offsets.len());
for (field, &offset) in izip!(fields, offsets) {
for (field, &offset) in fields.iter().zip(offsets) {
if let Some(name) = field.name() {
if name == field_name {
return Some((offset, field.deref().clone()));
}
} else {
let field_dtype = field.deref();
let (offset_inner, dtype) = some_or!(
field_dtype.get_offset_struct_field(field_name, structs),
continue
);
let Some((offset_inner, dtype)) =
field_dtype.get_offset_struct_field(field_name, structs)
else {
continue;
};
return Some((offset + offset_inner, dtype));
}
}

View File

@@ -1,7 +1,6 @@
use core::{fmt, iter, mem};
use std::collections::HashMap;
use itertools::izip;
use ordered_float::OrderedFloat;
use thiserror::Error;
@@ -184,8 +183,7 @@ impl Value {
Dtype::Float { width, .. } => Self::float(f64::default(), *width),
Dtype::Pointer { inner, .. } => Self::nullptr(inner.deref().clone()),
Dtype::Array { inner, size } => {
let values = iter::repeat(Self::default_from_dtype(inner, structs))
.take(*size)
let values = iter::repeat_n(Self::default_from_dtype(inner, structs), *size)
.collect::<Result<Vec<_>, _>>()?;
Self::array(inner.deref().clone(), values)
}
@@ -605,7 +603,7 @@ mod calculator {
}
// TODO: change to template function in the future
pub fn calculate_binary_operator_expression(
pub(crate) fn calculate_binary_operator_expression(
op: &ast::BinaryOperator,
lhs: Value,
rhs: Value,
@@ -675,7 +673,7 @@ mod calculator {
}
}
pub fn calculate_unary_operator_expression(
pub(crate) fn calculate_unary_operator_expression(
op: &ast::UnaryOperator,
operand: Value,
) -> Result<Value, ()> {
@@ -727,7 +725,7 @@ mod calculator {
}
}
pub fn calculate_typecast(value: Value, dtype: Dtype) -> Result<Value, ()> {
pub(crate) fn calculate_typecast(value: Value, dtype: Dtype) -> Result<Value, ()> {
if value.dtype() == dtype {
return Ok(value);
}
@@ -851,7 +849,7 @@ impl Byte {
fn block_from_dtype(dtype: &Dtype, structs: &HashMap<String, Option<Dtype>>) -> Vec<Self> {
let size = dtype.size_align_of(structs).unwrap().0;
iter::repeat(Self::Undef).take(size).collect()
iter::repeat_n(Self::Undef, size).collect()
}
fn u128_to_bytes(mut value: u128, size: usize) -> Vec<u8> {
@@ -889,27 +887,25 @@ impl Byte {
width, is_signed, ..
} => {
let size = dtype.size_align_of(structs).unwrap().0;
let bytes = bytes.by_ref().take(size).collect::<Vec<_>>();
let value = some_or!(
bytes
.iter()
.map(|b| b.get_concrete())
.collect::<Option<Vec<_>>>(),
return Ok(Value::undef(dtype.clone()))
);
let Some(value) = bytes
.take(size)
.map(Byte::get_concrete)
.collect::<Option<Vec<_>>>()
else {
return Ok(Value::undef(dtype.clone()));
};
let value = Self::bytes_to_u128(&value, *is_signed);
Ok(Value::int(value, *width, *is_signed))
}
Dtype::Float { width, .. } => {
let size = dtype.size_align_of(structs).unwrap().0;
let bytes = bytes.by_ref().take(size).collect::<Vec<_>>();
let value = some_or!(
bytes
.iter()
.map(|b| b.get_concrete())
.collect::<Option<Vec<_>>>(),
return Ok(Value::undef(dtype.clone()))
);
let Some(value) = bytes
.take(size)
.map(Byte::get_concrete)
.collect::<Option<Vec<_>>>()
else {
return Ok(Value::undef(dtype.clone()));
};
let value = Self::bytes_to_u128(&value, false);
let value = if size == Dtype::SIZE_OF_FLOAT {
f32::from_bits(value as u32) as f64
@@ -920,17 +916,13 @@ impl Byte {
Ok(Value::float(value, *width))
}
Dtype::Pointer { inner, .. } => {
let bytes = bytes
.by_ref()
let Some(value) = bytes
.take(Dtype::SIZE_OF_POINTER)
.collect::<Vec<_>>();
let value = some_or!(
bytes
.iter()
.map(|b| b.get_pointer())
.collect::<Option<Vec<_>>>(),
return Ok(Value::undef(dtype.clone()))
);
.map(Byte::get_pointer)
.collect::<Option<Vec<_>>>()
else {
return Ok(Value::undef(dtype.clone()));
};
let (bid, offset, _) = value.first().expect("not empty");
@@ -983,13 +975,15 @@ impl Byte {
let bytes = bytes.by_ref().take(*size).cloned().collect::<Vec<_>>();
assert_eq!(fields.len(), offsets.len());
let fields = izip!(fields, offsets)
let fields = fields
.iter()
.zip(offsets)
.map(|(f, o)| {
let mut sub_bytes = bytes[*o..].iter();
let value = Self::bytes_to_value(&mut sub_bytes, f.deref(), structs)?;
Ok(Named::new(f.name().cloned(), value))
})
.collect::<Result<Vec<_>, InterpreterError>>()?;
.collect::<Result<Vec<_>, _>>()?;
Ok(Value::Struct {
name: name.clone(),
@@ -1010,9 +1004,9 @@ impl Byte {
} => {
let size = value.dtype().size_align_of(structs).unwrap().0;
Self::u128_to_bytes(*int_value, size)
.iter()
.map(|b| Self::concrete(*b))
.collect::<Vec<_>>()
.into_iter()
.map(Self::concrete)
.collect()
}
Value::Float {
value: float_value, ..
@@ -1025,9 +1019,9 @@ impl Byte {
};
Self::u128_to_bytes(value_bits, size)
.iter()
.map(|b| Self::concrete(*b))
.collect::<Vec<_>>()
.into_iter()
.map(Self::concrete)
.collect()
}
Value::Pointer { bid, offset, .. } => (0..Dtype::SIZE_OF_POINTER)
.map(|i| Self::pointer(*bid, *offset, i))
@@ -1042,7 +1036,7 @@ impl Byte {
.iter()
.flat_map(|v| {
let mut result = Self::value_to_bytes(v, structs);
result.extend(iter::repeat(Byte::Undef).take(padding));
result.extend(iter::repeat_n(Byte::Undef, padding));
result
})
.collect()
@@ -1058,10 +1052,10 @@ impl Byte {
.expect("`struct_type` must be struct type")
.as_ref()
.expect("`offsets` must be `Some`");
let mut values = iter::repeat(Byte::Undef).take(*size_of).collect::<Vec<_>>();
let mut values = iter::repeat_n(Byte::Undef, *size_of).collect::<Vec<_>>();
assert_eq!(fields.len(), offsets.len());
izip!(fields, offsets).for_each(|(f, o)| {
fields.iter().zip(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;
let _unused = values.splice(*o..(*o + size_of_data), result);
@@ -1270,7 +1264,9 @@ impl<'i> State<'i> {
}
// Execute a block exit.
let return_value = some_or!(self.interp_block_exit(&block.exit)?, return Ok(None));
let Some(return_value) = self.interp_block_exit(&block.exit)? else {
return Ok(None);
};
// If it's returning from a function, pop the stack frame.
@@ -1288,7 +1284,9 @@ impl<'i> State<'i> {
}
// restore previous state
let prev_stack_frame = some_or!(self.stack.pop(), return Ok(Some(return_value)));
let Some(prev_stack_frame) = self.stack.pop() else {
return Ok(Some(return_value));
};
self.stack_frame = prev_stack_frame;
// create temporary register to write return value
@@ -1313,7 +1311,9 @@ impl<'i> State<'i> {
) -> Result<Vec<Value>, InterpreterError> {
// Check that the dtype of each args matches the expected
if !(args.len() == signature.params.len()
&& izip!(args, &signature.params)
&& args
.iter()
.zip(&signature.params)
.all(|(a, d)| a.dtype().set_const(false) == d.clone().set_const(false)))
{
panic!("dtype of args and params must be compatible")
@@ -1333,7 +1333,7 @@ impl<'i> State<'i> {
.expect("block matched with `arg.bid` must be exist");
assert_eq!(arg.args.len(), block.phinodes.len());
for (a, d) in izip!(&arg.args, &block.phinodes) {
for (a, d) in arg.args.iter().zip(&block.phinodes) {
assert!(a.dtype().set_const(false) == d.deref().clone().set_const(false));
}
@@ -1394,6 +1394,7 @@ impl<'i> State<'i> {
fn interp_instruction(&mut self, instruction: &Instruction) -> Result<(), InterpreterError> {
let result = match instruction {
Instruction::Nop => Value::unit(),
Instruction::Value { value, .. } => self.interp_operand(value)?,
Instruction::BinOp { op, lhs, rhs, .. } => {
let lhs = self.interp_operand(lhs)?;
let rhs = self.interp_operand(rhs)?;
@@ -1469,7 +1470,7 @@ impl<'i> State<'i> {
.expect("init block must exists");
if !(args.len() == block_init.phinodes.len()
&& izip!(args, &block_init.phinodes).all(|(a, d)| {
&& args.iter().zip(&block_init.phinodes).all(|(a, d)| {
a.dtype().set_const(false) == d.deref().clone().set_const(false)
}))
{

View File

@@ -15,7 +15,7 @@ use std::hash::{Hash, Hasher};
pub use dtype::{Dtype, DtypeError, HasDtype};
use hexf_parse::{parse_hexf32, parse_hexf64};
pub use interp::{interp, Value};
pub use interp::{Value, interp};
use itertools::Itertools;
use lang_c::ast;
use ordered_float::OrderedFloat;
@@ -192,6 +192,9 @@ pub struct Block {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Instruction {
Nop,
Value {
value: Operand,
},
BinOp {
op: ast::BinaryOperator,
lhs: Operand,
@@ -233,6 +236,7 @@ impl HasDtype for Instruction {
fn dtype(&self) -> Dtype {
match self {
Self::Nop | Self::Store { .. } => Dtype::unit(),
Self::Value { value } => value.dtype(),
Self::BinOp { dtype, .. }
| Self::UnaryOp { dtype, .. }
| Self::Call {
@@ -316,6 +320,7 @@ impl fmt::Display for Instruction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Instruction::Nop => write!(f, "nop"),
Instruction::Value { value } => write!(f, "{value}"),
Instruction::BinOp { op, lhs, rhs, .. } => {
write!(f, "{} {} {}", op.write_operation(), lhs, rhs)
}
@@ -440,7 +445,7 @@ impl fmt::Display for JumpArg {
self.bid,
self.args
.iter()
.format_with(", ", |a, f| f(&format_args!("{}", a)))
.format_with(", ", |a, f| f(&format_args!("{a}")))
)
}
}

View File

@@ -17,28 +17,25 @@ peg::parser! {
pub rule translation_unit() -> TranslationUnit
= _ named_structs:(named_struct() ** __) _ ds:(named_decl() ** __) _ {
let mut structs = HashMap::new();
for named_struct in &named_structs {
let mut structs = named_structs.iter().map(|named_struct| {
let name = named_struct.name.as_ref().unwrap();
let struct_type = &named_struct.inner;
let result = structs.insert(name.clone(), struct_type.clone());
assert!(result.is_none());
}
(name.clone(), struct_type.clone())
}).collect::<HashMap<_,_>>();
// Resolve struct type in structs
// TODO: This is needed?
for named_struct in named_structs {
let name = named_struct.name.unwrap();
let dtype = some_or!(structs.get(&name).unwrap(), continue);
let Some(dtype) = structs.get(&name).unwrap() else {
continue;
};
if dtype.get_struct_size_align_offsets().unwrap().is_none() {
resolve_structs(dtype.clone(), &mut structs);
}
}
let mut decls = BTreeMap::new();
for decl in ds {
let result = decls.insert(decl.name.unwrap(), decl.inner);
assert!(result.is_none());
}
let mut decls = ds.into_iter().map(|decl| (decl.name.unwrap(), decl.inner)).collect::<BTreeMap<_,_>>();
TranslationUnit { decls, structs }
}
@@ -211,11 +208,10 @@ peg::parser! {
rule instruction() -> (BlockId, usize, Named<Instruction>)
= "%" bid:bid() ":i" number:number() ":" dtype:dtype() name:(":" name:id() { name })? _ "=" _ instruction:instruction_inner() {
// TODO: The dtype of `GetElementPtr` instruction depends on the situation.
// Let's `ptr` has `*[5 x i32]` type, after applying `GetElementPtr` instruction,
// the dtype of the result can be `*i32` or `*[5 x i32]` in the current KECC.
// For this reason, we need to check the dtype of the result to confirm the dtype
// of `GetElementPtr` instruction when parsing IR.
// TODO: The dtype of `GetElementPtr` instruction depends on the situation. Say `ptr`
// has type `*[5 x i32]`, after applying `GetElementPtr`, result' dtype can currently
// be `*i32` or `*[5 x i32]`. Thus, we need to check the dtype of the result to confirm
// the dtype of `GetElementPtr` instruction when parsing IR.
let instruction = if let Instruction::GetElementPtr { ptr, offset, .. } = instruction {
Instruction::GetElementPtr { ptr, offset, dtype }
} else {
@@ -319,6 +315,10 @@ peg::parser! {
dtype: Dtype::unit(), // TODO
}
}
/
value:operand() {
Instruction::Value { value }
}
/
"<instruction>" {
todo!()

View File

@@ -2,8 +2,8 @@
use std::collections::HashMap;
use crate::ir::*;
use crate::Translate;
use crate::ir::*;
#[derive(Default, Debug)]
pub struct Visualizer {

View File

@@ -6,7 +6,9 @@ use crate::write_base::*;
impl WriteLine for TranslationUnit {
fn write_line(&self, indent: usize, write: &mut dyn Write) -> Result<()> {
// TODO: consider KECC IR parser in the future.
for (name, struct_type) in &self.structs {
let mut structs = self.structs.iter().collect::<Vec<_>>();
structs.sort_unstable_by_key(|&(name, _)| name);
for (name, struct_type) in structs {
let definition = if let Some(struct_type) = struct_type {
let fields = struct_type
.get_struct_fields()