mirror of
https://github.com/kmc7468/cs420.git
synced 2025-12-16 07:28:52 +00:00
Prepare for Spring 2025.
This commit is contained in:
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}))
|
||||
{
|
||||
|
||||
@@ -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}")))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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!()
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::ir::*;
|
||||
use crate::Translate;
|
||||
use crate::ir::*;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Visualizer {
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user