From 503e09e572c4c0d9e10173730482a1ccf90d9dd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Thu, 25 Apr 2024 17:49:12 -0300 Subject: [PATCH 01/19] Add local_ty for ConstantIndex store --- crates/concrete_codegen_mlir/src/codegen.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/crates/concrete_codegen_mlir/src/codegen.rs b/crates/concrete_codegen_mlir/src/codegen.rs index 8e5f8c0..2936756 100644 --- a/crates/concrete_codegen_mlir/src/codegen.rs +++ b/crates/concrete_codegen_mlir/src/codegen.rs @@ -1013,7 +1013,12 @@ fn compile_store_place<'c: 'b, 'b>( } } PlaceElem::Index(_) => todo!(), - PlaceElem::ConstantIndex(_) => todo!(), + PlaceElem::ConstantIndex(index) => { + local_ty = match local_ty.kind { + TyKind::Array(inner, _) => *inner, + _ => unreachable!(), + } + } } } From 8b53d8c55a2ca211c0c1da617d293da9c666a268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Thu, 25 Apr 2024 18:27:36 -0300 Subject: [PATCH 02/19] Compile array type --- crates/concrete_codegen_mlir/src/codegen.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/concrete_codegen_mlir/src/codegen.rs b/crates/concrete_codegen_mlir/src/codegen.rs index 2936756..0a13911 100644 --- a/crates/concrete_codegen_mlir/src/codegen.rs +++ b/crates/concrete_codegen_mlir/src/codegen.rs @@ -1277,7 +1277,15 @@ fn compile_type<'c>(ctx: ModuleCodegenCtx<'c>, ty: &Ty) -> Type<'c> { concrete_ir::FloatTy::F64 => Type::float64(ctx.ctx.mlir_context), }, concrete_ir::TyKind::String => todo!(), - concrete_ir::TyKind::Array(_, _) => todo!(), + concrete_ir::TyKind::Array(inner_type, length) => { + let inner_type = compile_type(ctx, inner_type); + let length = match length.data { + concrete_ir::ConstKind::Value(ValueTree::Leaf(ConstValue::U64(length))) => length, + _ => unimplemented!(), + }; + + melior::dialect::llvm::r#type::array(inner_type, length as u32) + } concrete_ir::TyKind::Ref(_inner_ty, _) | concrete_ir::TyKind::Ptr(_inner_ty, _) => { llvm::r#type::opaque_pointer(ctx.ctx.mlir_context) } From 09a13a113560348ae913f40f50bf6d4924de0f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Thu, 25 Apr 2024 18:35:35 -0300 Subject: [PATCH 03/19] Add ptr for ConstantIndex store --- crates/concrete_codegen_mlir/src/codegen.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/crates/concrete_codegen_mlir/src/codegen.rs b/crates/concrete_codegen_mlir/src/codegen.rs index 0a13911..77fd197 100644 --- a/crates/concrete_codegen_mlir/src/codegen.rs +++ b/crates/concrete_codegen_mlir/src/codegen.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; use concrete_ir::{ - BinOp, DefId, FnBody, LocalKind, ModuleBody, Operand, Place, PlaceElem, ProgramBody, Rvalue, - Span, Ty, TyKind, ValueTree, + BinOp, ConstValue, DefId, FnBody, LocalKind, ModuleBody, Operand, Place, PlaceElem, + ProgramBody, Rvalue, Span, Ty, TyKind, ValueTree, }; use concrete_session::Session; use melior::{ @@ -1014,6 +1014,21 @@ fn compile_store_place<'c: 'b, 'b>( } PlaceElem::Index(_) => todo!(), PlaceElem::ConstantIndex(index) => { + ptr = block + .append_operation(llvm::get_element_ptr( + ctx.context(), + ptr, + DenseI32ArrayAttribute::new( + ctx.context(), + &[0, (*index).try_into().unwrap()], + ), + compile_type(ctx.module_ctx, &local_ty), + opaque_pointer(ctx.context()), + Location::unknown(ctx.context()), + )) + .result(0)? + .into(); + local_ty = match local_ty.kind { TyKind::Array(inner, _) => *inner, _ => unreachable!(), From 3946b87dbe404c04703b3861d74a6ba8d12cb782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Fri, 26 Apr 2024 13:08:10 -0300 Subject: [PATCH 04/19] Use GEP correctly --- crates/concrete_codegen_mlir/src/codegen.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/crates/concrete_codegen_mlir/src/codegen.rs b/crates/concrete_codegen_mlir/src/codegen.rs index 77fd197..300da75 100644 --- a/crates/concrete_codegen_mlir/src/codegen.rs +++ b/crates/concrete_codegen_mlir/src/codegen.rs @@ -1014,25 +1014,22 @@ fn compile_store_place<'c: 'b, 'b>( } PlaceElem::Index(_) => todo!(), PlaceElem::ConstantIndex(index) => { + local_ty = match local_ty.kind { + TyKind::Array(inner, _) => *inner, + _ => unreachable!(), + }; + ptr = block .append_operation(llvm::get_element_ptr( ctx.context(), ptr, - DenseI32ArrayAttribute::new( - ctx.context(), - &[0, (*index).try_into().unwrap()], - ), + DenseI32ArrayAttribute::new(ctx.context(), &[(*index).try_into().unwrap()]), compile_type(ctx.module_ctx, &local_ty), opaque_pointer(ctx.context()), Location::unknown(ctx.context()), )) .result(0)? .into(); - - local_ty = match local_ty.kind { - TyKind::Array(inner, _) => *inner, - _ => unreachable!(), - } } } } From b5bf99f4535f3a5f1a5cc32fb16318156e8af68b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Fri, 26 Apr 2024 13:10:12 -0300 Subject: [PATCH 05/19] Implement PlaceElem::Index in load_place --- crates/concrete_codegen_mlir/src/codegen.rs | 26 ++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/crates/concrete_codegen_mlir/src/codegen.rs b/crates/concrete_codegen_mlir/src/codegen.rs index 300da75..9336736 100644 --- a/crates/concrete_codegen_mlir/src/codegen.rs +++ b/crates/concrete_codegen_mlir/src/codegen.rs @@ -1101,7 +1101,31 @@ fn compile_load_place<'c: 'b, 'b>( _ => unreachable!(), } } - PlaceElem::Index(_) => todo!(), + PlaceElem::Index(local) => { + local_ty = match local_ty.kind { + TyKind::Array(inner, _) => *inner, + _ => unreachable!(), + }; + + let place = Place { + local, + projection: None, + }; + + let (index, _) = compile_load_place(ctx, block, &place, locals)?; + + ptr = block + .append_operation(llvm::get_element_ptr_dynamic( + ctx.context(), + ptr, + &[index], + compile_type(ctx.module_ctx, &local_ty), + opaque_pointer(ctx.context()), + Location::unknown(ctx.context()), + )) + .result(0)? + .into(); + } PlaceElem::ConstantIndex(_) => todo!(), } } From 55b0c0ceb1826156c76bccd6441e705e4c04486b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Fri, 26 Apr 2024 13:23:36 -0300 Subject: [PATCH 06/19] Fix bug --- crates/concrete_codegen_mlir/src/codegen.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/concrete_codegen_mlir/src/codegen.rs b/crates/concrete_codegen_mlir/src/codegen.rs index 9336736..554b3ed 100644 --- a/crates/concrete_codegen_mlir/src/codegen.rs +++ b/crates/concrete_codegen_mlir/src/codegen.rs @@ -1108,8 +1108,8 @@ fn compile_load_place<'c: 'b, 'b>( }; let place = Place { - local, - projection: None, + local: *local, + projection: Default::default(), }; let (index, _) = compile_load_place(ctx, block, &place, locals)?; From 31f70a2f6f55975da4e4291bc477dd463b3fb7e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Fri, 26 Apr 2024 13:31:05 -0300 Subject: [PATCH 07/19] Add array modifying to example --- examples/arrays.con | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/arrays.con b/examples/arrays.con index 9721fd7..52ade15 100644 --- a/examples/arrays.con +++ b/examples/arrays.con @@ -1,7 +1,10 @@ mod Example { fn main() -> i32 { - let array: [i32; 4] = [1, 2, 3, 4]; - let nested_array: [[i32; 2]; 2] = [[1, 2], [3, 4]]; + let mut array: [i32; 4] = [1, 9, 3, 4]; + let nested_array: [[i32; 2]; 2] = [[1, 2], [9, 9]]; + + array[1] = 2; + nested_array[1] = [3, 4]; let a: i32 = array[1]; let b: i32 = nested_array[1][0]; From f800fd3e176d50e7bd6969f7de796fbb1bf86aa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Fri, 26 Apr 2024 13:33:10 -0300 Subject: [PATCH 08/19] Add constant index to load_place --- crates/concrete_codegen_mlir/src/codegen.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/crates/concrete_codegen_mlir/src/codegen.rs b/crates/concrete_codegen_mlir/src/codegen.rs index 554b3ed..c15c7b7 100644 --- a/crates/concrete_codegen_mlir/src/codegen.rs +++ b/crates/concrete_codegen_mlir/src/codegen.rs @@ -1126,7 +1126,23 @@ fn compile_load_place<'c: 'b, 'b>( .result(0)? .into(); } - PlaceElem::ConstantIndex(_) => todo!(), + PlaceElem::ConstantIndex(index) => { + local_ty = match local_ty.kind { + TyKind::Array(inner, _) => *inner, + _ => unreachable!(), + }; + ptr = block + .append_operation(llvm::get_element_ptr( + ctx.context(), + ptr, + DenseI32ArrayAttribute::new(ctx.context(), &[(*index).try_into().unwrap()]), + compile_type(ctx.module_ctx, &local_ty), + opaque_pointer(ctx.context()), + Location::unknown(ctx.context()), + )) + .result(0)? + .into(); + } } } From f92aeb9645a58b9509cdbd97fb1f3edd9f137618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Fri, 26 Apr 2024 13:34:32 -0300 Subject: [PATCH 09/19] Add Index to store place --- crates/concrete_codegen_mlir/src/codegen.rs | 26 ++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/crates/concrete_codegen_mlir/src/codegen.rs b/crates/concrete_codegen_mlir/src/codegen.rs index c15c7b7..cb1e1d4 100644 --- a/crates/concrete_codegen_mlir/src/codegen.rs +++ b/crates/concrete_codegen_mlir/src/codegen.rs @@ -1012,7 +1012,31 @@ fn compile_store_place<'c: 'b, 'b>( _ => unreachable!(), } } - PlaceElem::Index(_) => todo!(), + PlaceElem::Index(local) => { + local_ty = match local_ty.kind { + TyKind::Array(inner, _) => *inner, + _ => unreachable!(), + }; + + let place = Place { + local: *local, + projection: vec![], + }; + + let (index, _) = compile_load_place(ctx, block, &place, locals)?; + + ptr = block + .append_operation(llvm::get_element_ptr_dynamic( + ctx.context(), + ptr, + &[index], + compile_type(ctx.module_ctx, &local_ty), + opaque_pointer(ctx.context()), + Location::unknown(ctx.context()), + )) + .result(0)? + .into(); + } PlaceElem::ConstantIndex(index) => { local_ty = match local_ty.kind { TyKind::Array(inner, _) => *inner, From 7d963374e7c215c12a1ee2ddfc5d81816183a309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Fri, 26 Apr 2024 13:44:21 -0300 Subject: [PATCH 10/19] Add test for array --- crates/concrete_driver/tests/examples.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/concrete_driver/tests/examples.rs b/crates/concrete_driver/tests/examples.rs index 8ca3e6c..455f58e 100644 --- a/crates/concrete_driver/tests/examples.rs +++ b/crates/concrete_driver/tests/examples.rs @@ -20,6 +20,7 @@ mod common; #[test_case(include_str!("../../../examples/if_if_false.con"), "if_if_false", false, 7 ; "if_if_false.con")] #[test_case(include_str!("../../../examples/for.con"), "for", false, 10 ; "for.con")] #[test_case(include_str!("../../../examples/for_while.con"), "for_while", false, 10 ; "for_while.con")] +#[test_case(include_str!("../../../examples/arrays.con"), "arrays", false, 5 ; "arrays.con")] fn example_tests(source: &str, name: &str, is_library: bool, status_code: i32) { assert_eq!( status_code, From bfc07ea4a0a676660d2328326a0311312a391f94 Mon Sep 17 00:00:00 2001 From: Edgar Date: Tue, 7 May 2024 12:35:35 +0200 Subject: [PATCH 11/19] Add more type and mutability checks --- crates/concrete_check/src/lib.rs | 46 ++++++++++++++++ crates/concrete_driver/tests/checks.rs | 55 +++++++++++++++++-- .../invalid_programs/immutable_mutation.con | 7 +++ .../tests/invalid_programs/invalid_assign.con | 8 +++ .../{refmut.con => invalid_borrow_mut.con} | 2 +- .../mutable_nonmut_borrow.con | 8 +++ crates/concrete_ir/src/lib.rs | 44 ++++++++++++++- crates/concrete_ir/src/lowering.rs | 50 ++++++++++++++--- crates/concrete_ir/src/lowering/errors.rs | 12 ++++ examples/for.con | 2 +- examples/for_while.con | 2 +- examples/if_if_false.con | 2 +- 12 files changed, 220 insertions(+), 18 deletions(-) create mode 100644 crates/concrete_driver/tests/invalid_programs/immutable_mutation.con create mode 100644 crates/concrete_driver/tests/invalid_programs/invalid_assign.con rename crates/concrete_driver/tests/invalid_programs/{refmut.con => invalid_borrow_mut.con} (82%) create mode 100644 crates/concrete_driver/tests/invalid_programs/mutable_nonmut_borrow.con diff --git a/crates/concrete_check/src/lib.rs b/crates/concrete_check/src/lib.rs index 608d53b..c10dc8b 100644 --- a/crates/concrete_check/src/lib.rs +++ b/crates/concrete_check/src/lib.rs @@ -222,5 +222,51 @@ pub fn lowering_error_to_report( .with_message(msg) .finish() } + LoweringError::NotMutable { + span, + declare_span, + program_id, + } => { + let path = file_paths[program_id].display().to_string(); + let mut report = Report::build(ReportKind::Error, path.clone(), span.from) + .with_code("NotMutable") + .with_label( + Label::new((path.clone(), span.into())) + .with_message("can't mutate this variable because it's not mutable") + .with_color(colors.next()), + ); + + if let Some(declare_span) = declare_span { + report = report.with_label( + Label::new((path, declare_span.into())) + .with_message("variable declared here") + .with_color(colors.next()), + ); + } + report.finish() + } + LoweringError::CantTakeMutableBorrow { + span, + declare_span, + program_id, + } => { + let path = file_paths[program_id].display().to_string(); + let mut report = Report::build(ReportKind::Error, path.clone(), span.from) + .with_code("CantTakeMutableBorrow") + .with_label( + Label::new((path.clone(), span.into())) + .with_message("can't take a mutate borrow to this variable because it's not declared mutable") + .with_color(colors.next()), + ); + + if let Some(declare_span) = declare_span { + report = report.with_label( + Label::new((path, declare_span.into())) + .with_message("variable declared here") + .with_color(colors.next()), + ); + } + report.finish() + } } } diff --git a/crates/concrete_driver/tests/checks.rs b/crates/concrete_driver/tests/checks.rs index 2a5e670..6673a6e 100644 --- a/crates/concrete_driver/tests/checks.rs +++ b/crates/concrete_driver/tests/checks.rs @@ -35,14 +35,14 @@ fn import_not_found() { #[test] fn invalid_borrow_mut() { - let (source, name) = (include_str!("invalid_programs/refmut.con"), "refmut"); + let (source, name) = ( + include_str!("invalid_programs/invalid_borrow_mut.con"), + "invalid_borrow_mut", + ); let error = check_invalid_program(source, name); assert!( - matches!( - &error, - LoweringError::BorrowNotMutable { name, .. } if name == "a" - ), + matches!(&error, LoweringError::NotMutable { .. }), "{:#?}", error ); @@ -102,3 +102,48 @@ fn undeclared_var() { error ); } + +#[test] +fn invalid_assign() { + let (source, name) = ( + include_str!("invalid_programs/invalid_assign.con"), + "invalid_assign", + ); + let error = check_invalid_program(source, name); + + assert!( + matches!(&error, LoweringError::UnexpectedType { .. }), + "{:#?}", + error + ); +} + +#[test] +fn immutable_mutation() { + let (source, name) = ( + include_str!("invalid_programs/immutable_mutation.con"), + "immutable_mutation", + ); + let error = check_invalid_program(source, name); + + assert!( + matches!(&error, LoweringError::NotMutable { .. }), + "{:#?}", + error + ); +} + +#[test] +fn mutable_nonmut_borrow() { + let (source, name) = ( + include_str!("invalid_programs/mutable_nonmut_borrow.con"), + "mutable_nonmut_borrow", + ); + let error = check_invalid_program(source, name); + + assert!( + matches!(&error, LoweringError::CantTakeMutableBorrow { .. }), + "{:#?}", + error + ); +} diff --git a/crates/concrete_driver/tests/invalid_programs/immutable_mutation.con b/crates/concrete_driver/tests/invalid_programs/immutable_mutation.con new file mode 100644 index 0000000..9d42bab --- /dev/null +++ b/crates/concrete_driver/tests/invalid_programs/immutable_mutation.con @@ -0,0 +1,7 @@ +mod Simple { + fn main() -> i32 { + let x: i32 = 2; + x = 4; + return x; + } +} diff --git a/crates/concrete_driver/tests/invalid_programs/invalid_assign.con b/crates/concrete_driver/tests/invalid_programs/invalid_assign.con new file mode 100644 index 0000000..69ace67 --- /dev/null +++ b/crates/concrete_driver/tests/invalid_programs/invalid_assign.con @@ -0,0 +1,8 @@ +mod Simple { + fn main() -> i32 { + let mut x: i32 = 2; + let y: i64 = 4; + x = y; + return x; + } +} diff --git a/crates/concrete_driver/tests/invalid_programs/refmut.con b/crates/concrete_driver/tests/invalid_programs/invalid_borrow_mut.con similarity index 82% rename from crates/concrete_driver/tests/invalid_programs/refmut.con rename to crates/concrete_driver/tests/invalid_programs/invalid_borrow_mut.con index 526ea46..7cbfb46 100644 --- a/crates/concrete_driver/tests/invalid_programs/refmut.con +++ b/crates/concrete_driver/tests/invalid_programs/invalid_borrow_mut.con @@ -1,7 +1,7 @@ mod Simple { fn main() -> i32 { - let x: i32 = 1; + let mut x: i32 = 1; hello(&x); return x; } diff --git a/crates/concrete_driver/tests/invalid_programs/mutable_nonmut_borrow.con b/crates/concrete_driver/tests/invalid_programs/mutable_nonmut_borrow.con new file mode 100644 index 0000000..e0bf1f5 --- /dev/null +++ b/crates/concrete_driver/tests/invalid_programs/mutable_nonmut_borrow.con @@ -0,0 +1,8 @@ +mod Simple { + fn main() -> i32 { + let x: i32 = 2; + let y: &mut i32 = &mut x; + *y = 4; + return *y; + } +} diff --git a/crates/concrete_ir/src/lib.rs b/crates/concrete_ir/src/lib.rs index 7be040f..1f425e4 100644 --- a/crates/concrete_ir/src/lib.rs +++ b/crates/concrete_ir/src/lib.rs @@ -178,6 +178,17 @@ pub enum Rvalue { Cast(Operand, Ty, Span), } +impl Rvalue { + pub fn get_local(&self) -> Option { + match self { + Rvalue::Use(op) => op.get_local(), + Rvalue::Ref(_, op) => Some(op.local), + Rvalue::Cast(op, _, _) => op.get_local(), + _ => None, + } + } +} + /// A operand is a value, either from a place in memory or constant data. #[derive(Debug, Clone)] pub enum Operand { @@ -185,6 +196,15 @@ pub enum Operand { Const(ConstData), } +impl Operand { + pub fn get_local(&self) -> Option { + match self { + Operand::Place(place) => Some(place.local), + Operand::Const(_) => None, + } + } +} + /// A place in memory, defined by the given local and it's projection (deref, field, index, etc). #[derive(Debug, Clone)] pub struct Place { @@ -216,15 +236,24 @@ pub struct Local { pub ty: Ty, /// The type of local. pub kind: LocalKind, + /// Whether this local is declared mutable. + pub mutable: bool, } impl Local { - pub fn new(span: Option, kind: LocalKind, ty: Ty, debug_name: Option) -> Self { + pub fn new( + span: Option, + kind: LocalKind, + ty: Ty, + debug_name: Option, + mutable: bool, + ) -> Self { Self { span, kind, ty, debug_name, + mutable, } } @@ -234,6 +263,19 @@ impl Local { ty, kind: LocalKind::Temp, debug_name: None, + mutable: false, + } + } + + pub fn is_mutable(&self) -> bool { + if self.mutable { + return true; + } + + match self.ty.kind { + TyKind::Ptr(_, is_mut) => matches!(is_mut, Mutability::Mut), + TyKind::Ref(_, is_mut) => matches!(is_mut, Mutability::Mut), + _ => false, } } } diff --git a/crates/concrete_ir/src/lowering.rs b/crates/concrete_ir/src/lowering.rs index 6cf620e..19189fb 100644 --- a/crates/concrete_ir/src/lowering.rs +++ b/crates/concrete_ir/src/lowering.rs @@ -258,10 +258,13 @@ fn lower_func( .clone(); builder.ret_local = builder.body.locals.len(); - builder - .body - .locals - .push(Local::new(None, LocalKind::ReturnPointer, ret_ty, None)); + builder.body.locals.push(Local::new( + None, + LocalKind::ReturnPointer, + ret_ty, + None, + false, + )); for (arg, ty) in func.decl.params.iter().zip(args_ty) { builder @@ -272,6 +275,7 @@ fn lower_func( LocalKind::Arg, ty, Some(arg.name.name.clone()), + false, )); } @@ -289,6 +293,7 @@ fn lower_func( LocalKind::Temp, ty, Some(name.name.clone()), + info.is_mutable, )); } LetStmtTarget::Destructure(_) => todo!(), @@ -306,6 +311,7 @@ fn lower_func( LocalKind::Temp, ty, Some(name.name.clone()), + info.is_mutable, )); } LetStmtTarget::Destructure(_) => todo!(), @@ -684,12 +690,12 @@ fn lower_let(builder: &mut FnBodyBuilder, info: &LetStmt) -> Result<(), Lowering match &info.target { LetStmtTarget::Simple { name, r#type } => { let ty = lower_type(&builder.ctx, r#type, builder.local_module)?; - let (rvalue, rvalue_ty, _exp_span) = + let (rvalue, rvalue_ty, rvalue_span) = lower_expression(builder, &info.value, Some(ty.clone()))?; if ty.kind != rvalue_ty.kind { return Err(LoweringError::UnexpectedType { - span: info.span, + span: rvalue_span, found: rvalue_ty, expected: ty.clone(), program_id: builder.local_module.program_id, @@ -720,6 +726,14 @@ fn lower_let(builder: &mut FnBodyBuilder, info: &LetStmt) -> Result<(), Lowering fn lower_assign(builder: &mut FnBodyBuilder, info: &AssignStmt) -> Result<(), LoweringError> { let (mut place, mut ty, _path_span) = lower_path(builder, &info.target)?; + if !builder.body.locals[place.local].is_mutable() { + return Err(LoweringError::NotMutable { + span: info.span, + declare_span: builder.body.locals[place.local].span, + program_id: builder.body.id.program_id, + }); + } + for _ in 0..info.derefs { match &ty.kind { TyKind::Ref(inner, is_mut) | TyKind::Ptr(inner, is_mut) => { @@ -738,7 +752,17 @@ fn lower_assign(builder: &mut FnBodyBuilder, info: &AssignStmt) -> Result<(), Lo place.projection.push(PlaceElem::Deref); } - let (rvalue, _rvalue_ty, _exp_span) = lower_expression(builder, &info.value, Some(ty.clone()))?; + let (rvalue, rvalue_ty, rvalue_span) = + lower_expression(builder, &info.value, Some(ty.clone()))?; + + if ty.kind != rvalue_ty.kind { + return Err(LoweringError::UnexpectedType { + span: rvalue_span, + found: rvalue_ty, + expected: ty.clone(), + program_id: builder.local_module.program_id, + }); + } builder.statements.push(Statement { span: Some(info.target.first.span), @@ -935,7 +959,17 @@ fn lower_expression( }, None => None, }; - let (value, ty, _span) = lower_expression(builder, inner, type_hint)?; + let (value, ty, _ref_target_span) = lower_expression(builder, inner, type_hint)?; + + if let Some(local) = value.get_local() { + if *mutable && !builder.body.locals[local].mutable { + return Err(LoweringError::CantTakeMutableBorrow { + span: *asref_span, + declare_span: builder.body.locals[local].span, + program_id: builder.body.id.program_id, + }); + } + } let mutability = match mutable { false => Mutability::Not, diff --git a/crates/concrete_ir/src/lowering/errors.rs b/crates/concrete_ir/src/lowering/errors.rs index 48d9a58..8d329c8 100644 --- a/crates/concrete_ir/src/lowering/errors.rs +++ b/crates/concrete_ir/src/lowering/errors.rs @@ -43,6 +43,18 @@ pub enum LoweringError { name: String, program_id: usize, }, + #[error("can't mutate this value because it's not declared mutable")] + NotMutable { + span: Span, + declare_span: Option, + program_id: usize, + }, + #[error("can't take a mutable borrow to this value because it's not declared mutable")] + CantTakeMutableBorrow { + span: Span, + declare_span: Option, + program_id: usize, + }, #[error("unrecognized type {name}")] UnrecognizedType { span: Span, diff --git a/examples/for.con b/examples/for.con index 1f2ddd0..154c7d5 100644 --- a/examples/for.con +++ b/examples/for.con @@ -6,7 +6,7 @@ mod Example { fn sum_to(limit: i64) -> i64 { let mut result: i64 = 0; - for (let n: i64 = 1; n <= limit; n = n + 1) { + for (let mut n: i64 = 1; n <= limit; n = n + 1) { result = result + n; } diff --git a/examples/for_while.con b/examples/for_while.con index d87f1d7..3da1adf 100644 --- a/examples/for_while.con +++ b/examples/for_while.con @@ -6,7 +6,7 @@ mod Example { fn sum_to(limit: i64) -> i64 { let mut result: i64 = 0; - let n: i64 = 1; + let mut n: i64 = 1; for (n <= limit) { result = result + n; n = n + 1; diff --git a/examples/if_if_false.con b/examples/if_if_false.con index a38c67d..456cd4c 100644 --- a/examples/if_if_false.con +++ b/examples/if_if_false.con @@ -1,6 +1,6 @@ mod Example { fn main() -> i32 { - let foo: i32 = 7; + let mut foo: i32 = 7; if true { if false { From 907fd28b809ba216e1d3e7f33179b0716120af5e Mon Sep 17 00:00:00 2001 From: Edgar Date: Tue, 7 May 2024 15:57:03 +0200 Subject: [PATCH 12/19] Fix opaque pointers in merge and remove wrappers.cpp --- crates/concrete_codegen_mlir/build.rs | 16 ------------- crates/concrete_codegen_mlir/src/codegen.rs | 8 +++---- crates/concrete_codegen_mlir/src/lib.rs | 15 +++--------- crates/concrete_codegen_mlir/src/wrappers.cpp | 23 ------------------- 4 files changed, 7 insertions(+), 55 deletions(-) delete mode 100644 crates/concrete_codegen_mlir/build.rs delete mode 100644 crates/concrete_codegen_mlir/src/wrappers.cpp diff --git a/crates/concrete_codegen_mlir/build.rs b/crates/concrete_codegen_mlir/build.rs deleted file mode 100644 index e94c06f..0000000 --- a/crates/concrete_codegen_mlir/build.rs +++ /dev/null @@ -1,16 +0,0 @@ -use std::env::var; - -fn main() { - let mlir_path = var("MLIR_SYS_180_PREFIX").expect("MLIR path should be set."); - - cc::Build::new() - .cpp(true) - .flag("-std=c++17") - .flag_if_supported("-Wno-unused-parameter") - .flag_if_supported("-Wno-comment") - .include(&format!("{mlir_path}/include")) - .file("src/wrappers.cpp") - .compile("ffi"); - - println!("cargo:rerun-if-changed=src/wrappers.cpp"); -} diff --git a/crates/concrete_codegen_mlir/src/codegen.rs b/crates/concrete_codegen_mlir/src/codegen.rs index 3ee279a..1aa5e5d 100644 --- a/crates/concrete_codegen_mlir/src/codegen.rs +++ b/crates/concrete_codegen_mlir/src/codegen.rs @@ -1031,7 +1031,7 @@ fn compile_store_place<'c: 'b, 'b>( ptr, &[index], compile_type(ctx.module_ctx, &local_ty), - opaque_pointer(ctx.context()), + pointer(ctx.context(), 0), Location::unknown(ctx.context()), )) .result(0)? @@ -1049,7 +1049,7 @@ fn compile_store_place<'c: 'b, 'b>( ptr, DenseI32ArrayAttribute::new(ctx.context(), &[(*index).try_into().unwrap()]), compile_type(ctx.module_ctx, &local_ty), - opaque_pointer(ctx.context()), + pointer(ctx.context(), 0), Location::unknown(ctx.context()), )) .result(0)? @@ -1144,7 +1144,7 @@ fn compile_load_place<'c: 'b, 'b>( ptr, &[index], compile_type(ctx.module_ctx, &local_ty), - opaque_pointer(ctx.context()), + pointer(ctx.context(), 0), Location::unknown(ctx.context()), )) .result(0)? @@ -1161,7 +1161,7 @@ fn compile_load_place<'c: 'b, 'b>( ptr, DenseI32ArrayAttribute::new(ctx.context(), &[(*index).try_into().unwrap()]), compile_type(ctx.module_ctx, &local_ty), - opaque_pointer(ctx.context()), + pointer(ctx.context(), 0), Location::unknown(ctx.context()), )) .result(0)? diff --git a/crates/concrete_codegen_mlir/src/lib.rs b/crates/concrete_codegen_mlir/src/lib.rs index a8e30aa..70a05cc 100644 --- a/crates/concrete_codegen_mlir/src/lib.rs +++ b/crates/concrete_codegen_mlir/src/lib.rs @@ -19,7 +19,6 @@ use llvm_sys::{ LLVMPrintModuleToFile, }, error::LLVMGetErrorMessage, - prelude::{LLVMContextRef, LLVMModuleRef}, target::{ LLVM_InitializeAllAsmPrinters, LLVM_InitializeAllTargetInfos, LLVM_InitializeAllTargetMCs, LLVM_InitializeAllTargets, @@ -34,6 +33,7 @@ use llvm_sys::{ LLVMCreatePassBuilderOptions, LLVMDisposePassBuilderOptions, LLVMRunPasses, }, }; +use mlir_sys::mlirTranslateModuleToLLVMIR; use module::MLIRModule; mod codegen; @@ -68,15 +68,6 @@ pub fn compile(session: &Session, program: &ProgramBody) -> Result LLVMModuleRef; -} - pub fn get_target_triple(_session: &Session) -> String { // TODO: use session to get the specified target triple let target_triple = unsafe { @@ -160,7 +151,7 @@ pub fn compile_to_object( let op = module.melior_module.as_operation().to_raw(); - let llvm_module = mlirTranslateModuleToLLVMIR(op, llvm_context); + let llvm_module = mlirTranslateModuleToLLVMIR(op, llvm_context as *mut _) as *mut _; let mut null = null_mut(); let mut error_buffer = addr_of_mut!(null); @@ -219,7 +210,7 @@ pub fn compile_to_object( OptLevel::Aggressive => 3, }; let passes = CString::new(format!("default")).unwrap(); - let error = LLVMRunPasses(llvm_module, passes.as_ptr(), machine, opts); + let error = LLVMRunPasses(llvm_module as *mut _, passes.as_ptr(), machine, opts); if !error.is_null() { let msg = LLVMGetErrorMessage(error); let msg = CStr::from_ptr(msg); diff --git a/crates/concrete_codegen_mlir/src/wrappers.cpp b/crates/concrete_codegen_mlir/src/wrappers.cpp deleted file mode 100644 index 004136f..0000000 --- a/crates/concrete_codegen_mlir/src/wrappers.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern "C" LLVMModuleRef mlirTranslateModuleToLLVMIR(MlirOperation module, - LLVMContextRef context) { - mlir::Operation *moduleOp = unwrap(module); - - llvm::LLVMContext *ctx = llvm::unwrap(context); - - std::unique_ptr llvmModule = mlir::translateModuleToLLVMIR( - moduleOp, *ctx); - - LLVMModuleRef moduleRef = llvm::wrap(llvmModule.release()); - - return moduleRef; -} From b52af8ae6d2510c77a91e49e24734b25783a7bb7 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Tue, 7 May 2024 08:24:22 +0200 Subject: [PATCH 13/19] add function call type checks --- crates/concrete_check/src/lib.rs | 19 +++++++++++ crates/concrete_driver/tests/checks.rs | 33 +++++++++++++++++++ .../invalid_programs/call_count_mismatch.con | 9 +++++ .../invalid_programs/invalid_call_params.con | 10 ++++++ crates/concrete_ir/src/lowering.rs | 23 +++++++++++-- crates/concrete_ir/src/lowering/errors.rs | 7 ++++ 6 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 crates/concrete_driver/tests/invalid_programs/call_count_mismatch.con create mode 100644 crates/concrete_driver/tests/invalid_programs/invalid_call_params.con diff --git a/crates/concrete_check/src/lib.rs b/crates/concrete_check/src/lib.rs index 608d53b..6289620 100644 --- a/crates/concrete_check/src/lib.rs +++ b/crates/concrete_check/src/lib.rs @@ -222,5 +222,24 @@ pub fn lowering_error_to_report( .with_message(msg) .finish() } + LoweringError::CallParamCountMismatch { + span, + found, + needs, + program_id, + } => { + let path = file_paths[program_id].to_str().unwrap().to_string(); + Report::build(ReportKind::Error, path.clone(), span.from) + .with_code("CallParamCountMismatch") + .with_label( + Label::new((path, span.into())) + .with_message(format!( + "function call parameter count mismatch: found {}, needs {}.", + found, needs + )) + .with_color(colors.next()), + ) + .finish() + } } } diff --git a/crates/concrete_driver/tests/checks.rs b/crates/concrete_driver/tests/checks.rs index 2a5e670..d4af71d 100644 --- a/crates/concrete_driver/tests/checks.rs +++ b/crates/concrete_driver/tests/checks.rs @@ -102,3 +102,36 @@ fn undeclared_var() { error ); } + +#[test] +fn call_count_mismatch() { + let (source, name) = ( + include_str!("invalid_programs/call_count_mismatch.con"), + "call_count_mismatch", + ); + let error = check_invalid_program(source, name); + + assert!( + matches!( + &error, + LoweringError::CallParamCountMismatch { found, needs, .. } if *found == 2 && *needs == 1 + ), + "{:#?}", + error + ); +} + +#[test] +fn invalid_call_params() { + let (source, name) = ( + include_str!("invalid_programs/invalid_call_params.con"), + "invalid_call_params", + ); + let error = check_invalid_program(source, name); + + assert!( + matches!(&error, LoweringError::UnexpectedType { .. }), + "{:#?}", + error + ); +} diff --git a/crates/concrete_driver/tests/invalid_programs/call_count_mismatch.con b/crates/concrete_driver/tests/invalid_programs/call_count_mismatch.con new file mode 100644 index 0000000..8fd3b1f --- /dev/null +++ b/crates/concrete_driver/tests/invalid_programs/call_count_mismatch.con @@ -0,0 +1,9 @@ +mod Test { + fn main() -> i32 { + return hello(1, 2); + } + + fn hello(a: i32) -> i32 { + return a * 2; + } +} diff --git a/crates/concrete_driver/tests/invalid_programs/invalid_call_params.con b/crates/concrete_driver/tests/invalid_programs/invalid_call_params.con new file mode 100644 index 0000000..6ae9715 --- /dev/null +++ b/crates/concrete_driver/tests/invalid_programs/invalid_call_params.con @@ -0,0 +1,10 @@ +mod Test { + fn main() -> i32 { + let x: u32 = 1; + return hello(x); + } + + fn hello(a: i32) -> i32 { + return a * 2; + } +} diff --git a/crates/concrete_ir/src/lowering.rs b/crates/concrete_ir/src/lowering.rs index 6cf620e..fefd5f8 100644 --- a/crates/concrete_ir/src/lowering.rs +++ b/crates/concrete_ir/src/lowering.rs @@ -1179,11 +1179,30 @@ fn lower_fn_call( } }; + if args_ty.len() != info.args.len() { + return Err(LoweringError::CallParamCountMismatch { + span: info.span, + found: info.args.len(), + needs: args_ty.len(), + program_id: builder.get_module_body().id.program_id, + }); + } + let mut args = Vec::new(); for (arg, arg_ty) in info.args.iter().zip(args_ty) { - let rvalue = lower_expression(builder, arg, Some(arg_ty.clone()))?; - args.push(rvalue.0); + let (rvalue, rvalue_ty, arg_span) = lower_expression(builder, arg, Some(arg_ty.clone()))?; + + if rvalue_ty.kind != arg_ty.kind { + return Err(LoweringError::UnexpectedType { + span: arg_span, + found: rvalue_ty, + expected: arg_ty, + program_id: builder.get_module_body().id.program_id, + }); + } + + args.push(rvalue); } let dest_local = builder.add_local(Local::temp(ret_ty.clone())); diff --git a/crates/concrete_ir/src/lowering/errors.rs b/crates/concrete_ir/src/lowering/errors.rs index 48d9a58..febab2d 100644 --- a/crates/concrete_ir/src/lowering/errors.rs +++ b/crates/concrete_ir/src/lowering/errors.rs @@ -76,4 +76,11 @@ pub enum LoweringError { }, #[error("internal error: {0}")] InternalError(String, usize), + #[error("function call parameter count mismatch, found {found}, needs {needs}")] + CallParamCountMismatch { + span: Span, + found: usize, + needs: usize, + program_id: usize, + }, } From 5644d2f060a83a7b44ce717bb68975c77b54684d Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Wed, 8 May 2024 11:38:15 +0200 Subject: [PATCH 14/19] apply suggestions --- crates/concrete_check/src/lib.rs | 26 +++++++++---------- crates/concrete_driver/tests/checks.rs | 12 ++++----- ...atch.con => call_param_count_mismatch.con} | 0 ...arams.con => call_param_type_mismatch.con} | 0 4 files changed, 19 insertions(+), 19 deletions(-) rename crates/concrete_driver/tests/invalid_programs/{call_count_mismatch.con => call_param_count_mismatch.con} (100%) rename crates/concrete_driver/tests/invalid_programs/{invalid_call_params.con => call_param_type_mismatch.con} (100%) diff --git a/crates/concrete_check/src/lib.rs b/crates/concrete_check/src/lib.rs index 6289620..81830c4 100644 --- a/crates/concrete_check/src/lib.rs +++ b/crates/concrete_check/src/lib.rs @@ -17,7 +17,7 @@ pub fn lowering_error_to_report( program_id, } => { let offset = span.from; - let path = file_paths[program_id].to_str().unwrap().to_string(); + let path = file_paths[program_id].display().to_string(); Report::build(ReportKind::Error, path.clone(), offset) .with_code("ModuleNotFound") .with_label( @@ -33,7 +33,7 @@ pub fn lowering_error_to_report( function, program_id, } => { - let path = file_paths[program_id].to_str().unwrap().to_string(); + let path = file_paths[program_id].display().to_string(); Report::build(ReportKind::Error, path.clone(), span.from) .with_code("FunctionNotFound") .with_label( @@ -48,7 +48,7 @@ pub fn lowering_error_to_report( name, program_id, } => { - let path = file_paths[program_id].to_str().unwrap().to_string(); + let path = file_paths[program_id].display().to_string(); Report::build(ReportKind::Error, path.clone(), span.from) .with_code("StructFieldNotFound") .with_label( @@ -64,7 +64,7 @@ pub fn lowering_error_to_report( symbol, program_id, } => { - let path = file_paths[program_id].to_str().unwrap().to_string(); + let path = file_paths[program_id].display().to_string(); let offset = symbol.span.from; Report::build(ReportKind::Error, path.clone(), offset) .with_code("ImportNotFound") @@ -90,7 +90,7 @@ pub fn lowering_error_to_report( type_span, program_id, } => { - let path = file_paths[program_id].to_str().unwrap().to_string(); + let path = file_paths[program_id].display().to_string(); let mut labels = vec![Label::new((path.clone(), span.into())) .with_message(format!( "Can't mutate {name:?} because it's behind a immutable borrow" @@ -115,7 +115,7 @@ pub fn lowering_error_to_report( name, program_id, } => { - let path = file_paths[program_id].to_str().unwrap().to_string(); + let path = file_paths[program_id].display().to_string(); Report::build(ReportKind::Error, path.clone(), span.from) .with_code("UnrecognizedType") .with_label( @@ -131,7 +131,7 @@ pub fn lowering_error_to_report( id, program_id, } => { - let path = file_paths[program_id].to_str().unwrap().to_string(); + let path = file_paths[program_id].display().to_string(); Report::build(ReportKind::Error, path.clone(), span.from) .with_code("E_ID") .with_label( @@ -147,7 +147,7 @@ pub fn lowering_error_to_report( message, program_id, } => { - let path = file_paths[program_id].to_str().unwrap().to_string(); + let path = file_paths[program_id].display().to_string(); Report::build(ReportKind::Error, path.clone(), span.from) .with_code("NotYetImplemented") .with_label( @@ -163,7 +163,7 @@ pub fn lowering_error_to_report( expected, program_id, } => { - let path = file_paths[program_id].to_str().unwrap().to_string(); + let path = file_paths[program_id].display().to_string(); let mut labels = vec![Label::new((path.clone(), span.into())) .with_message(format!( "Unexpected type '{}', expected '{}'", @@ -190,7 +190,7 @@ pub fn lowering_error_to_report( name, program_id, } => { - let path = file_paths[program_id].to_str().unwrap().to_string(); + let path = file_paths[program_id].display().to_string(); Report::build(ReportKind::Error, path.clone(), span.from) .with_code("UseOfUndeclaredVariable") .with_label( @@ -205,7 +205,7 @@ pub fn lowering_error_to_report( name, program_id, } => { - let path = file_paths[program_id].to_str().unwrap().to_string(); + let path = file_paths[program_id].display().to_string(); Report::build(ReportKind::Error, path.clone(), span.from) .with_code("ExternFnWithBody") .with_label( @@ -216,7 +216,7 @@ pub fn lowering_error_to_report( .finish() } LoweringError::InternalError(msg, program_id) => { - let path = file_paths[program_id].to_str().unwrap().to_string(); + let path = file_paths[program_id].display().to_string(); Report::build(ReportKind::Error, path.clone(), 0) .with_code("InternalError") .with_message(msg) @@ -228,7 +228,7 @@ pub fn lowering_error_to_report( needs, program_id, } => { - let path = file_paths[program_id].to_str().unwrap().to_string(); + let path = file_paths[program_id].display().to_string(); Report::build(ReportKind::Error, path.clone(), span.from) .with_code("CallParamCountMismatch") .with_label( diff --git a/crates/concrete_driver/tests/checks.rs b/crates/concrete_driver/tests/checks.rs index d4af71d..b5368ae 100644 --- a/crates/concrete_driver/tests/checks.rs +++ b/crates/concrete_driver/tests/checks.rs @@ -104,10 +104,10 @@ fn undeclared_var() { } #[test] -fn call_count_mismatch() { +fn call_param_count_mismatch() { let (source, name) = ( - include_str!("invalid_programs/call_count_mismatch.con"), - "call_count_mismatch", + include_str!("invalid_programs/call_param_count_mismatch.con"), + "call_param_count_mismatch", ); let error = check_invalid_program(source, name); @@ -122,10 +122,10 @@ fn call_count_mismatch() { } #[test] -fn invalid_call_params() { +fn call_param_type_mismatch() { let (source, name) = ( - include_str!("invalid_programs/invalid_call_params.con"), - "invalid_call_params", + include_str!("invalid_programs/call_param_type_mismatch.con"), + "call_param_type_mismatch", ); let error = check_invalid_program(source, name); diff --git a/crates/concrete_driver/tests/invalid_programs/call_count_mismatch.con b/crates/concrete_driver/tests/invalid_programs/call_param_count_mismatch.con similarity index 100% rename from crates/concrete_driver/tests/invalid_programs/call_count_mismatch.con rename to crates/concrete_driver/tests/invalid_programs/call_param_count_mismatch.con diff --git a/crates/concrete_driver/tests/invalid_programs/invalid_call_params.con b/crates/concrete_driver/tests/invalid_programs/call_param_type_mismatch.con similarity index 100% rename from crates/concrete_driver/tests/invalid_programs/invalid_call_params.con rename to crates/concrete_driver/tests/invalid_programs/call_param_type_mismatch.con From aff819dfefd124caf6310d191a087826c8c3a95c Mon Sep 17 00:00:00 2001 From: Edgar Date: Tue, 7 May 2024 15:33:43 +0200 Subject: [PATCH 15/19] Add pointer addition (arithmetic) and intrinsic parsing --- crates/concrete_ast/src/common.rs | 7 ++++ crates/concrete_ast/src/functions.rs | 3 +- crates/concrete_codegen_mlir/src/codegen.rs | 39 ++++++++++++++++++++- crates/concrete_codegen_mlir/src/errors.rs | 2 ++ crates/concrete_driver/tests/common.rs | 18 +++++++++- crates/concrete_driver/tests/examples.rs | 22 +++++++++++- crates/concrete_ir/src/lib.rs | 16 ++++++++- crates/concrete_ir/src/lowering.rs | 35 ++++++++++++++---- crates/concrete_parser/src/grammar.lalrpop | 20 ++++++++++- crates/concrete_parser/src/lib.rs | 11 ++++++ crates/concrete_parser/src/tokens.rs | 2 ++ examples/hello_world_hacky.con | 36 +++++++++++++++++++ 12 files changed, 198 insertions(+), 13 deletions(-) create mode 100644 examples/hello_world_hacky.con diff --git a/crates/concrete_ast/src/common.rs b/crates/concrete_ast/src/common.rs index 3de3ee3..5b8d48f 100644 --- a/crates/concrete_ast/src/common.rs +++ b/crates/concrete_ast/src/common.rs @@ -37,3 +37,10 @@ pub struct GenericParam { pub params: Vec, pub span: Span, } + +#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] +pub struct Attribute { + pub name: String, + pub value: Option, + pub span: Span, +} diff --git a/crates/concrete_ast/src/functions.rs b/crates/concrete_ast/src/functions.rs index 7ef8746..42c2e0d 100644 --- a/crates/concrete_ast/src/functions.rs +++ b/crates/concrete_ast/src/functions.rs @@ -1,5 +1,5 @@ use crate::{ - common::{DocString, GenericParam, Ident, Span}, + common::{Attribute, DocString, GenericParam, Ident, Span}, statements::Statement, types::TypeSpec, }; @@ -13,6 +13,7 @@ pub struct FunctionDecl { pub ret_type: Option, pub is_extern: bool, pub is_pub: bool, + pub attributes: Vec, pub span: Span, } diff --git a/crates/concrete_codegen_mlir/src/codegen.rs b/crates/concrete_codegen_mlir/src/codegen.rs index 1aa5e5d..2dd5fb8 100644 --- a/crates/concrete_codegen_mlir/src/codegen.rs +++ b/crates/concrete_codegen_mlir/src/codegen.rs @@ -613,10 +613,32 @@ fn compile_binop<'c: 'b, 'b>( let is_float = matches!(lhs_ty.kind, TyKind::Float(_)); let is_signed = matches!(lhs_ty.kind, TyKind::Int(_)); + let is_ptr = if let TyKind::Ptr(inner, _) = &lhs_ty.kind { + Some((*inner).clone()) + } else { + None + }; Ok(match op { BinOp::Add => { - let value = if is_float { + let value = if let Some(inner) = is_ptr { + let inner_ty = compile_type(ctx.module_ctx, &inner); + block + .append_operation( + ods::llvm::getelementptr( + ctx.context(), + pointer(ctx.context(), 0), + lhs, + &[rhs], + DenseI32ArrayAttribute::new(ctx.context(), &[i32::MIN]), + TypeAttribute::new(inner_ty), + location, + ) + .into(), + ) + .result(0)? + .into() + } else if is_float { block .append_operation(arith::addf(lhs, rhs, location)) .result(0)? @@ -630,6 +652,11 @@ fn compile_binop<'c: 'b, 'b>( (value, lhs_ty) } BinOp::Sub => { + if is_ptr.is_some() { + return Err(CodegenError::NotImplemented( + "substracting from a pointer is not yet implemented".to_string(), + )); + } let value = if is_float { block .append_operation(arith::subf(lhs, rhs, location)) @@ -644,6 +671,11 @@ fn compile_binop<'c: 'b, 'b>( (value, lhs_ty) } BinOp::Mul => { + if is_ptr.is_some() { + return Err(CodegenError::NotImplemented( + "multiplying a pointer is not yet implemented".to_string(), + )); + } let value = if is_float { block .append_operation(arith::mulf(lhs, rhs, location)) @@ -658,6 +690,11 @@ fn compile_binop<'c: 'b, 'b>( (value, lhs_ty) } BinOp::Div => { + if is_ptr.is_some() { + return Err(CodegenError::NotImplemented( + "dividing a pointer is not yet implemented".to_string(), + )); + } let value = if is_float { block .append_operation(arith::divf(lhs, rhs, location)) diff --git a/crates/concrete_codegen_mlir/src/errors.rs b/crates/concrete_codegen_mlir/src/errors.rs index 55d5092..1d90b88 100644 --- a/crates/concrete_codegen_mlir/src/errors.rs +++ b/crates/concrete_codegen_mlir/src/errors.rs @@ -8,4 +8,6 @@ pub enum CodegenError { LLVMCompileError(String), #[error("melior error: {0}")] MeliorError(#[from] melior::Error), + #[error("not yet implemented: {0}")] + NotImplemented(String), } diff --git a/crates/concrete_driver/tests/common.rs b/crates/concrete_driver/tests/common.rs index ba1e261..bdf2e5d 100644 --- a/crates/concrete_driver/tests/common.rs +++ b/crates/concrete_driver/tests/common.rs @@ -2,7 +2,7 @@ use std::{ borrow::Cow, fmt, path::{Path, PathBuf}, - process::Output, + process::{Output, Stdio}, }; use ariadne::Source; @@ -110,6 +110,7 @@ pub fn compile_program( pub fn run_program(program: &Path) -> Result { std::process::Command::new(program) + .stdout(Stdio::piped()) .spawn()? .wait_with_output() } @@ -122,3 +123,18 @@ pub fn compile_and_run(source: &str, name: &str, library: bool, optlevel: OptLev output.status.code().unwrap() } + +#[allow(unused)] // false positive +#[track_caller] +pub fn compile_and_run_output( + source: &str, + name: &str, + library: bool, + optlevel: OptLevel, +) -> String { + let result = compile_program(source, name, library, optlevel).expect("failed to compile"); + + let output = run_program(&result.binary_file).expect("failed to run"); + + std::str::from_utf8(&output.stdout).unwrap().to_string() +} diff --git a/crates/concrete_driver/tests/examples.rs b/crates/concrete_driver/tests/examples.rs index 455f58e..1377b7f 100644 --- a/crates/concrete_driver/tests/examples.rs +++ b/crates/concrete_driver/tests/examples.rs @@ -1,4 +1,4 @@ -use crate::common::compile_and_run; +use crate::common::{compile_and_run, compile_and_run_output}; use concrete_session::config::OptLevel; use test_case::test_case; @@ -39,3 +39,23 @@ fn example_tests(source: &str, name: &str, is_library: bool, status_code: i32) { compile_and_run(source, name, is_library, OptLevel::Aggressive) ); } + +#[test_case(include_str!("../../../examples/hello_world_hacky.con"), "hello_world_hacky", false, "Hello World\n" ; "hello_world_hacky.con")] +fn example_tests_with_output(source: &str, name: &str, is_library: bool, result: &str) { + assert_eq!( + result, + compile_and_run_output(source, name, is_library, OptLevel::None) + ); + assert_eq!( + result, + compile_and_run_output(source, name, is_library, OptLevel::Less) + ); + assert_eq!( + result, + compile_and_run_output(source, name, is_library, OptLevel::Default) + ); + assert_eq!( + result, + compile_and_run_output(source, name, is_library, OptLevel::Aggressive) + ); +} diff --git a/crates/concrete_ir/src/lib.rs b/crates/concrete_ir/src/lib.rs index 7be040f..464a532 100644 --- a/crates/concrete_ir/src/lib.rs +++ b/crates/concrete_ir/src/lib.rs @@ -68,6 +68,7 @@ pub struct FnBody { pub id: DefId, pub name: String, pub is_extern: bool, + pub is_intrinsic: Option, pub basic_blocks: Vec, pub locals: Vec, } @@ -397,7 +398,15 @@ impl fmt::Display for TyKind { FloatTy::F64 => write!(f, "f32"), }, TyKind::String => write!(f, "string"), - TyKind::Array(_, _) => todo!(), + TyKind::Array(inner, size) => { + let value = + if let ConstKind::Value(ValueTree::Leaf(ConstValue::U64(x))) = &size.data { + *x + } else { + unreachable!("const data for array sizes should always be u64") + }; + write!(f, "[{}; {:?}]", inner.kind, value) + } TyKind::Ref(inner, is_mut) => { let word = if let Mutability::Mut = is_mut { "mut" @@ -571,3 +580,8 @@ pub enum ConstValue { F32(f32), F64(f64), } + +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] +pub enum ConcreteIntrinsic { + // Todo: Add intrinsics here +} diff --git a/crates/concrete_ir/src/lowering.rs b/crates/concrete_ir/src/lowering.rs index 6cf620e..dd2104c 100644 --- a/crates/concrete_ir/src/lowering.rs +++ b/crates/concrete_ir/src/lowering.rs @@ -16,10 +16,10 @@ use concrete_ast::{ }; use crate::{ - AdtBody, BasicBlock, BinOp, ConstData, ConstKind, ConstValue, DefId, FloatTy, FnBody, IntTy, - Local, LocalKind, LogOp, Mutability, Operand, Place, PlaceElem, ProgramBody, Rvalue, Statement, - StatementKind, SwitchTargets, Terminator, TerminatorKind, Ty, TyKind, UintTy, ValueTree, - VariantDef, + AdtBody, BasicBlock, BinOp, ConcreteIntrinsic, ConstData, ConstKind, ConstValue, DefId, + FloatTy, FnBody, IntTy, Local, LocalKind, LogOp, Mutability, Operand, Place, PlaceElem, + ProgramBody, Rvalue, Statement, StatementKind, SwitchTargets, Terminator, TerminatorKind, Ty, + TyKind, UintTy, ValueTree, VariantDef, }; use self::errors::LoweringError; @@ -217,11 +217,16 @@ fn lower_func( func: &FunctionDef, module_id: DefId, ) -> Result { + let is_intrinsic: Option = None; + + // TODO: parse insintrics here. + let mut builder = FnBodyBuilder { body: FnBody { basic_blocks: Vec::new(), locals: Vec::new(), is_extern: func.decl.is_extern, + is_intrinsic, name: func.decl.name.name.clone(), id: { let body = ctx.body.modules.get(&module_id).unwrap(); @@ -350,11 +355,16 @@ fn lower_func_decl( func: &FunctionDecl, module_id: DefId, ) -> Result { + let is_intrinsic: Option = None; + + // TODO: parse insintrics here. + let builder = FnBodyBuilder { body: FnBody { basic_blocks: Vec::new(), locals: Vec::new(), is_extern: func.is_extern, + is_intrinsic, name: func.name.name.clone(), id: { let body = ctx.body.modules.get(&module_id).unwrap(); @@ -1236,14 +1246,22 @@ fn lower_binary_op( } else { lower_expression(builder, lhs, type_hint.clone())? }; + + // We must handle the special case where you can do ptr + offset. + let is_lhs_ptr = matches!(lhs_ty.kind, TyKind::Ptr(_, _)); + let (rhs, rhs_ty, rhs_span) = if type_hint.is_none() { let ty = find_expression_type(builder, rhs).unwrap_or(lhs_ty.clone()); - lower_expression(builder, rhs, Some(ty))? + lower_expression(builder, rhs, if is_lhs_ptr { None } else { Some(ty) })? } else { - lower_expression(builder, rhs, type_hint.clone())? + lower_expression( + builder, + rhs, + if is_lhs_ptr { None } else { type_hint.clone() }, + )? }; - if lhs_ty != rhs_ty { + if !is_lhs_ptr && lhs_ty != rhs_ty { return Err(LoweringError::UnexpectedType { span: rhs_span, found: rhs_ty, @@ -1409,6 +1427,9 @@ fn lower_value_expr( UintTy::U128 => ConstValue::U128(*value), }, TyKind::Bool => ConstValue::Bool(*value != 0), + TyKind::Ptr(ref _inner, _mutable) => { + ConstValue::I64((*value).try_into().expect("value out of range")) + } x => unreachable!("{:?}", x), })), }, diff --git a/crates/concrete_parser/src/grammar.lalrpop b/crates/concrete_parser/src/grammar.lalrpop index 3b40d96..7990ba8 100644 --- a/crates/concrete_parser/src/grammar.lalrpop +++ b/crates/concrete_parser/src/grammar.lalrpop @@ -53,6 +53,7 @@ extern { ":" => Token::Colon, "->" => Token::Arrow, "," => Token::Coma, + "#" => Token::Hashtag, "<" => Token::LessThanSign, ">" => Token::MoreThanSign, ">=" => Token::MoreThanEqSign, @@ -119,6 +120,14 @@ PlusSeparated: Vec = { } }; +List: Vec = { + => vec![<>], + > => { + s.push(n); + s + }, +} + // Requires the semicolon at end SemiColonSeparated: Vec = { ";" => vec![<>], @@ -291,13 +300,22 @@ pub(crate) Param: ast::functions::Param = { } } +pub(crate) Attribute: ast::common::Attribute = { + "#" "[" )?> "]" => ast::common::Attribute { + name, + value, + span: ast::common::Span::new(lo, hi), + } +} + pub(crate) FunctionDecl: ast::functions::FunctionDecl = { - + ?> "fn" "(" > ")" => ast::functions::FunctionDecl { doc_string: None, generic_params: generic_params.unwrap_or(vec![]), + attributes: attributes.unwrap_or(vec![]), name, params, ret_type, diff --git a/crates/concrete_parser/src/lib.rs b/crates/concrete_parser/src/lib.rs index 3108b09..5acfc43 100644 --- a/crates/concrete_parser/src/lib.rs +++ b/crates/concrete_parser/src/lib.rs @@ -285,6 +285,17 @@ mod ModuleName { return arr[1][0]; } +}"##; + let lexer = Lexer::new(source); + let parser = grammar::ProgramParser::new(); + parser.parse(lexer).unwrap(); + } + + #[test] + fn parse_intrinsic() { + let source = r##"mod MyMod { + #[intrinsic = "simdsomething"] + pub extern fn myintrinsic(); }"##; let lexer = Lexer::new(source); let parser = grammar::ProgramParser::new(); diff --git a/crates/concrete_parser/src/tokens.rs b/crates/concrete_parser/src/tokens.rs index 4b1326c..c9a884a 100644 --- a/crates/concrete_parser/src/tokens.rs +++ b/crates/concrete_parser/src/tokens.rs @@ -109,6 +109,8 @@ pub enum Token { Coma, #[token(".")] Dot, + #[token("#")] + Hashtag, #[token("<")] LessThanSign, #[token(">")] diff --git a/examples/hello_world_hacky.con b/examples/hello_world_hacky.con new file mode 100644 index 0000000..ed27057 --- /dev/null +++ b/examples/hello_world_hacky.con @@ -0,0 +1,36 @@ +mod HelloWorld { + pub extern fn malloc(size: u64) -> *mut u8; + pub extern fn puts(data: *mut u8) -> i32; + + fn main() -> i32 { + let origin: *mut u8 = malloc(12); + let mut p: *mut u8 = origin; + + *p = 'H'; + p = p + 1; + *p = 'e'; + p = p + 1; + *p = 'l'; + p = p + 1; + *p = 'l'; + p = p + 1; + *p = 'o'; + p = p + 1; + *p = ' '; + p = p + 1; + *p = 'W'; + p = p + 1; + *p = 'o'; + p = p + 1; + *p = 'r'; + p = p + 1; + *p = 'l'; + p = p + 1; + *p = 'd'; + p = p + 1; + *p = '\0'; + puts(origin); + + return 0; + } +} From 7d0e5a590caf209230695bf1c0d5fb5d51b8b1a2 Mon Sep 17 00:00:00 2001 From: Edgar Date: Thu, 9 May 2024 11:45:25 +0200 Subject: [PATCH 16/19] macos ci --- .github/workflows/ci.yml | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5468d33..57f8985 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,7 +73,26 @@ jobs: run: sudo apt-get install libc-dev build-essential - name: test run: make test - + test-macos: + name: test (macOS) + runs-on: macos-14 + env: + CARGO_TERM_COLOR: always + CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse + LIBRARY_PATH: /opt/homebrew/lib + MLIR_SYS_170_PREFIX: /opt/homebrew/opt/llvm@18 + LLVM_SYS_170_PREFIX: /opt/homebrew/opt/llvm@18 + TABLEGEN_170_PREFIX: /opt/homebrew/opt/llvm@18 + RUST_LOG: debug + steps: + - uses: actions/checkout@v4 + - name: Rustup toolchain install + uses: dtolnay/rust-toolchain@1.78.0 + - uses: homebrew/actions/setup-homebrew@master + - name: install llvm + run: brew install llvm@18 + - name: Run tests + run: make test coverage: name: coverage runs-on: ubuntu-latest From a984efc06b92bbc05aa722218d8e1f06b6eb138d Mon Sep 17 00:00:00 2001 From: Edgar Date: Thu, 9 May 2024 11:49:00 +0200 Subject: [PATCH 17/19] fix env --- .github/workflows/ci.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 57f8985..839997c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -78,11 +78,10 @@ jobs: runs-on: macos-14 env: CARGO_TERM_COLOR: always - CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse LIBRARY_PATH: /opt/homebrew/lib - MLIR_SYS_170_PREFIX: /opt/homebrew/opt/llvm@18 - LLVM_SYS_170_PREFIX: /opt/homebrew/opt/llvm@18 - TABLEGEN_170_PREFIX: /opt/homebrew/opt/llvm@18 + MLIR_SYS_180_PREFIX: /opt/homebrew/opt/llvm@18 + LLVM_SYS_180_PREFIX: /opt/homebrew/opt/llvm@18 + TABLEGEN_180_PREFIX: /opt/homebrew/opt/llvm@18 RUST_LOG: debug steps: - uses: actions/checkout@v4 From 3a25d5e22147a9eb3b6efe9dc27f756d2330ff73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Thu, 9 May 2024 16:35:04 -0300 Subject: [PATCH 18/19] Fix array example mut was missing --- examples/arrays.con | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/arrays.con b/examples/arrays.con index 52ade15..1e29aac 100644 --- a/examples/arrays.con +++ b/examples/arrays.con @@ -1,7 +1,7 @@ mod Example { fn main() -> i32 { let mut array: [i32; 4] = [1, 9, 3, 4]; - let nested_array: [[i32; 2]; 2] = [[1, 2], [9, 9]]; + let mut nested_array: [[i32; 2]; 2] = [[1, 2], [9, 9]]; array[1] = 2; nested_array[1] = [3, 4]; From 16fda9f5970654ccbc634733117fa98d547d5e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Thu, 9 May 2024 16:54:51 -0300 Subject: [PATCH 19/19] Use ascii code instead of char casting from char to u8 is not supported --- examples/hello_world_hacky.con | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/hello_world_hacky.con b/examples/hello_world_hacky.con index ed27057..132fe07 100644 --- a/examples/hello_world_hacky.con +++ b/examples/hello_world_hacky.con @@ -6,29 +6,29 @@ mod HelloWorld { let origin: *mut u8 = malloc(12); let mut p: *mut u8 = origin; - *p = 'H'; + *p = 72; p = p + 1; - *p = 'e'; + *p = 101; p = p + 1; - *p = 'l'; + *p = 108; p = p + 1; - *p = 'l'; + *p = 108; p = p + 1; - *p = 'o'; + *p = 111; p = p + 1; - *p = ' '; + *p = 32; p = p + 1; - *p = 'W'; + *p = 87; p = p + 1; - *p = 'o'; + *p = 111; p = p + 1; - *p = 'r'; + *p = 114; p = p + 1; - *p = 'l'; + *p = 108; p = p + 1; - *p = 'd'; + *p = 100; p = p + 1; - *p = '\0'; + *p = 0; puts(origin); return 0;