Format and stuff

This commit is contained in:
Janggun Lee
2025-01-23 19:11:43 +09:00
parent fcb6ca2538
commit 00c64a5297
22 changed files with 201 additions and 163 deletions

View File

@@ -1,7 +1,7 @@
use clap::Parser;
use std::path::Path;
use clap::Parser;
#[derive(Debug, Parser)]
#[clap(name = "fuzz", version, author, about)]
struct FuzzCli {

View File

@@ -1,18 +1,16 @@
use clap::Parser;
use std::ffi::OsStr;
use std::io::Write;
use std::os::unix::io::{FromRawFd, IntoRawFd};
use std::path::Path;
use std::process::{Command, Stdio};
use lang_c::ast::TranslationUnit;
use tempfile::tempdir;
use clap::Parser;
use kecc::{
ir, ok_or_exit, write, Asmgen, Deadcode, Gvn, IrParse, IrVisualizer, Irgen, Mem2reg, Optimize,
Parse, SimplifyCfg, Translate, O1,
};
use lang_c::ast::TranslationUnit;
use tempfile::tempdir;
#[derive(Debug, Parser)]
#[clap(name = "kecc", version, author, about)]

View File

@@ -1,10 +1,10 @@
mod write_asm;
use crate::ir;
use core::convert::TryFrom;
use core::fmt;
use crate::ir;
/// An assembly file.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Asm {

View File

@@ -1,15 +1,24 @@
use crate::asm;
use crate::ir;
use crate::Translate;
use std::collections::{HashMap, HashSet, VecDeque};
#[derive(Default, Clone, Copy, Debug)]
use lang_c::ast;
use crate::ir::HasDtype;
use crate::{asm, ir, Translate};
#[derive(Debug)]
pub struct Asmgen {}
impl Default for Asmgen {
fn default() -> Self {
todo!()
}
}
impl Translate<ir::TranslationUnit> for Asmgen {
type Target = asm::Asm;
type Error = ();
fn translate(&mut self, _source: &ir::TranslationUnit) -> Result<Self::Target, Self::Error> {
todo!("Homework: Assembly Generation")
fn translate(&mut self, source: &ir::TranslationUnit) -> Result<Self::Target, Self::Error> {
todo!()
}
}

View File

@@ -8,14 +8,14 @@ use lang_c::span::Node;
use crate::utils::AssertSupported;
use crate::Translate;
/// TODO(document)
/// Parse Error
#[derive(Debug)]
pub enum Error {
ParseError(ParseError),
Unsupported,
}
/// TODO(document)
/// C file Parser.
#[derive(Default, Clone, Copy, Debug)]
pub struct Parse;

View File

@@ -1,9 +1,8 @@
use std::io::{Result, Write};
use lang_c::ast::*;
use lang_c::span::Node;
use core::ops::Deref;
use std::io::{Result, Write};
use crate::write_base::*;
impl<T: WriteLine> WriteLine for Node<T> {
@@ -19,8 +18,8 @@ impl<T: WriteString> WriteString for Node<T> {
}
impl WriteLine for TranslationUnit {
fn write_line(&self, _indent: usize, _write: &mut dyn Write) -> Result<()> {
todo!("Homework: write C")
fn write_line(&self, indent: usize, write: &mut dyn Write) -> Result<()> {
todo!()
}
}

View File

@@ -1,13 +1,13 @@
use core::convert::TryFrom;
use core::fmt;
use core::ops::Deref;
use lang_c::ast;
use lang_c::span::Node;
use std::collections::{HashMap, HashSet};
use std::hash::Hash;
use thiserror::Error;
use itertools::izip;
use lang_c::ast;
use lang_c::span::Node;
use thiserror::Error;
use crate::ir::*;
use crate::some_or;

View File

@@ -1,11 +1,9 @@
use core::fmt;
use core::iter;
use core::mem;
use ordered_float::OrderedFloat;
use core::{fmt, iter, mem};
use std::collections::HashMap;
use thiserror::Error;
use itertools::izip;
use ordered_float::OrderedFloat;
use thiserror::Error;
use crate::ir::*;
use crate::*;
@@ -410,10 +408,12 @@ impl<'i> StackFrame<'i> {
}
mod calculator {
use std::cmp::Ordering;
use lang_c::ast;
use super::Value;
use crate::ir::*;
use lang_c::ast;
use std::cmp::Ordering;
fn calculate_integer_binary_operator_expression(
op: &ast::BinaryOperator,

View File

@@ -10,15 +10,15 @@ mod write_ir;
use core::convert::TryFrom;
use core::fmt;
use core::ops::{Deref, DerefMut};
use hexf_parse::{parse_hexf32, parse_hexf64};
use itertools::Itertools;
use lang_c::ast;
use ordered_float::OrderedFloat;
use std::collections::{BTreeMap, HashMap};
use std::hash::{Hash, Hasher};
pub use dtype::{Dtype, DtypeError, HasDtype};
use hexf_parse::{parse_hexf32, parse_hexf64};
pub use interp::{interp, Value};
use itertools::Itertools;
use lang_c::ast;
use ordered_float::OrderedFloat;
pub use parse::Parse;
pub use visualize::Visualizer;

View File

@@ -5,8 +5,7 @@ use lang_c::*;
use crate::ir::*;
use crate::utils::AssertSupported;
use crate::Translate;
use crate::*;
use crate::{Translate, *};
peg::parser! {
grammar ir_parse() for str {

View File

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

View File

@@ -1,7 +1,6 @@
use crate::ir::*;
use std::io::{Result, Write};
use crate::ir::*;
use crate::write_base::*;
use crate::*;

View File

@@ -34,23 +34,22 @@
//! [irgen-stmt-1]: https://youtu.be/jFahkyxm994
//! [irgen-stmt-2]: https://youtu.be/UkaXaNw462U
//! [github-qna-irgen]: https://github.com/kaist-cp/cs420/labels/homework%20-%20irgen
#![allow(dead_code)]
use core::cmp::Ordering;
use core::convert::TryFrom;
use core::fmt;
use core::mem;
use core::{fmt, mem};
use std::collections::{BTreeMap, HashMap};
use std::ops::Deref;
use itertools::izip;
use lang_c::ast::*;
use lang_c::driver::Parse;
use lang_c::span::Node;
use thiserror::Error;
use crate::ir::{DtypeError, HasDtype, Named};
use crate::write_base::WriteString;
use crate::*;
use itertools::izip;
#[derive(Debug)]
pub struct IrgenError {
pub code: String,
@@ -69,6 +68,9 @@ impl fmt::Display for IrgenError {
}
}
/// Error format when a compiler error happens.
///
/// Feel free to add more kinds of errors.
#[derive(Debug, PartialEq, Eq, Error)]
pub enum IrgenErrorMessage {
/// For uncommon error
@@ -89,11 +91,17 @@ pub enum IrgenErrorMessage {
RequireLvalue { message: String },
}
/// A C file going through IR generation.
#[derive(Default, Debug)]
pub struct Irgen {
/// Declarations made in the C file (e.g, global variables and functions)
decls: BTreeMap<String, ir::Declaration>,
/// Type definitions made in the C file (e.g, typedef my_type = int;)
typedefs: HashMap<String, ir::Dtype>,
/// Structs defined in the C file,
// TODO: explain how to use this.
structs: HashMap<String, Option<ir::Dtype>>,
/// Temporary counter for anonymous structs. One should not need to use this any more.
struct_tempid_counter: usize,
}
@@ -112,14 +120,14 @@ impl Translate<TranslationUnit> for Irgen {
fn translate(&mut self, source: &TranslationUnit) -> Result<Self::Target, Self::Error> {
for ext_decl in &source.0 {
match ext_decl.node {
ExternalDeclaration::Declaration(ref var) => {
match &ext_decl.node {
ExternalDeclaration::Declaration(var) => {
self.add_declaration(&var.node)?;
}
ExternalDeclaration::StaticAssert(_) => {
panic!("ExternalDeclaration::StaticAssert is unsupported")
}
ExternalDeclaration::FunctionDefinition(ref func) => {
ExternalDeclaration::FunctionDefinition(func) => {
self.add_function_definition(&func.node)?;
}
}
@@ -513,9 +521,10 @@ impl IrgenFunc<'_> {
}
/// Create a new allocation with type given by `alloc`.
fn insert_alloc(&mut self, alloc: Named<ir::Dtype>) -> usize {
fn insert_alloc(&mut self, alloc: Named<ir::Dtype>) -> ir::RegisterId {
self.allocations.push(alloc);
self.allocations.len() - 1
let id = self.allocations.len() - 1;
ir::RegisterId::local(id)
}
/// Insert a new block `context` with exit instruction `exit`.
@@ -551,6 +560,7 @@ impl IrgenFunc<'_> {
/// Panics if there are no scopes to exit, i.e, the function has a unmatched `}`.
fn exit_scope(&mut self) {
let _unused = self.symbol_table.pop().unwrap();
debug_assert!(!self.symbol_table.is_empty())
}
/// Inserts `var` with `value` to the current symbol table.
@@ -576,15 +586,15 @@ impl IrgenFunc<'_> {
/// `bid_continue` and break block `bid_break`.
fn translate_stmt(
&mut self,
_stmt: &Statement,
_context: &mut Context,
_bid_continue: Option<ir::BlockId>,
_bid_break: Option<ir::BlockId>,
stmt: &Statement,
context: &mut Context,
bid_continue: Option<ir::BlockId>,
bid_break: Option<ir::BlockId>,
) -> Result<(), IrgenError> {
todo!("Homework: IR Generation")
todo!()
}
/// Translate parameter declaration of the functions to IR.
/// Translate initial parameter declarations of the functions to IR.
///
/// For example, given the following C function from [`foo.c`][foo]:
///
@@ -610,9 +620,11 @@ impl IrgenFunc<'_> {
/// %b0:p0:i32:x
/// %b0:p1:i32:y
/// %b0:p2:i32:z
/// ...
/// ```
///
/// With the following arguments :
///
/// ```ignore
/// signature = FunctionSignature { ret: ir::INT, params: vec![ir::INT, ir::INT, ir::INT] }
/// bid_init = 0
@@ -638,6 +650,7 @@ impl IrgenFunc<'_> {
/// %b0:i0:unit = store %b0:p0:i32 %l0:i32*
/// %b0:i1:unit = store %b0:p1:i32 %l1:i32*
/// %b0:i2:unit = store %b0:p2:i32 %l2:i32*
/// ...
/// ```
///
/// In particular, note that it is added to the local allocation list and store them to the
@@ -649,12 +662,12 @@ impl IrgenFunc<'_> {
/// [foo]: https://github.com/kaist-cp/kecc-public/blob/main/examples/c/foo.c
fn translate_parameter_decl(
&mut self,
_signature: &ir::FunctionSignature,
_bid_init: ir::BlockId,
_name_of_params: &[String],
_context: &mut Context,
signature: &ir::FunctionSignature,
bid_init: ir::BlockId,
name_of_params: &[String],
context: &mut Context,
) -> Result<(), IrgenErrorMessage> {
todo!("Homework: IR Generation")
todo!()
}
}

View File

@@ -5,45 +5,50 @@
#![deny(warnings)]
// Tries to deny all rustc allow lints.
// <https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html>
#![deny(absolute_paths_not_starting_with_crate)]
// Old, historical lint
// #![deny(box_pointers)]
#![deny(elided_lifetimes_in_paths)]
#![deny(explicit_outlives_requirements)]
#![deny(keyword_idents)]
#![deny(let_underscore_drop)]
#![deny(macro_use_extern_crate)]
#![deny(meta_variable_misuse)]
#![deny(missing_abi)]
#![deny(missing_copy_implementations)]
#![deny(missing_debug_implementations)]
// TODO
// #![deny(missing_docs)]
#![deny(non_ascii_idents)]
#![deny(noop_method_call)]
#![deny(rust_2021_incompatible_closure_captures)]
#![deny(rust_2021_incompatible_or_patterns)]
#![deny(rust_2021_prefixes_incompatible_syntax)]
#![deny(rust_2021_prelude_collisions)]
// Necessary for skeleton code.
// #![deny(single_use_lifetimes)]
#![deny(trivial_casts)]
#![deny(trivial_numeric_casts)]
// Necessary for skeleton code.
// #![deny(unreachable_pub)]
#![deny(unsafe_code)]
#![deny(unsafe_op_in_unsafe_fn)]
#![deny(unstable_features)]
// Necessary for `build-bin` trick.
// #![deny(unused_crate_dependencies)]
#![deny(unused_extern_crates)]
#![deny(unused_import_braces)]
#![deny(unused_lifetimes)]
#![deny(unused_macro_rules)]
#![deny(unused_qualifications)]
#![deny(unused_results)]
// Allowed for more flexible variants.
// #![deny(variant_size_differences)]
#![deny(
absolute_paths_not_starting_with_crate,
// Old, historical lint
// box_pointers,
elided_lifetimes_in_paths,
explicit_outlives_requirements,
keyword_idents,
let_underscore_drop,
macro_use_extern_crate,
meta_variable_misuse,
missing_abi,
// Most stuff are reasonably not copy.
// missing_copy_implementations,
missing_debug_implementations,
// TODO
// 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,
trivial_casts,
trivial_numeric_casts,
// Necessary for skeleton code.
// unreachable_pub,
unsafe_code,
unsafe_op_in_unsafe_fn,
unstable_features,
// Necessary for `build-bin` trick.
// unused_crate_dependencies,
unused_extern_crates,
unused_import_braces,
unused_lifetimes,
unused_macro_rules,
unused_qualifications,
unused_results,
// Allowed for more flexible variants.
// variant_size_differences,
)]
// For skeleton code.
#![allow(unused)]
mod tests;
mod utils;
@@ -57,17 +62,14 @@ mod asmgen;
mod irgen;
mod opt;
pub use tests::*;
pub use utils::*;
pub use write_base::write;
pub use c::Parse;
pub use ir::Parse as IrParse;
pub use ir::Visualizer as IrVisualizer;
pub use asmgen::Asmgen;
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,
};
pub use tests::*;
pub use utils::*;
pub use write_base::write;

View File

@@ -1,6 +1,9 @@
use core::ops::Deref;
use std::collections::{HashMap, HashSet};
use crate::ir::*;
use crate::opt::FunctionPass;
use crate::*;
use crate::opt::opt_utils::*;
use crate::opt::*;
pub type Deadcode = FunctionPass<Repeat<DeadcodeInner>>;
@@ -8,7 +11,7 @@ pub type Deadcode = FunctionPass<Repeat<DeadcodeInner>>;
pub struct DeadcodeInner {}
impl Optimize<FunctionDefinition> for DeadcodeInner {
fn optimize(&mut self, _code: &mut FunctionDefinition) -> bool {
todo!("Homework: Deadcode Elimination")
fn optimize(&mut self, code: &mut FunctionDefinition) -> bool {
todo!()
}
}

View File

@@ -1,13 +1,20 @@
use crate::opt::FunctionPass;
use crate::*;
use core::ops::Deref;
use std::collections::HashMap;
use itertools::izip;
use lang_c::ast;
use crate::ir::*;
use crate::opt::opt_utils::*;
use crate::opt::*;
pub type Gvn = FunctionPass<GvnInner>;
#[derive(Default, Clone, Copy, Debug)]
pub struct GvnInner {}
impl Optimize<ir::FunctionDefinition> for GvnInner {
fn optimize(&mut self, _code: &mut ir::FunctionDefinition) -> bool {
todo!("Homework: Global Variable Numbering")
impl Optimize<FunctionDefinition> for GvnInner {
fn optimize(&mut self, code: &mut FunctionDefinition) -> bool {
todo!()
}
}

View File

@@ -1,6 +1,9 @@
use core::ops::{Deref, DerefMut};
use std::collections::{BTreeMap, HashMap, HashSet};
use crate::ir::*;
use crate::opt::FunctionPass;
use crate::*;
use crate::opt::opt_utils::*;
use crate::opt::*;
pub type Mem2reg = FunctionPass<Mem2regInner>;
@@ -8,7 +11,7 @@ pub type Mem2reg = FunctionPass<Mem2regInner>;
pub struct Mem2regInner {}
impl Optimize<FunctionDefinition> for Mem2regInner {
fn optimize(&mut self, _code: &mut FunctionDefinition) -> bool {
todo!("Homework: Register Promotion")
fn optimize(&mut self, code: &mut FunctionDefinition) -> bool {
todo!()
}
}

View File

@@ -1,5 +1,5 @@
//! Utilities for implementing optimizations.
//!
//! You can add here utilities commonly used in the implementation of multiple optimizations.
//! You can freely add utilities commonly used in the implementation of multiple optimizations here.
#![allow(dead_code)]

View File

@@ -1,6 +1,11 @@
use std::collections::{HashMap, HashSet};
use std::ops::Deref;
use itertools::izip;
use crate::ir::*;
use crate::opt::FunctionPass;
use crate::*;
use crate::opt::opt_utils::*;
use crate::opt::*;
pub type SimplifyCfg = FunctionPass<
Repeat<(
@@ -26,25 +31,25 @@ pub struct SimplifyCfgMerge {}
pub struct SimplifyCfgEmpty {}
impl Optimize<FunctionDefinition> for SimplifyCfgConstProp {
fn optimize(&mut self, _code: &mut FunctionDefinition) -> bool {
todo!("Homework: Simplify CFG")
fn optimize(&mut self, code: &mut FunctionDefinition) -> bool {
todo!()
}
}
impl Optimize<FunctionDefinition> for SimplifyCfgReach {
fn optimize(&mut self, _code: &mut FunctionDefinition) -> bool {
todo!("Homework: Simplify CFG")
fn optimize(&mut self, code: &mut FunctionDefinition) -> bool {
todo!()
}
}
impl Optimize<FunctionDefinition> for SimplifyCfgMerge {
fn optimize(&mut self, _code: &mut FunctionDefinition) -> bool {
todo!("Homework: Simplify CFG")
fn optimize(&mut self, code: &mut FunctionDefinition) -> bool {
todo!()
}
}
impl Optimize<FunctionDefinition> for SimplifyCfgEmpty {
fn optimize(&mut self, _code: &mut FunctionDefinition) -> bool {
todo!("Homework: Simplify CFG")
fn optimize(&mut self, code: &mut FunctionDefinition) -> bool {
todo!()
}
}

View File

@@ -1,9 +1,10 @@
use lang_c::*;
use rand::Rng;
use std::fs::{self, File};
use std::io::{stderr, Read, Write};
use std::path::Path;
use std::process::{Command, Stdio};
use lang_c::*;
use rand::Rng;
use tempfile::tempdir;
use wait_timeout::ChildExt;

View File

@@ -1,11 +1,7 @@
use itertools::izip;
use core::ops::Deref;
#[macro_export]
/// Ok or executing the given expression.
macro_rules! ok_or {
($e:expr, $err:expr) => {{
($e:expr_2021, $err:expr_2021) => {{
match $e {
Ok(r) => r,
Err(_) => $err,
@@ -16,7 +12,7 @@ macro_rules! ok_or {
#[macro_export]
/// Some or executing the given expression.
macro_rules! some_or {
($e:expr, $err:expr) => {{
($e:expr_2021, $err:expr_2021) => {{
match $e {
Some(r) => r,
None => $err,
@@ -27,7 +23,7 @@ macro_rules! some_or {
#[macro_export]
/// Ok or exiting the process.
macro_rules! ok_or_exit {
($e:expr, $code:expr) => {{
($e:expr_2021, $code:expr_2021) => {{
match $e {
Ok(r) => r,
Err(e) => {
@@ -41,7 +37,7 @@ macro_rules! ok_or_exit {
#[macro_export]
/// Ok or exiting the process.
macro_rules! some_or_exit {
($e:expr, $code:expr) => {{
($e:expr_2021, $code:expr_2021) => {{
match $e {
Some(r) => r,
None => ::std::process::exit($code),
@@ -49,33 +45,41 @@ macro_rules! some_or_exit {
}};
}
/// TODO(document)
/// Translates `S` to [`Translate::Target`].
// TODO: Should this be in utils?
pub trait Translate<S> {
/// TODO(document)
/// The type to translate to.
type Target;
/// TODO(document)
/// The error type.
type Error;
/// TODO(document)
/// Translate `source` to `Self::Target`.
fn translate(&mut self, source: &S) -> Result<Self::Target, Self::Error>;
}
/// TODO(document)
/// Trait to check if a type can be translated.
pub trait AssertSupported {
/// TODO(document)
/// Assert that the type can be translated.
///
/// # Panics
///
/// Panics if the type can't be translated.
// TODO: should return a boolean.
fn assert_supported(&self);
}
/// TODO(document)
/// Essentially the same as [`PartialEq`].
///
/// Exists to check equaility on some foreign types.
pub trait IsEquiv {
/// TODO(document)
/// See [`PartialEq::eq`].
fn is_equiv(&self, other: &Self) -> bool;
}
impl<T: IsEquiv> IsEquiv for Box<T> {
fn is_equiv(&self, other: &Self) -> bool {
self.deref().is_equiv(other.deref())
(**self).is_equiv(&**other)
}
}
@@ -97,6 +101,6 @@ impl<T: IsEquiv> IsEquiv for Option<T> {
impl<T: IsEquiv> IsEquiv for Vec<T> {
fn is_equiv(&self, other: &Self) -> bool {
self.len() == other.len() && izip!(self, other).all(|(lhs, rhs)| lhs.is_equiv(rhs))
self.len() == other.len() && self.iter().zip(other).all(|(lhs, rhs)| lhs.is_equiv(rhs))
}
}

View File

@@ -1,7 +1,6 @@
use std::io::{Result, Write};
/// Write `indent` number of double spaces to `write`.
#[inline]
pub fn write_indent(indent: usize, write: &mut dyn Write) -> Result<()> {
write!(write, "{}", " ".repeat(indent))
}
@@ -9,24 +8,21 @@ pub fn write_indent(indent: usize, write: &mut dyn Write) -> Result<()> {
/// A trait for writing a type to a `Write` stream with a new line.
pub trait WriteLine {
/// Write `self` to `write`, starting at `indent` number of double spaces, with a newline at the
/// ned.
/// end.
fn write_line(&self, indent: usize, write: &mut dyn Write) -> Result<()>;
}
/// Format types to a String.
/// Essentially the same as [`ToString`].
///
/// Most cases, `fmt::Display` is used to format a type to a string. However, in some cases, we
/// can't implement `fmt::Display` for a type as it is defined in another crate. In such cases, we
/// can implement this trait to format the type to a string.
/// Exists to make some foreign types into a string.
pub trait WriteString {
/// Change a type into a String.
/// See [`ToString::to_string`].
fn write_string(&self) -> String;
}
impl<T: WriteString> WriteString for Box<T> {
fn write_string(&self) -> String {
use core::ops::Deref;
self.deref().write_string()
(**self).write_string()
}
}
@@ -36,6 +32,7 @@ impl<T: WriteString> WriteString for &T {
}
}
// Might be useful for debugging.
impl<T: WriteString> WriteString for Option<T> {
fn write_string(&self) -> String {
if let Some(this) = self {