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,9 +1,10 @@
use std::collections::{HashMap, HashSet, VecDeque};
use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
use lang_c::ast;
use crate::ir::HasDtype;
use crate::{asm, ir, Translate};
use crate::opt::opt_utils;
use crate::{Translate, asm, ir};
#[derive(Debug)]
pub struct Asmgen {}

View File

@@ -523,7 +523,7 @@ impl IsEquiv for AlignOf {
}
}
pub fn assert_ast_equiv(lhs: &TranslationUnit, rhs: &TranslationUnit) {
pub(crate) fn assert_ast_equiv(lhs: &TranslationUnit, rhs: &TranslationUnit) {
if !lhs.is_equiv(rhs) {
panic!(
r#"assertion failed: `(left.is_equiv(right))`

View File

@@ -2,5 +2,5 @@ mod ast_equiv;
mod parse;
mod write_c;
pub use ast_equiv::assert_ast_equiv;
pub(crate) use ast_equiv::assert_ast_equiv;
pub use parse::Parse;

View File

@@ -2,11 +2,11 @@ use core::ops::Deref;
use std::path::Path;
use lang_c::ast::*;
use lang_c::driver::{parse, Config, Error as ParseError};
use lang_c::driver::{Config, Error as ParseError, parse};
use lang_c::span::Node;
use crate::utils::AssertSupported;
use crate::Translate;
use crate::utils::AssertSupported;
/// Parse Error
#[derive(Debug)]
@@ -616,7 +616,7 @@ impl AssertSupported for AlignOf {
}
#[inline]
pub fn is_valid_global_variable_declaration(decl: &Declaration) -> bool {
fn is_valid_global_variable_declaration(decl: &Declaration) -> bool {
let declarators = &decl.declarators;
declarators.iter().all(|init_decl| {
@@ -629,7 +629,7 @@ pub fn is_valid_global_variable_declaration(decl: &Declaration) -> bool {
}
#[inline]
pub fn is_valid_global_variable_initializer(initializer: &Initializer) -> bool {
fn is_valid_global_variable_initializer(initializer: &Initializer) -> bool {
match initializer {
Initializer::Expression(expr) => match &expr.node {
Expression::Constant(_) => true,

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()

View File

@@ -426,10 +426,9 @@ impl Irgen {
///
/// Returns error if the previous declearation is incompatible with `decl`.
fn add_decl(&mut self, name: &str, decl: ir::Declaration) -> Result<(), IrgenError> {
let old_decl = some_or!(
self.decls.insert(name.to_string(), decl.clone()),
return Ok(())
);
let Some(old_decl) = self.decls.insert(name.to_string(), decl.clone()) else {
return Ok(());
};
// Check if type is conflicting for pre-declared one
if !old_decl.is_compatible(&decl) {
@@ -781,9 +780,7 @@ fn is_invalid_structure(dtype: &ir::Dtype, structs: &HashMap<String, Option<ir::
if let ir::Dtype::Struct { name, fields, .. } = dtype {
assert!(name.is_some() && fields.is_none());
let name = name.as_ref().unwrap();
let struct_type = some_or!(structs.get(name), return true);
struct_type.is_none()
structs.get(name).is_none_or(Option::is_none)
} else {
false
}

View File

@@ -7,8 +7,6 @@
// <https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html>
#![deny(
absolute_paths_not_starting_with_crate,
// Old, historical lint
// box_pointers,
elided_lifetimes_in_paths,
explicit_outlives_requirements,
keyword_idents,
@@ -16,25 +14,22 @@
macro_use_extern_crate,
meta_variable_misuse,
missing_abi,
// Most stuff are reasonably not copy.
// These are stupid.
// missing_copy_implementations,
missing_debug_implementations,
// missing_debug_implementations,
// TODO
// missing_docs
// missing_docs,
non_ascii_idents,
noop_method_call,
rust_2021_incompatible_closure_captures,
rust_2021_incompatible_or_patterns,
rust_2021_prefixes_incompatible_syntax,
rust_2021_prelude_collisions,
// Necessary for skeleton code.
// single_use_lifetimes,
single_use_lifetimes,
trivial_casts,
trivial_numeric_casts,
// Necessary for skeleton code.
// unreachable_pub,
unreachable_pub,
unsafe_code,
unsafe_op_in_unsafe_fn,
unstable_features,
// Necessary for `build-bin` trick.
// unused_crate_dependencies,
@@ -44,7 +39,7 @@
unused_macro_rules,
unused_qualifications,
unused_results,
// Allowed for more flexible variants.
// This is stupid. Allowed for more flexible variants.
// variant_size_differences,
)]
// For skeleton code.
@@ -67,9 +62,9 @@ pub use c::Parse;
pub use ir::{Parse as IrParse, Visualizer as IrVisualizer};
pub use irgen::Irgen;
pub use opt::{
Deadcode, FunctionPass, Gvn, Mem2reg, Optimize, Repeat, SimplifyCfg, SimplifyCfgConstProp,
SimplifyCfgEmpty, SimplifyCfgMerge, SimplifyCfgReach, O0, O1,
Deadcode, FunctionPass, Gvn, Mem2reg, O0, O1, Optimize, Repeat, SimplifyCfg,
SimplifyCfgConstProp, SimplifyCfgEmpty, SimplifyCfgMerge, SimplifyCfgReach,
};
pub use tests::*;
pub use utils::*;
pub use write_base::write;
pub(crate) use write_base::write;

View File

@@ -3,7 +3,7 @@ use crate::*;
mod deadcode;
mod gvn;
mod mem2reg;
pub mod opt_utils;
pub(crate) mod opt_utils;
mod simplify_cfg;
pub use deadcode::Deadcode;
@@ -43,9 +43,7 @@ impl Optimize<ir::TranslationUnit> for Null {
impl<T, O1: Optimize<T>, O2: Optimize<T>> Optimize<T> for (O1, O2) {
fn optimize(&mut self, code: &mut T) -> bool {
let changed1 = self.0.optimize(code);
let changed2 = self.1.optimize(code);
changed1 || changed2
self.0.optimize(code) | self.1.optimize(code)
}
}
@@ -67,8 +65,7 @@ where
fn optimize(&mut self, code: &mut ir::TranslationUnit) -> bool {
code.decls
.values_mut()
.map(|decl| self.optimize(decl))
.fold(false, |l, r| l | r)
.fold(false, |b, decl| b | self.optimize(decl))
}
}
@@ -77,8 +74,9 @@ where
T: Optimize<ir::FunctionDefinition>,
{
fn optimize(&mut self, code: &mut ir::Declaration) -> bool {
let (_, fdef) = some_or!(code.get_function_mut(), return false);
let fdef = some_or!(fdef, return false);
let Some((_, Some(fdef))) = code.get_function_mut() else {
return false;
};
self.inner.optimize(fdef)
}
}

View File

@@ -1,7 +1,8 @@
use std::fs::{self, File};
use std::io::{stderr, Read, Write};
use std::io::{Read, Write, stderr};
use std::path::Path;
use std::process::{Command, Stdio};
use std::time::Duration;
use lang_c::*;
use rand::Rng;
@@ -107,7 +108,7 @@ pub fn test_irgen(path: &Path) {
.translate(&unit)
.unwrap_or_else(|irgen_error| panic!("{}", irgen_error));
let rand_num = rand::thread_rng().gen_range(1..100);
let rand_num = rand::rng().random_range(1..100);
let new_c = modify_c(path, rand_num);
modify_ir(&mut ir, rand_num);
@@ -148,17 +149,15 @@ pub fn test_irgen(path: &Path) {
.spawn()
.expect("failed to execute the compiled executable");
let status = some_or!(
child
.wait_timeout_ms(1000)
.expect("failed to obtain exit status from child process"),
{
println!("timeout occurs");
child.kill().unwrap();
let _ = child.wait().unwrap();
::std::process::exit(SKIP_TEST);
}
);
let Some(status) = child
.wait_timeout(Duration::from_millis(1000))
.expect("failed to obtain exit status from child process")
else {
println!("timeout occurs");
child.kill().unwrap();
let _ = child.wait().unwrap();
::std::process::exit(SKIP_TEST);
};
if child
.stderr
@@ -302,7 +301,7 @@ pub fn test_asmgen(path: &Path) {
.translate(&ir)
.expect("fail to create riscv assembly code");
let rand_num = rand::thread_rng().gen_range(1..100);
let rand_num = rand::rng().random_range(1..100);
modify_ir(&mut ir, rand_num);
modify_asm(&mut asm, rand_num);
@@ -345,17 +344,15 @@ pub fn test_asmgen(path: &Path) {
.spawn()
.expect("failed to execute the compiled executable");
let status = some_or!(
child
.wait_timeout_ms(1000)
.expect("failed to obtain exit status from child process"),
{
println!("timeout occurs");
child.kill().unwrap();
let _ = child.wait().unwrap();
::std::process::exit(SKIP_TEST);
}
);
let Some(status) = child
.wait_timeout(Duration::from_millis(1000))
.expect("failed to obtain exit status from child process")
else {
println!("timeout occurs");
child.kill().unwrap();
let _ = child.wait().unwrap();
::std::process::exit(SKIP_TEST);
};
if child
.stderr
@@ -425,17 +422,15 @@ pub fn test_end_to_end(path: &Path) {
.status()
.expect("failed to remove compiled executable");
let status = some_or!(
child
.wait_timeout_ms(1000)
.expect("failed to obtain exit status from child process"),
{
println!("timeout occurs");
child.kill().unwrap();
let _ = child.wait().unwrap();
::std::process::exit(SKIP_TEST);
}
);
let Some(status) = child
.wait_timeout(Duration::from_millis(1000))
.expect("failed to obtain exit status from child process")
else {
println!("timeout occurs");
child.kill().unwrap();
let _ = child.wait().unwrap();
::std::process::exit(SKIP_TEST);
};
if child
.stderr
@@ -508,17 +503,15 @@ pub fn test_end_to_end(path: &Path) {
.spawn()
.expect("failed to execute the compiled executable");
let status = some_or!(
child
.wait_timeout_ms(1000)
.expect("failed to obtain exit status from child process"),
{
println!("timeout occurs");
child.kill().unwrap();
let _ = child.wait().unwrap();
::std::process::exit(SKIP_TEST);
}
);
let Some(status) = child
.wait_timeout(Duration::from_millis(1000))
.expect("failed to obtain exit status from child process")
else {
println!("timeout occurs");
child.kill().unwrap();
let _ = child.wait().unwrap();
::std::process::exit(SKIP_TEST);
};
if child
.stderr

View File

@@ -1,14 +1,3 @@
#[macro_export]
/// Some or executing the given expression.
macro_rules! some_or {
($e:expr_2021, $err:expr_2021) => {{
match $e {
Some(r) => r,
None => $err,
}
}};
}
#[macro_export]
/// Ok or exiting the process.
macro_rules! ok_or_exit {
@@ -24,7 +13,7 @@ macro_rules! ok_or_exit {
}
#[macro_export]
/// Ok or exiting the process.
/// Some or exiting the process.
macro_rules! some_or_exit {
($e:expr_2021, $code:expr_2021) => {{
match $e {

View File

@@ -1,12 +1,12 @@
use std::io::{Result, Write};
/// Write `indent` number of double spaces to `write`.
pub fn write_indent(indent: usize, write: &mut dyn Write) -> Result<()> {
pub(crate) fn write_indent(indent: usize, write: &mut dyn Write) -> Result<()> {
write!(write, "{}", " ".repeat(indent))
}
/// A trait for writing a type to a `Write` stream with a new line.
pub trait WriteLine {
pub(crate) trait WriteLine {
/// Write `self` to `write`, starting at `indent` number of double spaces, with a newline at the
/// end.
fn write_line(&self, indent: usize, write: &mut dyn Write) -> Result<()>;
@@ -15,7 +15,7 @@ pub trait WriteLine {
/// Essentially the same as [`ToString`].
///
/// Exists to make some foreign types into a string.
pub trait WriteString {
pub(crate) trait WriteString {
/// See [`ToString::to_string`].
fn write_string(&self) -> String;
}
@@ -44,6 +44,6 @@ impl<T: WriteString> WriteString for Option<T> {
}
/// Write `t` to `write`.
pub fn write<T: WriteLine>(t: &T, write: &mut dyn Write) -> Result<()> {
pub(crate) fn write<T: WriteLine>(t: &T, write: &mut dyn Write) -> Result<()> {
t.write_line(0, write)
}