diff --git a/examples/array.c b/examples/array.c index 2ace5c6..110d0f9 100644 --- a/examples/array.c +++ b/examples/array.c @@ -1,9 +1,19 @@ -int sum(int len, int p[2][3]) { - return 0; +int sum(int len, int *p) { + int result = 0; + for (int i = 0; i < len; i++) { + result += p[i]; + } + + return result; } int main() { - int a[2][3]; + int a[5]; + int len = 5; + + for (int i = 0; i < len; i++) { + a[i] = i; + } - return 0; + return sum(len, a) == 10; } diff --git a/examples/array2.c b/examples/array2.c new file mode 100644 index 0000000..01fe612 --- /dev/null +++ b/examples/array2.c @@ -0,0 +1,16 @@ +void init(int row, int col, int a[4][5]) { + for (int i = 0; i < row; i++) { + for (int j = 0; j < col; j++) { + a[i][j] = i * j; + } + } +} + +int main() { + int a[4][5]; + int row = 4, col = 5; + + init(row, col, a); + + return a[2][3] == 6; +} diff --git a/examples/array3.c b/examples/array3.c new file mode 100644 index 0000000..414b3bd --- /dev/null +++ b/examples/array3.c @@ -0,0 +1,13 @@ +int* foo(int a[10]){ + return a; +} + +int main() { + int a[10]; + + for (int i = 0; i < 10; i++) { + (foo(a))[i] = i; + } + + return a[5] == 5; +} diff --git a/src/ir/dtype.rs b/src/ir/dtype.rs index 7e3fe2e..a6694a3 100644 --- a/src/ir/dtype.rs +++ b/src/ir/dtype.rs @@ -729,7 +729,10 @@ impl Dtype { } Self::Array { inner, size } => { let inner = inner.deref().clone().resolve_typedefs(typedefs)?; - Dtype::array(inner, *size) + Dtype::Array { + inner: Box::new(inner), + size: *size, + } } Self::Function { ret, params } => { let ret = ret.deref().clone().resolve_typedefs(typedefs)?; diff --git a/src/ir/interp.rs b/src/ir/interp.rs index 8f4ec27..345609c 100644 --- a/src/ir/interp.rs +++ b/src/ir/interp.rs @@ -950,6 +950,27 @@ impl<'i> State<'i> { } })? } + Instruction::GetElementPtr { ptr, offset, dtype } => { + let ptr = self.interp_operand(ptr.clone())?; + + let (value, _, _) = self + .interp_operand(offset.clone())? + .get_int() + .expect("`idx` must be `Value::Int`"); + + let (bid, prev_offset, ..) = ptr + .get_pointer() + .expect("`pointer` must be `Value::Pointer` to access memory"); + + let inner_dtype = dtype + .get_pointer_inner() + .expect("`dtype` must be pointer type"); + + let offset = prev_offset + value as isize; + assert!(0 <= offset); + + Value::pointer(*bid, offset as isize, inner_dtype.clone()) + } }; let register = RegisterId::temp(self.stack_frame.pc.bid, self.stack_frame.pc.iid); diff --git a/src/ir/mod.rs b/src/ir/mod.rs index e03bc51..997816e 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -210,6 +210,13 @@ pub enum Instruction { value: Operand, target_dtype: Dtype, }, + /// `GetElementPtr` is inspired from `getelementptr` instruction of LLVM. + /// https://llvm.org/docs/LangRef.html#i-getelementptr + GetElementPtr { + ptr: Operand, + offset: Operand, + dtype: Box, + }, } impl HasDtype for Instruction { @@ -228,6 +235,7 @@ impl HasDtype for Instruction { .set_const(false), Self::Call { return_type, .. } => return_type.clone(), Self::TypeCast { target_dtype, .. } => target_dtype.clone(), + Self::GetElementPtr { dtype, .. } => dtype.deref().clone(), } } } diff --git a/src/ir/write_ir.rs b/src/ir/write_ir.rs index f4c1850..71238e3 100644 --- a/src/ir/write_ir.rs +++ b/src/ir/write_ir.rs @@ -174,6 +174,9 @@ impl WriteString for Instruction { value, target_dtype, } => format!("typecast {} to {}", value.write_string(), target_dtype), + Instruction::GetElementPtr { ptr, offset, .. } => { + format!("getelementptr {} offset {}", ptr, offset) + } } } } diff --git a/src/tests.rs b/src/tests.rs index ffd2163..abdaa38 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,7 +1,7 @@ use lang_c::ast::*; use std::fs::{self, File}; use std::path::Path; -use std::process::Command; +use std::process::{Command, Stdio}; use tempfile::tempdir; use crate::*; @@ -25,17 +25,27 @@ pub fn test_irgen(unit: &TranslationUnit, path: &Path) { // Check if the file has .c extension assert_eq!(path.extension(), Some(std::ffi::OsStr::new("c"))); + // Test parse + c::Parse::default() + .translate(&path) + .expect("failed to parse the given program"); + let file_path = path.display().to_string(); let bin_path = path.with_extension("exe").as_path().display().to_string(); - // Compile c file - Command::new("gcc") + // Compile c file: If fails, test is vacuously success + if !Command::new("gcc") .args(&["-O1", &file_path, "-o", &bin_path]) - .output() - .expect("failed to compile the given program"); + .stderr(Stdio::null()) + .status() + .unwrap() + .success() + { + return; + } // Execute compiled executable - let status = Command::new(fs::canonicalize(format!("./{}", bin_path.clone())).unwrap()) + let status = Command::new(fs::canonicalize(bin_path.clone()).unwrap()) .status() .expect("failed to execute the compiled executable") .code()