diff --git a/fuzzer/inputs/expr.c b/fuzzer/inputs/expr.c index 94c4575..0c2b233 100644 --- a/fuzzer/inputs/expr.c +++ b/fuzzer/inputs/expr.c @@ -1,3 +1,3 @@ -int a = 2147483649 * 3 << +2 + a % (2) + (int)'d'; +short a = 217 - 3 & +2 % (2) + (short)'d'; int main() { return a; } diff --git a/fuzzer/inputs/header.c b/fuzzer/inputs/header.c index a8d5e50..3b3b6b5 100644 --- a/fuzzer/inputs/header.c +++ b/fuzzer/inputs/header.c @@ -1,6 +1,6 @@ #include int main() { - int a = 2; - printf("hello %d", a); + long a = 2; + printf("hello %ld", a); } diff --git a/fuzzer/src/main.rs b/fuzzer/src/main.rs index 4a98f77..b732fb5 100644 --- a/fuzzer/src/main.rs +++ b/fuzzer/src/main.rs @@ -1,12 +1,19 @@ #[macro_use] extern crate afl; +use std::collections::HashMap; use std::path::Path; use wrecc_compiler::*; fn main() { fuzz!(|data: &[u8]| { if let Ok(s) = std::str::from_utf8(data) { - if let Ok(source) = preprocess(Path::new("./some.c"),&Vec::new(),&Vec::new(), s.to_string()) { + if let Ok(source) = preprocess( + Path::new("./some.c"), + &Vec::new(), + &Vec::new(), + &HashMap::new(), + s.to_string(), + ) { let _ = compile(source, false); } } diff --git a/tests/fixtures/short_type.c b/tests/fixtures/short_type.c new file mode 100644 index 0000000..33cb9f2 --- /dev/null +++ b/tests/fixtures/short_type.c @@ -0,0 +1,13 @@ +#include + +short int foo(int short s) { return 4 - s; } + +int main() { + char c = sizeof((short int)5); + short int s = foo(9); + int short o = foo(3); + printf("%d", c); + printf("%d", s); + printf("%d", o); + printf("%ld", sizeof(s)); +} diff --git a/tests/snapshots/success_short_type b/tests/snapshots/success_short_type new file mode 100644 index 0000000..6393e73 --- /dev/null +++ b/tests/snapshots/success_short_type @@ -0,0 +1 @@ +2-512 \ No newline at end of file diff --git a/wrecc_compiler/src/compiler/codegen/register.rs b/wrecc_compiler/src/compiler/codegen/register.rs index e4b5495..dc55647 100644 --- a/wrecc_compiler/src/compiler/codegen/register.rs +++ b/wrecc_compiler/src/compiler/codegen/register.rs @@ -7,13 +7,13 @@ use crate::compiler::typechecker::mir::expr::ValueKind; use super::lir::maybe_prefix_underscore; /// Registers used for passing arguments to functions -pub static ARG_REGS: &[[&str; 3]; 6] = &[ - ["%rdi", "%edi", "%dil"], - ["%rsi", "%esi", "%sil"], - ["%rdx", "%edx", "%dl"], - ["%rcx", "%ecx", "%cl"], - ["%r8", "%r8d", "%r8b"], - ["%r9", "%r9d", "%r9b"], +pub static ARG_REGS: &[[&str; 4]; 6] = &[ + ["%rdi", "%edi", "%di", "%dil"], + ["%rsi", "%esi", "%si", "%sil"], + ["%rdx", "%edx", "%dx", "%dl"], + ["%rcx", "%ecx", "%cx", "%cl"], + ["%r8", "%r8d", "%r8w", "%r8b"], + ["%r9", "%r9d", "%r9w", "%r9b"], ]; /// All possible operands to an instruction in [LIR](crate::compiler::codegen::lir) @@ -376,7 +376,7 @@ impl ArgRegister { #[derive(Debug, PartialEq, Clone)] pub struct ArgRegisterKind { in_use: bool, - names: [&'static str; 3], + names: [&'static str; 4], } impl ArgRegisterKind { pub fn new(index: usize) -> Self { @@ -389,7 +389,8 @@ impl ScratchRegister for ArgRegisterKind { } fn name(&self, type_decl: &Type) -> String { match type_decl { - Type::Primitive(Primitive::Char) => self.names[2], + Type::Primitive(Primitive::Char) => self.names[3], + Type::Primitive(Primitive::Short) => self.names[2], Type::Primitive(Primitive::Int) | Type::Enum(..) => self.names[1], Type::Primitive(Primitive::Long) | Type::Pointer(_) | Type::Array { .. } => self.names[0], _ => unimplemented!("aggregate types are not yet implemented as function args"), diff --git a/wrecc_compiler/src/compiler/common/token.rs b/wrecc_compiler/src/compiler/common/token.rs index 185d266..f16eb17 100644 --- a/wrecc_compiler/src/compiler/common/token.rs +++ b/wrecc_compiler/src/compiler/common/token.rs @@ -66,6 +66,7 @@ pub enum TokenKind { Long, Int, Char, + Short, Struct, Union, Enum, @@ -196,6 +197,7 @@ impl Display for TokenKind { TokenKind::Char => "'char'", TokenKind::CharLit(_) => "'char'", TokenKind::Int => "'int'", + TokenKind::Short => "'short'", TokenKind::Long => "'long'", TokenKind::Struct => "'struct'", TokenKind::TypeDef => "'typedef'", @@ -302,6 +304,7 @@ impl Token { | TokenKind::Struct | TokenKind::Void | TokenKind::Char + | TokenKind::Short | TokenKind::Int | TokenKind::Long ) @@ -328,9 +331,10 @@ impl PartialEq for Token { impl Into for Token { fn into(self) -> SpecifierKind { match self.kind { - TokenKind::Int => SpecifierKind::Int, - TokenKind::Char => SpecifierKind::Char, TokenKind::Void => SpecifierKind::Void, + TokenKind::Char => SpecifierKind::Char, + TokenKind::Short => SpecifierKind::Short, + TokenKind::Int => SpecifierKind::Int, TokenKind::Long => SpecifierKind::Long, _ => unreachable!("token not specifier"), } diff --git a/wrecc_compiler/src/compiler/common/types.rs b/wrecc_compiler/src/compiler/common/types.rs index 5289539..fad248e 100644 --- a/wrecc_compiler/src/compiler/common/types.rs +++ b/wrecc_compiler/src/compiler/common/types.rs @@ -6,7 +6,7 @@ use crate::compiler::parser::hir::expr::*; use std::fmt::Display; use std::rc::Rc; -static RETURN_REG: &[&str; 3] = &["%al", "%eax", "%rax"]; +static RETURN_REG: &[&str; 4] = &["%al", "%ax", "%eax", "%rax"]; pub trait TypeInfo { /// Returns size of type in bytes @@ -248,6 +248,7 @@ impl Type { pub fn maybe_wrap(&self, n: i64) -> Option { match self { Type::Primitive(Primitive::Char) => Some(n as i8 as i64), + Type::Primitive(Primitive::Short) => Some(n as i16 as i64), Type::Primitive(Primitive::Int) | Type::Enum(..) => Some(n as i32 as i64), Type::Pointer(_) | Type::Primitive(Primitive::Long) => Some(n), _ => None, @@ -282,6 +283,7 @@ pub struct FuncType { pub enum Primitive { Void, Char, + Short, Int, Long, } @@ -292,6 +294,7 @@ impl TypeInfo for Primitive { match self { Primitive::Void => 0, Primitive::Char => 1, + Primitive::Short => 2, Primitive::Int => 4, Primitive::Long => 8, } @@ -300,6 +303,7 @@ impl TypeInfo for Primitive { String::from(match self { Primitive::Void => unreachable!(), Primitive::Char => "b", + Primitive::Short => "w", Primitive::Int => "d", Primitive::Long => "", }) @@ -311,6 +315,7 @@ impl TypeInfo for Primitive { String::from(match self { Primitive::Void => "zero", Primitive::Char => "byte", + Primitive::Short => "word", Primitive::Int => "long", Primitive::Long => "quad", }) @@ -319,8 +324,9 @@ impl TypeInfo for Primitive { String::from(match self { Primitive::Void => unreachable!("doesnt have return register when returning void"), Primitive::Char => RETURN_REG[0], - Primitive::Int => RETURN_REG[1], - Primitive::Long => RETURN_REG[2], + Primitive::Short => RETURN_REG[1], + Primitive::Int => RETURN_REG[2], + Primitive::Long => RETURN_REG[3], }) } } @@ -329,6 +335,7 @@ impl Primitive { match self { Primitive::Void => "void", Primitive::Char => "char", + Primitive::Short => "short", Primitive::Int => "int", Primitive::Long => "long", } @@ -338,6 +345,7 @@ impl Primitive { match self { Primitive::Void => unreachable!(), Primitive::Char => i8::MAX as i64, + Primitive::Short => i16::MAX as i64, Primitive::Int => i32::MAX as i64, Primitive::Long => i64::MAX, } @@ -346,6 +354,7 @@ impl Primitive { match self { Primitive::Void => unreachable!(), Primitive::Char => i8::MIN as i64, + Primitive::Short => i16::MIN as i64, Primitive::Int => i32::MIN as i64, Primitive::Long => i64::MIN, } @@ -623,7 +632,7 @@ pub mod tests { assert_type_print("char *(**)", "char ***"); assert_type_print("char *(*)[3][4][2]", "char *(*)[3][4][2]"); - assert_type_print("char (**[3][4])[2]", "char (**[3][4])[2]"); + assert_type_print("short (**[3][4])[2]", "short (**[3][4])[2]"); assert_type_print("char (**(*)[4])[2]", "char (**(*)[4])[2]"); assert_type_print("char(**(*[3])[4])[2]", "char (**(*[3])[4])[2]"); @@ -645,6 +654,6 @@ pub mod tests { "int (**(int *, char (*)()))[3]", ); - assert_type_print("int *(int**, ...)", "int *(int **, ...)"); + assert_type_print("short *(short int**, ...)", "short *(short **, ...)"); } } diff --git a/wrecc_compiler/src/compiler/parser/fold.rs b/wrecc_compiler/src/compiler/parser/fold.rs index a25cebf..5a2202b 100644 --- a/wrecc_compiler/src/compiler/parser/fold.rs +++ b/wrecc_compiler/src/compiler/parser/fold.rs @@ -649,6 +649,7 @@ mod tests { assert_fold_type("2147483648 + (int*)1", "(int*)8589934593", "int*"); assert_fold_type("'a'", "'a'", "char"); + assert_fold_type("'a' + (short)3", "100", "int"); assert_fold_type("-'a'", "-'a'", "int"); assert_fold_type("+'a'", "(int)'a'", "int"); @@ -685,6 +686,7 @@ mod tests { ); assert_fold_type("(char)127 + 2", "129", "int"); + assert_fold_type("(short)127 + 2", "129", "int"); assert_fold_type("2147483648 + 1", "2147483649", "long"); } diff --git a/wrecc_compiler/src/compiler/parser/hir/decl.rs b/wrecc_compiler/src/compiler/parser/hir/decl.rs index 2d41797..08e339a 100644 --- a/wrecc_compiler/src/compiler/parser/hir/decl.rs +++ b/wrecc_compiler/src/compiler/parser/hir/decl.rs @@ -61,6 +61,7 @@ pub struct MemberDeclarator { pub enum SpecifierKind { Void, Char, + Short, Int, Long, @@ -75,9 +76,12 @@ impl SpecifierKind { match self { SpecifierKind::Void => 0, SpecifierKind::Char => 1, - SpecifierKind::Int => 2, + SpecifierKind::Short => 2, SpecifierKind::Long => 3, - _ => 4, + // int is last in specifier order because thats easier to read: + // eg: `short int` `long int` + SpecifierKind::Int => 4, + _ => 5, } } } diff --git a/wrecc_compiler/src/compiler/scanner.rs b/wrecc_compiler/src/compiler/scanner.rs index 5282710..4d3c42c 100644 --- a/wrecc_compiler/src/compiler/scanner.rs +++ b/wrecc_compiler/src/compiler/scanner.rs @@ -23,6 +23,7 @@ impl<'a> Scanner<'a> { ("int", TokenKind::Int), ("long", TokenKind::Long), ("char", TokenKind::Char), + ("short", TokenKind::Short), ("struct", TokenKind::Struct), ("union", TokenKind::Union), ("enum", TokenKind::Enum), diff --git a/wrecc_compiler/src/compiler/typechecker/mod.rs b/wrecc_compiler/src/compiler/typechecker/mod.rs index bf4eaff..436c422 100644 --- a/wrecc_compiler/src/compiler/typechecker/mod.rs +++ b/wrecc_compiler/src/compiler/typechecker/mod.rs @@ -240,7 +240,7 @@ impl TypeChecker { let mut specifier_kind_list: Vec = specifiers.into_iter().map(|spec| spec.kind).collect(); - specifier_kind_list.sort_by_key(|spec| std::cmp::Reverse(spec.order())); + specifier_kind_list.sort_by_key(|spec| spec.order()); match specifier_kind_list.as_slice() { [hir::decl::SpecifierKind::Struct(name, members)] @@ -263,6 +263,10 @@ impl TypeChecker { [hir::decl::SpecifierKind::Void] => Ok(Type::Primitive(Primitive::Void)), [hir::decl::SpecifierKind::Char] => Ok(Type::Primitive(Primitive::Char)), + [hir::decl::SpecifierKind::Short] + | [hir::decl::SpecifierKind::Short, hir::decl::SpecifierKind::Int] => { + Ok(Type::Primitive(Primitive::Short)) + } [hir::decl::SpecifierKind::Int] => Ok(Type::Primitive(Primitive::Int)), [hir::decl::SpecifierKind::Long] | [hir::decl::SpecifierKind::Long, hir::decl::SpecifierKind::Int] @@ -2559,8 +2563,8 @@ int a;"; #[test] fn array_init_list() { - let actual = setup_init_list("int a[3] = {1,2};").unwrap(); - let expected = vec![(0, "1", "int"), (4, "2", "int")]; + let actual = setup_init_list("short a[3] = {1,2};").unwrap(); + let expected = vec![(0, "1", "short"), (2, "2", "short")]; assert_init(actual, expected); }