diff --git a/Cargo.lock b/Cargo.lock index eb7de34494..9edda60d9e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1526,23 +1526,23 @@ dependencies = [ [[package]] name = "inkwell" -version = "0.2.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f4fcb4a4fa0b8f7b4178e24e6317d6f8b95ab500d8e6e1bd4283b6860e369c1" +checksum = "40fb405537710d51f6bdbc8471365ddd4cd6d3a3c3ad6e0c8291691031ba94b2" dependencies = [ "either", "inkwell_internals", "libc", "llvm-sys", "once_cell", - "parking_lot", + "thiserror", ] [[package]] name = "inkwell_internals" -version = "0.8.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b185e7d068d6820411502efa14d8fbf010750485399402156b72dd2a548ef8e9" +checksum = "9dd28cfd4cfba665d47d31c08a6ba637eed16770abca2eccbbc3ca831fef1e44" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.36", @@ -2509,6 +2509,7 @@ dependencies = [ "rustc-hash", "serde", "serde_json", + "thiserror", "toml", ] diff --git a/Cargo.toml b/Cargo.toml index 9765dcf8d0..c8b1ef71ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,6 @@ plc_diagnostics = { path = "./compiler/plc_diagnostics" } plc_index = { path = "./compiler/plc_index" } section_mangler = { path = "./compiler/section_mangler" } logos = "0.12.0" -thiserror = "1.0" clap = { version = "3.0", features = ["derive"] } indexmap = "2.0" generational-arena = "0.2.8" @@ -35,6 +34,7 @@ lld_rs = "140.0.0" which = "4.2.5" log.workspace = true inkwell.workspace = true +thiserror.workspace = true chrono.workspace = true itertools.workspace = true anyhow.workspace = true @@ -79,7 +79,7 @@ members = [ default-members = [".", "compiler/plc_driver", "compiler/plc_xml"] [workspace.dependencies] -inkwell = { version = "0.2", features = ["llvm14-0"] } +inkwell = { version = "0.5", features = ["llvm14-0"] } encoding_rs = "0.8" encoding_rs_io = "0.1" log = "0.4" @@ -91,3 +91,4 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1" toml = "0.5" rustc-hash = "1.1.0" +thiserror = "1.0" diff --git a/compiler/plc_diagnostics/Cargo.toml b/compiler/plc_diagnostics/Cargo.toml index 4e30856a0f..988124d4ad 100644 --- a/compiler/plc_diagnostics/Cargo.toml +++ b/compiler/plc_diagnostics/Cargo.toml @@ -15,4 +15,5 @@ toml.workspace = true anyhow.workspace = true lazy_static.workspace = true log.workspace = true -rustc-hash.workspace = true \ No newline at end of file +rustc-hash.workspace = true +thiserror.workspace = true diff --git a/compiler/plc_diagnostics/src/diagnostics.rs b/compiler/plc_diagnostics/src/diagnostics.rs index 1aa1441df2..1cd1c473e1 100644 --- a/compiler/plc_diagnostics/src/diagnostics.rs +++ b/compiler/plc_diagnostics/src/diagnostics.rs @@ -27,7 +27,7 @@ pub enum Severity { /// The `Diagnostics` struct describes an issue encountered during compile time. /// The issue is defined by an `error_code` and had a defined `severity` /// Diagnostic severity can be overridden when being reported. -#[derive(Debug)] +#[derive(thiserror::Error, Debug)] pub struct Diagnostic { /// The Description of the error being reported. message: String, @@ -40,15 +40,10 @@ pub struct Diagnostic { /// Children of the current diagnostic sub_diagnostics: Vec, /// If the diagnostic is caused by an error, this field contains the original error + #[source] internal_error: Option, } -impl std::error::Error for Diagnostic { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - self.internal_error.as_ref().and_then(|it| it.source()) - } -} - impl From for Diagnostic { fn from(value: std::io::Error) -> Self { Diagnostic::new(value.to_string()).with_error_code("E002").with_internal_error(value.into()) diff --git a/compiler/plc_driver/src/lib.rs b/compiler/plc_driver/src/lib.rs index 24d171e3bd..2bd23e6f5b 100644 --- a/compiler/plc_driver/src/lib.rs +++ b/compiler/plc_driver/src/lib.rs @@ -281,7 +281,10 @@ pub fn compile_with_options(compile_options: CompilationContext) -> Result<()> { // 5 : Codegen if !compile_parameters.is_check() { let res = generate(&compile_options, &link_options, compile_parameters.target, annotated_project) - .map_err(|err| Diagnostic::codegen_error(err.get_message(), err.get_location())); + .map_err(|err| { + Diagnostic::codegen_error(err.get_message(), err.get_location()) + .with_internal_error(err.into()) + }); if let Err(res) = res { diagnostician.handle(&[res]); return Err(Diagnostic::new("Compilation aborted due to previous errors") diff --git a/src/builtins.rs b/src/builtins.rs index 7b449f11bd..2b19cb5380 100644 --- a/src/builtins.rs +++ b/src/builtins.rs @@ -17,6 +17,7 @@ use plc_source::source_location::{SourceLocation, SourceLocationFactory}; use rustc_hash::FxHashMap; use crate::{ + codegen::diagnostics::CodegenDiagnostic, codegen::generators::expression_generator::{self, ExpressionCodeGenerator, ExpressionValue}, index::Index, lexer, parser, @@ -50,7 +51,7 @@ lazy_static! { if let [reference] = params { generator .generate_lvalue(reference) - .map(|it| ExpressionValue::RValue(it.as_basic_value_enum())) + .and_then(|it| Ok(ExpressionValue::RValue(it.as_basic_value_enum()))) } else { Err(Diagnostic::codegen_error( "Expected exactly one parameter for REF", @@ -138,7 +139,7 @@ lazy_static! { .and_then(|it| generator.get_type_hint_info_for(it))?; //Create a temp var let result_type = generator.llvm_index.get_associated_type(type_hint.get_name())?; - let result_var = generator.llvm.create_local_variable("", &result_type); + let result_var = generator.llvm.create_local_variable("", &result_type)?; let k = generator.generate_expression(k)?; let mut blocks = vec![]; @@ -152,12 +153,12 @@ lazy_static! { let value = context.i32_type().const_int(index as u64, false); builder.position_at_end(block); generator.generate_store(result_var, type_hint.get_type_information(), it)?; - builder.build_unconditional_branch(continue_block); + builder.build_unconditional_branch(continue_block).map_err(CodegenDiagnostic::from)?; Ok((value,block)) }).collect::,_>>()?; builder.position_at_end(insert_block); - builder.build_switch(k.into_int_value(), continue_block, &cases); + builder.build_switch(k.into_int_value(), continue_block, &cases).map_err(CodegenDiagnostic::from)?; builder.position_at_end(continue_block); Ok(ExpressionValue::LValue(result_var)) } else { @@ -183,7 +184,7 @@ lazy_static! { code: |generator, params, location| { if let &[g,in0,in1] = params { // evaluate the parameters - let cond = expression_generator::to_i1(generator.generate_expression(g)?.into_int_value(), &generator.llvm.builder); + let cond = expression_generator::to_i1(generator.generate_expression(g)?.into_int_value(), &generator.llvm.builder)?; // for aggregate types we need a ptr to perform memcpy // use generate_expression_value(), this will return a gep // generate_expression() would load the ptr @@ -198,7 +199,7 @@ lazy_static! { generator.generate_expression(in1)? }; // generate an llvm select instruction - let sel = generator.llvm.builder.build_select(cond, in1, in0, ""); + let sel = generator.llvm.builder.build_select(cond, in1, in0, "").map_err(CodegenDiagnostic::from)?; if sel.is_pointer_value(){ Ok(ExpressionValue::LValue(sel.into_pointer_value())) @@ -890,26 +891,35 @@ fn generate_variable_length_array_bound_function<'ink>( todo!() }; // this operation mirrors the offset calculation of literal ints, but at runtime - let offset = builder.build_int_mul( - llvm.i32_type().const_int(2, false), - builder.build_int_sub( - expression_value.into_int_value(), - llvm.i32_type().const_int(1, false), + let offset = builder + .build_int_mul( + llvm.i32_type().const_int(2, false), + builder + .build_int_sub( + expression_value.into_int_value(), + llvm.i32_type().const_int(1, false), + "", + ) + .map_err(CodegenDiagnostic::from)?, "", - ), - "", - ); + ) + .map_err(CodegenDiagnostic::from)?; if !is_lower { - builder.build_int_add(offset, llvm.i32_type().const_int(1, false), "") + builder + .build_int_add(offset, llvm.i32_type().const_int(1, false), "") + .map_err(CodegenDiagnostic::from)? } else { offset } } }; - let gep_bound = - unsafe { llvm.builder.build_in_bounds_gep(dim, &[llvm.i32_type().const_zero(), accessor], "") }; - let bound = llvm.builder.build_load(gep_bound, ""); + let gep_bound = unsafe { + llvm.builder + .build_in_bounds_gep(dim, &[llvm.i32_type().const_zero(), accessor], "") + .map_err(CodegenDiagnostic::from)? + }; + let bound = llvm.builder.build_load(gep_bound, "").map_err(CodegenDiagnostic::from)?; Ok(ExpressionValue::RValue(bound)) } diff --git a/src/codegen.rs b/src/codegen.rs index 75045f6bd8..24acae6736 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -30,7 +30,7 @@ use inkwell::{ context::Context, execution_engine::{ExecutionEngine, JitFunction}, memory_buffer::MemoryBuffer, - types::BasicType, + types::{BasicType, FunctionType}, values::BasicValue, AddressSpace, }; @@ -45,6 +45,7 @@ use plc_diagnostics::diagnostics::Diagnostic; use plc_source::source_location::SourceLocation; mod debug; +pub(crate) mod diagnostics; pub(crate) mod generators; mod llvm_index; mod llvm_typesystem; @@ -116,6 +117,14 @@ impl<'ink> CodeGen<'ink> { ) -> Result, Diagnostic> { let llvm = Llvm::new(context, context.create_builder()); let mut index = LlvmTypedIndex::default(); + //Create an init function and position builder there + //TODO: This will conflict with the planned init function + let init_module = llvm.context.create_module("Init"); + let void_type = llvm.context.void_type(); + let fn_type = void_type.fn_type(&[], false); + let init_func = init_module.add_function("__init", fn_type, None); + let basic_block = llvm.context.append_basic_block(init_func, "entry"); + llvm.builder.position_at_end(basic_block); //Generate types index, and any global variables associated with them. let llvm_type_index = data_type_generator::generate_data_types( &llvm, @@ -136,6 +145,7 @@ impl<'ink> CodeGen<'ink> { &self.online_change, ); + //Create a block for the inittializers //Generate global variables let llvm_gv_index = variable_generator.generate_global_variables(dependencies, &self.module_location)?; diff --git a/src/codegen/diagnostics.rs b/src/codegen/diagnostics.rs new file mode 100644 index 0000000000..d5078cdae6 --- /dev/null +++ b/src/codegen/diagnostics.rs @@ -0,0 +1,38 @@ +use std::{backtrace, fmt::Display}; + +use inkwell::builder::BuilderError; +use plc_diagnostics::diagnostics::Diagnostic; +use plc_source::source_location::SourceLocation; +use thiserror::Error; + +#[derive(Error, Debug)] +pub struct CodegenDiagnostic { + message: String, + source: BuilderError, + location: SourceLocation, +} + +impl Display for CodegenDiagnostic { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Codegen error: {}. Source: {} at {}", &self.message, &self.source, &self.location) + } +} + +impl From for CodegenDiagnostic { + fn from(source: BuilderError) -> Self { + // println!("Backtrace: {} ", backtrace::Backtrace::force_capture()); + CodegenDiagnostic { message: source.to_string(), source, location: SourceLocation::undefined() } + } +} + +impl CodegenDiagnostic { + pub(crate) fn with_location(self, location: SourceLocation) -> CodegenDiagnostic { + CodegenDiagnostic { location, ..self } + } +} + +impl From for Diagnostic { + fn from(value: CodegenDiagnostic) -> Self { + Diagnostic::codegen_error(&value.message, value.location.clone()).with_internal_error(value.into()) + } +} diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index 8f5942e2a1..7e7fefd52e 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -26,17 +26,18 @@ use plc_util::convention::qualified_name; use crate::{ codegen::{ debug::{Debug, DebugBuilderEnum}, + diagnostics::CodegenDiagnostic, llvm_index::LlvmTypedIndex, llvm_typesystem::{cast_if_needed, get_llvm_int_type}, + CodegenContext, }, index::{ const_expressions::ConstId, ArgumentType, ImplementationIndexEntry, Index, PouIndexEntry, VariableIndexEntry, VariableType, }, resolver::{AnnotationMap, AstAnnotations, StatementAnnotation}, - typesystem, typesystem::{ - is_same_type_class, DataType, DataTypeInformation, DataTypeInformationProvider, Dimension, + self, is_same_type_class, DataType, DataTypeInformation, DataTypeInformationProvider, Dimension, StringEncoding, VarArgs, DINT_TYPE, INT_SIZE, INT_TYPE, LINT_TYPE, }, }; @@ -96,10 +97,14 @@ impl<'ink> ExpressionValue<'ink> { /// returns the given expression value as an r-value which means that it will load /// the pointer, if this is an l_value - pub fn as_r_value(&self, llvm: &Llvm<'ink>, load_name: Option) -> BasicValueEnum<'ink> { + pub fn as_r_value( + &self, + llvm: &Llvm<'ink>, + load_name: Option, + ) -> Result, CodegenDiagnostic> { match self { ExpressionValue::LValue(it) => llvm.load_pointer(it, load_name.as_deref().unwrap_or("")), - ExpressionValue::RValue(it) => it.to_owned(), + ExpressionValue::RValue(it) => Ok(it.to_owned()), } } } @@ -177,7 +182,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let v = self .generate_expression_value(expression)? - .as_r_value(self.llvm, self.get_load_name(expression)) + .as_r_value(self.llvm, self.get_load_name(expression))? .as_basic_value_enum(); let Some(target_type) = self.annotations.get_type_hint(expression, self.index) else { @@ -185,7 +190,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { return Ok(v); }; let actual_type = self.annotations.get_type_or_void(expression, self.index); - Ok(cast_if_needed!(self, target_type, actual_type, v, self.annotations.get(expression))) + Ok(cast_if_needed!(self, target_type, actual_type, v, self.annotations.get(expression))?) } fn register_debug_location(&self, statement: &AstNode) { @@ -222,11 +227,11 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { self.generate_reference_expression(&data.access, data.base.as_deref(), expression)?; let val = match res { ExpressionValue::LValue(val) => { - ExpressionValue::LValue(self.auto_deref_if_necessary(val, expression)) + ExpressionValue::LValue(self.auto_deref_if_necessary(val, expression)?) } ExpressionValue::RValue(val) => { let val = if val.is_pointer_value() { - self.auto_deref_if_necessary(val.into_pointer_value(), expression) + self.auto_deref_if_necessary(val.into_pointer_value(), expression)? .as_basic_value_enum() } else { val @@ -310,7 +315,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { &[self.llvm.context.i32_type().const_int(idx, false)], "", )?; - Ok(self.llvm.load_pointer(&ptr, "").into_pointer_value()) + Ok(self.llvm.load_pointer(&ptr, "")?.into_pointer_value()) }) .transpose() } @@ -339,11 +344,11 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { &[self.llvm.context.i32_type().const_int(idx, false)], "", )?; - ptr = self.llvm.load_pointer(&ptr, "").into_pointer_value(); + ptr = self.llvm.load_pointer(&ptr, "")?.into_pointer_value(); let callable = CallableValue::try_from(ptr) .map_err(|_| Diagnostic::new("Pointer was not a function pointer"))?; - Ok(self.llvm.builder.build_call(callable, args, "call")) + Ok(self.llvm.builder.build_call(callable, args, "call").map_err(CodegenDiagnostic::from)?) }) .transpose() } @@ -372,13 +377,13 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { operator, self.generate_expression(left)?, self.generate_expression(right)?, - )) + )?) } else if ltype.is_float() && rtype.is_float() { Ok(self.create_llvm_float_binary_expression( operator, self.generate_expression(left)?, self.generate_expression(right)?, - )) + )?) } else if (ltype.is_pointer() && rtype.is_int()) || (ltype.is_int() && rtype.is_pointer()) || (ltype.is_pointer() && rtype.is_pointer()) @@ -404,14 +409,18 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { //The reason is that llvm expects a shift operation to happen on the same type, and //this is what the direct access will eventually end up in. let reference = - cast_if_needed!(self, target_type, self.get_type_hint_for(index)?, reference, None) + cast_if_needed!(self, target_type, self.get_type_hint_for(index)?, reference, None)? .into_int_value(); //Multiply by the bitwitdh if access.get_bit_width() > 1 { let bitwidth = reference.get_type().const_int(access.get_bit_width(), access_type.is_signed_int()); - Ok(self.llvm.builder.build_int_mul(reference, bitwidth, "")) + Ok(self + .llvm + .builder + .build_int_mul(reference, bitwidth, "") + .map_err(CodegenDiagnostic::from)?) } else { Ok(reference) } @@ -431,17 +440,19 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let value = match unary_operator { Operator::Not => { let operator = self.generate_expression(expression)?.into_int_value(); - let operator = if self - .get_type_hint_for(expression) - .map(|it| it.get_type_information().is_bool()) - .unwrap_or_default() - { - to_i1(operator, &self.llvm.builder) - } else { - operator - }; + let operator = + if self.get_type_hint_for(expression).map(|it| it.get_type_information().is_bool())? { + to_i1(operator, &self.llvm.builder)? + } else { + operator + }; - Ok(self.llvm.builder.build_not(operator, "tmpVar").as_basic_value_enum()) + Ok(self + .llvm + .builder + .build_not(operator, "tmpVar") + .map_err(CodegenDiagnostic::from)? + .as_basic_value_enum()) } Operator::Minus => { let generated_exp = self.generate_expression(expression)?; @@ -450,12 +461,14 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { .llvm .builder .build_float_neg(generated_exp.into_float_value(), "tmpVar") + .map_err(CodegenDiagnostic::from)? .as_basic_value_enum()) } else if generated_exp.is_int_value() { Ok(self .llvm .builder .build_int_neg(generated_exp.into_int_value(), "tmpVar") + .map_err(CodegenDiagnostic::from)? .as_basic_value_enum()) } else { Err(Diagnostic::codegen_error( @@ -534,7 +547,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { if data_type.is_aggregate_type() { // this is a function call with a return variable fed as an out-pointer let llvm_type = self.llvm_index.get_associated_type(data_type.get_name())?; - let out_pointer = self.llvm.create_local_variable("", &llvm_type); + let out_pointer = self.llvm.create_local_variable("", &llvm_type)?; // add the out-ptr as its first parameter arguments_list.insert(0, out_pointer.into()); Some(out_pointer) @@ -553,12 +566,14 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { .get_qualified_name(operator) .expect("Shouldn't have got this far without a name for the function"); let function_type = function.get_type(); - let call = self - .generate_got_call(qualified_name, &function_type, &arguments_list)? - .unwrap_or_else(|| self.llvm.builder.build_call(function, &arguments_list, "call")); - + let call = self.generate_got_call(qualified_name, &function_type, &arguments_list)?.map_or_else( + || // if the target is a function, declare the struct locally // assign all parameters into the struct values + self.llvm.builder.build_call(function, &arguments_list, "call") + .map_err(CodegenDiagnostic::from), + Ok, + )?; // so grab either: // - the out-pointer if we generated one in by_ref_func_out @@ -688,7 +703,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { .with_error_code("E055") .with_location(element.get_location())) }?; - index = self.llvm.builder.build_int_add(index, rhs_next, ""); + index = self.llvm.builder.build_int_add(index, rhs_next, "").map_err(CodegenDiagnostic::from)?; } //Build mask for the index @@ -697,22 +712,32 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let ones = rhs_type.const_all_ones(); //Extend the mask to the target type - let extended_mask = self.llvm.builder.build_int_z_extend(ones, left_value.get_type(), "ext"); + let extended_mask = self + .llvm + .builder + .build_int_z_extend(ones, left_value.get_type(), "ext") + .map_err(CodegenDiagnostic::from)?; //Position the ones in their correct locations - let shifted_mask = self.llvm.builder.build_left_shift(extended_mask, index, "shift"); + let shifted_mask = self + .llvm + .builder + .build_left_shift(extended_mask, index, "shift") + .map_err(CodegenDiagnostic::from)?; //Invert the mask - let mask = self.llvm.builder.build_not(shifted_mask, "invert"); + let mask = self.llvm.builder.build_not(shifted_mask, "invert").map_err(CodegenDiagnostic::from)?; //And the result with the mask to erase the set bits at the target location - let and_value = self.llvm.builder.build_and(left_value, mask, "erase"); + let and_value = + self.llvm.builder.build_and(left_value, mask, "erase").map_err(CodegenDiagnostic::from)?; //Cast the right side to the left side type - let lhs = cast_if_needed!(self, type_left, type_right, right_expr, None).into_int_value(); + let lhs = cast_if_needed!(self, type_left, type_right, right_expr, None)?.into_int_value(); //Shift left by the direct access - let value = self.llvm.builder.build_left_shift(lhs, index, "value"); + let value = + self.llvm.builder.build_left_shift(lhs, index, "value").map_err(CodegenDiagnostic::from)?; //OR the result and store it in the left side - let or_value = self.llvm.builder.build_or(and_value, value, "or"); - self.llvm.builder.build_store(left_pointer, or_value); + let or_value = self.llvm.builder.build_or(and_value, value, "or").map_err(CodegenDiagnostic::from)?; + self.llvm.builder.build_store(left_pointer, or_value).map_err(CodegenDiagnostic::from)?; Ok(()) } @@ -724,10 +749,11 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { right_pointer: PointerValue, right_type: &DataType, ) -> Result<(), Diagnostic> { - let left_value = self.llvm.builder.build_load(left_pointer, "").into_int_value(); + let left_value = + self.llvm.builder.build_load(left_pointer, "").map_err(CodegenDiagnostic::from)?.into_int_value(); //Generate an expression for the right size - let right = self.llvm.builder.build_load(right_pointer, ""); + let right = self.llvm.builder.build_load(right_pointer, "").map_err(CodegenDiagnostic::from)?; self.generate_assignment_with_direct_access( left_statement, left_value, @@ -808,8 +834,8 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { parameter.source_location.clone(), )?; } else { - let output_value = builder.build_load(output, ""); - builder.build_store(assigned_output, output_value); + let output_value = builder.build_load(output, "").map_err(CodegenDiagnostic::from)?; + builder.build_store(assigned_output, output_value).map_err(CodegenDiagnostic::from)?; } } }; @@ -1003,13 +1029,13 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { .find_associated_type(type_name) .ok_or_else(|| Diagnostic::unknown_type(type_name, argument.get_location()))?; - let ptr_value = self.llvm.builder.build_alloca(v_type, ""); + let ptr_value = self.llvm.builder.build_alloca(v_type, "").map_err(CodegenDiagnostic::from)?; if let Some(p) = declared_parameter { if let Some(initial_value) = self.get_initial_value(&p.initial_value, &self.get_parameter_type(p)) { let value = self.generate_expression(initial_value)?; - self.llvm.builder.build_store(ptr_value, value); + self.llvm.builder.build_store(ptr_value, value).map_err(CodegenDiagnostic::from)?; } } @@ -1024,8 +1050,12 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { ExpressionValue::RValue(_v) => { // Passed a literal to a byref parameter? let value = self.generate_expression(argument)?; - let argument = self.llvm.builder.build_alloca(value.get_type(), ""); - self.llvm.builder.build_store(argument, value); + let argument = self + .llvm + .builder + .build_alloca(value.get_type(), "") + .map_err(CodegenDiagnostic::from)?; + self.llvm.builder.build_store(argument, value).map_err(CodegenDiagnostic::from)?; argument } } @@ -1047,32 +1077,36 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { actual_type, value.into(), self.annotations.get(argument) - )); + )?); }; // From https://llvm.org/docs/LangRef.html#bitcast-to-instruction: The ‘bitcast’ instruction takes // a value to cast, which must be a **non-aggregate** first class value [...] if !actual_type_info.is_aggregate() && actual_type_info != target_type_info { - return Ok(self.llvm.builder.build_bitcast( - value, - self.llvm_index.get_associated_type(hint.get_name())?, - "", - )); + return Ok(self + .llvm + .builder + .build_bit_cast(value, self.llvm_index.get_associated_type(hint.get_name())?, "") + .map_err(CodegenDiagnostic::from)?); } } // ...check if we can bitcast an array to a pointer, i.e. `[81 x i8]*` should be passed as a `i8*` if value.get_type().get_element_type().is_array_type() { - let res = self.llvm.builder.build_bitcast( - value, - value - .get_type() - .get_element_type() - .into_array_type() - .get_element_type() - .ptr_type(AddressSpace::from(ADDRESS_SPACE_GENERIC)), - "", - ); + let res = self + .llvm + .builder + .build_bit_cast( + value, + value + .get_type() + .get_element_type() + .into_array_type() + .get_element_type() + .ptr_type(AddressSpace::from(ADDRESS_SPACE_GENERIC)), + "", + ) + .map_err(CodegenDiagnostic::from)?; return Ok(res.into_pointer_value().into()); } @@ -1130,7 +1164,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let size_param = self.llvm.i32_type().const_int(size as u64, true); let arr = ty.array_type(size as u32); - let arr_storage = self.llvm.builder.build_alloca(arr, ""); + let arr_storage = self.llvm.builder.build_alloca(arr, "").map_err(CodegenDiagnostic::from)?; for (i, ele) in generated_params.iter().enumerate() { let ele_ptr = self.llvm.load_array_element( arr_storage, @@ -1140,15 +1174,15 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { ], "", )?; - self.llvm.builder.build_store(ele_ptr, *ele); + self.llvm.builder.build_store(ele_ptr, *ele).map_err(CodegenDiagnostic::from)?; } // bitcast the array to pointer so it matches the declared function signature - let arr_storage = self.llvm.builder.build_bitcast( - arr_storage, - ty.ptr_type(AddressSpace::from(ADDRESS_SPACE_GENERIC)), - "", - ); + let arr_storage = self + .llvm + .builder + .build_bit_cast(arr_storage, ty.ptr_type(AddressSpace::from(ADDRESS_SPACE_GENERIC)), "") + .map_err(CodegenDiagnostic::from)?; Ok(vec![size_param.into(), arr_storage]) } else { @@ -1180,7 +1214,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { ) })?; - Ok(self.llvm.create_local_variable(&instance_name, &function_type)) + Ok(self.llvm.create_local_variable(&instance_name, &function_type)?) } /// generates the assignments of a pou-call's parameters @@ -1239,12 +1273,17 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { { self.generate_expression(initial_value) } else { - let ptr_value = self.llvm.builder.build_alloca(parameter_type, ""); - Ok(self.llvm.load_pointer(&ptr_value, "")) + let ptr_value = self + .llvm + .builder + .build_alloca(parameter_type, "") + .map_err(CodegenDiagnostic::from)?; + Ok(self.llvm.load_pointer(&ptr_value, "")?) } } _ => { - let ptr_value = self.llvm.builder.build_alloca(parameter_type, ""); + let ptr_value = + self.llvm.builder.build_alloca(parameter_type, "").map_err(CodegenDiagnostic::from)?; // if default value is given for an output // we need to initialize the pointer value before returning @@ -1252,7 +1291,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { self.get_initial_value(¶meter.initial_value, ¶meter_type_name) { let value = self.generate_expression(initial_value)?; - self.llvm.builder.build_store(ptr_value, value); + self.llvm.builder.build_store(ptr_value, value).map_err(CodegenDiagnostic::from)?; } Ok(ptr_value.as_basic_value_enum()) } @@ -1333,11 +1372,14 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { self.llvm_index.find_associated_type(inner_type_name).ok_or_else(|| { Diagnostic::unknown_type(parameter.get_name(), expression.get_location()) })?; - builder.build_alloca(temp_type, "empty_varinout").as_basic_value_enum() + builder + .build_alloca(temp_type, "empty_varinout") + .map_err(CodegenDiagnostic::from)? + .as_basic_value_enum() } else { self.generate_lvalue(expression)?.as_basic_value_enum() }; - builder.build_store(pointer_to_param, generated_exp); + builder.build_store(pointer_to_param, generated_exp).map_err(CodegenDiagnostic::from)?; } else { self.generate_store(pointer_to_param, parameter, expression)?; }; @@ -1464,25 +1506,25 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { } } - fn deref(&self, accessor_ptr: PointerValue<'ink>) -> PointerValue<'ink> { - self.llvm.load_pointer(&accessor_ptr, "deref").into_pointer_value() + fn deref(&self, accessor_ptr: PointerValue<'ink>) -> Result, CodegenDiagnostic> { + Ok(self.llvm.load_pointer(&accessor_ptr, "deref")?.into_pointer_value()) } - pub fn ptr_as_value(&self, ptr: PointerValue<'ink>) -> BasicValueEnum<'ink> { + pub fn ptr_as_value(&self, ptr: PointerValue<'ink>) -> Result, CodegenDiagnostic> { let int_type = self.llvm.context.i64_type(); - if ptr.is_const() { + Ok(if ptr.is_const() { ptr.const_to_int(int_type) } else { - self.llvm.builder.build_ptr_to_int(ptr, int_type, "") + self.llvm.builder.build_ptr_to_int(ptr, int_type, "")? } - .as_basic_value_enum() + .as_basic_value_enum()) } - pub fn int_neg(&self, value: IntValue<'ink>) -> IntValue<'ink> { + pub fn int_neg(&self, value: IntValue<'ink>) -> Result, CodegenDiagnostic> { if value.is_const() { - value.const_neg() + Ok(value.const_neg()) } else { - self.llvm.builder.build_int_neg(value, "") + Ok(self.llvm.builder.build_int_neg(value, "")?) } } @@ -1495,11 +1537,11 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { &self, accessor_ptr: PointerValue<'ink>, statement: &AstNode, - ) -> PointerValue<'ink> { + ) -> Result, CodegenDiagnostic> { if self.annotations.get(statement).is_some_and(|opt| opt.is_auto_deref()) { - self.deref(accessor_ptr) + Ok(self.deref(accessor_ptr)?) } else { - accessor_ptr + Ok(accessor_ptr) } } @@ -1523,11 +1565,14 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let result = if start_offset != 0 { let access_int_value = access_value.into_int_value(); let access_int_type = access_int_value.get_type(); - self.llvm.builder.build_int_sub( - access_int_value, - access_int_type.const_int(start_offset as u64, true), //TODO error handling for cast - "", - ) + self.llvm + .builder + .build_int_sub( + access_int_value, + access_int_type.const_int(start_offset as u64, true), //TODO error handling for cast + "", + ) + .map_err(CodegenDiagnostic::from)? } else { access_value.into_int_value() }; @@ -1538,7 +1583,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { self.get_type_hint_for(access_expression)?, result.as_basic_value_enum(), None - )) + )?) } /// generates a gep statement for a array-reference with an optional qualifier @@ -1617,11 +1662,15 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { &Operator::Multiplication, current_portion_value, v, - ); + )?; // take the sum of the mulitlication and the previous accumulated_value // this now becomes the new accumulated value - self.create_llvm_int_binary_expression(&Operator::Plus, m_v, last_v) - }) + Ok(self.create_llvm_int_binary_expression( + &Operator::Plus, + m_v, + last_v, + )?) + })? }); (result, 0 /* the 0 will be ignored */) }, @@ -1698,7 +1747,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { if let (Some(ptr), Some(mut index), Some(name)) = (ptr, index, name) { // if operator is minus we need to negate the index if let Operator::Minus = operator { - index = self.int_neg(index); + index = self.int_neg(index)?; } Ok(self.llvm.load_array_element(ptr, &[index], name.as_str())?.as_basic_value_enum()) @@ -1714,60 +1763,66 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { .builder .build_int_compare( IntPredicate::EQ, - self.convert_to_int_value_if_pointer(left_expr), - self.convert_to_int_value_if_pointer(right_expr), + self.convert_to_int_value_if_pointer(left_expr)?, + self.convert_to_int_value_if_pointer(right_expr)?, "tmpVar", ) + .map_err(Into::::into)? .as_basic_value_enum()), Operator::NotEqual => Ok(self .llvm .builder .build_int_compare( IntPredicate::NE, - self.convert_to_int_value_if_pointer(left_expr), - self.convert_to_int_value_if_pointer(right_expr), + self.convert_to_int_value_if_pointer(left_expr)?, + self.convert_to_int_value_if_pointer(right_expr)?, "tmpVar", ) + .map_err(Into::::into)? .as_basic_value_enum()), Operator::Less => Ok(self .llvm .builder .build_int_compare( IntPredicate::SLT, - self.convert_to_int_value_if_pointer(left_expr), - self.convert_to_int_value_if_pointer(right_expr), + self.convert_to_int_value_if_pointer(left_expr)?, + self.convert_to_int_value_if_pointer(right_expr)?, "tmpVar", ) + .map_err(Into::::into)? .as_basic_value_enum()), Operator::Greater => Ok(self .llvm .builder .build_int_compare( IntPredicate::SGT, - self.convert_to_int_value_if_pointer(left_expr), - self.convert_to_int_value_if_pointer(right_expr), + self.convert_to_int_value_if_pointer(left_expr)?, + self.convert_to_int_value_if_pointer(right_expr)?, "tmpVar", ) + .map_err(Into::::into)? .as_basic_value_enum()), Operator::LessOrEqual => Ok(self .llvm .builder .build_int_compare( IntPredicate::SLE, - self.convert_to_int_value_if_pointer(left_expr), - self.convert_to_int_value_if_pointer(right_expr), + self.convert_to_int_value_if_pointer(left_expr)?, + self.convert_to_int_value_if_pointer(right_expr)?, "tmpVar", ) + .map_err(Into::::into)? .as_basic_value_enum()), Operator::GreaterOrEqual => Ok(self .llvm .builder .build_int_compare( IntPredicate::SGE, - self.convert_to_int_value_if_pointer(left_expr), - self.convert_to_int_value_if_pointer(right_expr), + self.convert_to_int_value_if_pointer(left_expr)?, + self.convert_to_int_value_if_pointer(right_expr)?, "tmpVar", ) + .map_err(Into::::into)? .as_basic_value_enum()), _ => Err(Diagnostic::codegen_error( format!("Operator '{operator}' unimplemented for pointers").as_str(), @@ -1780,10 +1835,13 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { /// if the given `value` is a pointer value, it converts the pointer into an int_value to access the pointer's /// address, if the given `value` is already an IntValue it is returned as is - pub fn convert_to_int_value_if_pointer(&self, value: BasicValueEnum<'ink>) -> IntValue<'ink> { + pub fn convert_to_int_value_if_pointer( + &self, + value: BasicValueEnum<'ink>, + ) -> Result, CodegenDiagnostic> { match value { - BasicValueEnum::PointerValue(v) => self.ptr_as_value(v).into_int_value(), - BasicValueEnum::IntValue(v) => v, + BasicValueEnum::PointerValue(v) => Ok(self.ptr_as_value(v)?.into_int_value()), + BasicValueEnum::IntValue(v) => Ok(v), _ => unimplemented!(), } } @@ -1799,7 +1857,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { operator: &Operator, left_value: BasicValueEnum<'ink>, right_value: BasicValueEnum<'ink>, - ) -> BasicValueEnum<'ink> { + ) -> Result, CodegenDiagnostic> { let int_lvalue = left_value.into_int_value(); let int_rvalue = right_value.into_int_value(); @@ -1837,7 +1895,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { Operator::Or => self.llvm.builder.build_or(int_lvalue, int_rvalue, "tmpVar"), _ => unimplemented!(), }; - value.into() + Ok(value?.into()) } /// generates the result of a float binary-expression (+, -, *, /, %, ==) @@ -1851,57 +1909,59 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { operator: &Operator, lvalue: BasicValueEnum<'ink>, rvalue: BasicValueEnum<'ink>, - ) -> BasicValueEnum<'ink> { + ) -> Result, CodegenDiagnostic> { let float_lvalue = lvalue.into_float_value(); let float_rvalue = rvalue.into_float_value(); let value = match operator { - Operator::Plus => self.llvm.builder.build_float_add(float_lvalue, float_rvalue, "tmpVar").into(), - Operator::Minus => self.llvm.builder.build_float_sub(float_lvalue, float_rvalue, "tmpVar").into(), + Operator::Plus => self.llvm.builder.build_float_add(float_lvalue, float_rvalue, "tmpVar")?.into(), + Operator::Minus => { + self.llvm.builder.build_float_sub(float_lvalue, float_rvalue, "tmpVar")?.into() + } Operator::Multiplication => { - self.llvm.builder.build_float_mul(float_lvalue, float_rvalue, "tmpVar").into() + self.llvm.builder.build_float_mul(float_lvalue, float_rvalue, "tmpVar")?.into() } Operator::Division => { - self.llvm.builder.build_float_div(float_lvalue, float_rvalue, "tmpVar").into() + self.llvm.builder.build_float_div(float_lvalue, float_rvalue, "tmpVar")?.into() } Operator::Modulo => { - self.llvm.builder.build_float_rem(float_lvalue, float_rvalue, "tmpVar").into() + self.llvm.builder.build_float_rem(float_lvalue, float_rvalue, "tmpVar")?.into() } Operator::Equal => self .llvm .builder - .build_float_compare(FloatPredicate::OEQ, float_lvalue, float_rvalue, "tmpVar") + .build_float_compare(FloatPredicate::OEQ, float_lvalue, float_rvalue, "tmpVar")? .into(), Operator::NotEqual => self .llvm .builder - .build_float_compare(FloatPredicate::ONE, float_lvalue, float_rvalue, "tmpVar") + .build_float_compare(FloatPredicate::ONE, float_lvalue, float_rvalue, "tmpVar")? .into(), Operator::Less => self .llvm .builder - .build_float_compare(FloatPredicate::OLT, float_lvalue, float_rvalue, "tmpVar") + .build_float_compare(FloatPredicate::OLT, float_lvalue, float_rvalue, "tmpVar")? .into(), Operator::Greater => self .llvm .builder - .build_float_compare(FloatPredicate::OGT, float_lvalue, float_rvalue, "tmpVar") + .build_float_compare(FloatPredicate::OGT, float_lvalue, float_rvalue, "tmpVar")? .into(), Operator::LessOrEqual => self .llvm .builder - .build_float_compare(FloatPredicate::OLE, float_lvalue, float_rvalue, "tmpVar") + .build_float_compare(FloatPredicate::OLE, float_lvalue, float_rvalue, "tmpVar")? .into(), Operator::GreaterOrEqual => self .llvm .builder - .build_float_compare(FloatPredicate::OGE, float_lvalue, float_rvalue, "tmpVar") + .build_float_compare(FloatPredicate::OGE, float_lvalue, float_rvalue, "tmpVar")? .into(), _ => unimplemented!(), }; - value + Ok(value) } fn generate_numeric_literal( @@ -2289,29 +2349,32 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { .builder .build_int_compare( IntPredicate::EQ, - to_i1(self.generate_expression(left)?.into_int_value(), &self.llvm.builder), - to_i1(self.generate_expression(right)?.into_int_value(), &self.llvm.builder), + to_i1(self.generate_expression(left)?.into_int_value(), &self.llvm.builder)?, + to_i1(self.generate_expression(right)?.into_int_value(), &self.llvm.builder)?, "", ) + .map_err(CodegenDiagnostic::from)? .as_basic_value_enum()), Operator::NotEqual => Ok(self .llvm .builder .build_int_compare( IntPredicate::NE, - to_i1(self.generate_expression(left)?.into_int_value(), &self.llvm.builder), - to_i1(self.generate_expression(right)?.into_int_value(), &self.llvm.builder), + to_i1(self.generate_expression(left)?.into_int_value(), &self.llvm.builder)?, + to_i1(self.generate_expression(right)?.into_int_value(), &self.llvm.builder)?, "", ) + .map_err(CodegenDiagnostic::from)? .as_basic_value_enum()), Operator::Xor => Ok(self .llvm .builder .build_xor( - to_i1(self.generate_expression(left)?.into_int_value(), &self.llvm.builder), - to_i1(self.generate_expression(right)?.into_int_value(), &self.llvm.builder), + to_i1(self.generate_expression(left)?.into_int_value(), &self.llvm.builder)?, + to_i1(self.generate_expression(right)?.into_int_value(), &self.llvm.builder)?, "", ) + .map_err(CodegenDiagnostic::from)? .as_basic_value_enum()), _ => Err(Diagnostic::codegen_error( format!("illegal boolean expresspion for operator {operator:}").as_str(), @@ -2332,7 +2395,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { right: &AstNode, ) -> Result, Diagnostic> { let builder = &self.llvm.builder; - let lhs = to_i1(self.generate_expression(left)?.into_int_value(), builder); + let lhs = to_i1(self.generate_expression(left)?.into_int_value(), builder)?; let function = self.get_function_context(left)?.function; let right_branch = self.llvm.context.append_basic_block(function, ""); @@ -2342,8 +2405,12 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { //Compare left to 0 match operator { - Operator::Or => builder.build_conditional_branch(lhs, continue_branch, right_branch), - Operator::And => builder.build_conditional_branch(lhs, right_branch, continue_branch), + Operator::Or => builder + .build_conditional_branch(lhs, continue_branch, right_branch) + .map_err(CodegenDiagnostic::from)?, + Operator::And => builder + .build_conditional_branch(lhs, right_branch, continue_branch) + .map_err(CodegenDiagnostic::from)?, _ => { return Err(Diagnostic::codegen_error( format!("Cannot generate phi-expression for operator {operator:}"), @@ -2353,13 +2420,13 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { }; builder.position_at_end(right_branch); - let rhs = to_i1(self.generate_expression(right)?.into_int_value(), builder); + let rhs = to_i1(self.generate_expression(right)?.into_int_value(), builder)?; let final_right_block = builder.get_insert_block().expect(INTERNAL_LLVM_ERROR); - builder.build_unconditional_branch(continue_branch); + builder.build_unconditional_branch(continue_branch).map_err(CodegenDiagnostic::from)?; builder.position_at_end(continue_branch); //Generate phi - let phi_value = builder.build_phi(lhs.get_type(), ""); + let phi_value = builder.build_phi(lhs.get_type(), "").map_err(CodegenDiagnostic::from)?; //assert phi_value.add_incoming(&[(&lhs, final_left_block), (&rhs, final_right_block)]); @@ -2427,7 +2494,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { )?; } else { let expression = self.generate_expression(right_statement)?; - self.llvm.builder.build_store(left, expression); + self.llvm.builder.build_store(left, expression).map_err(CodegenDiagnostic::from)?; } Ok(()) } @@ -2474,10 +2541,11 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { _ => unreachable!("memcpy is not used for non-aggregate types"), }; - self.llvm + Ok(self + .llvm .builder .build_memcpy(left, alignment, right, alignment, size) - .map_err(|err| Diagnostic::codegen_error(err, left_location)) + .map_err(|it| CodegenDiagnostic::from(it).with_location(left_location))?) } /// returns an optional name used for a temporary variable when loading a pointer represented by `expression` @@ -2502,7 +2570,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { reference: ExpressionValue<'ink>, reference_annotation: &StatementAnnotation, access: &AstNode, - ) -> Result, ()> { + ) -> Result, Diagnostic> { let builder = &self.llvm.builder; // array access is either directly on a reference or on another array access (ARRAY OF ARRAY) @@ -2515,17 +2583,25 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let struct_ptr = reference.get_basic_value_enum().into_pointer_value(); // GEPs into the VLA struct, getting an LValue for the array pointer and the dimension array and // dereferences the former - let arr_ptr_gep = self.llvm.builder.build_struct_gep(struct_ptr, 0, "vla_arr_gep")?; - let vla_arr_ptr = builder.build_load(arr_ptr_gep, "vla_arr_ptr").into_pointer_value(); + let arr_ptr_gep = self + .llvm + .builder + .build_struct_gep(struct_ptr, 0, "vla_arr_gep") + .map_err(CodegenDiagnostic::from)?; + let vla_arr_ptr = builder + .build_load(arr_ptr_gep, "vla_arr_ptr") + .map_err(CodegenDiagnostic::from)? + .into_pointer_value(); // get pointer to array containing dimension information - let dim_arr_gep = builder.build_struct_gep(struct_ptr, 1, "dim_arr").unwrap(); + let dim_arr_gep = + builder.build_struct_gep(struct_ptr, 1, "dim_arr").map_err(CodegenDiagnostic::from)?; // get lengths of dimensions let type_ = self.index.get_type_information_or_void(reference_type); let Some(ndims) = type_.get_type_information().get_dimensions() else { unreachable!() }; // get the start/end offsets for each dimension ( ARRAY[4..10, -4..4] ...) - let index_offsets = get_indices(self.llvm, ndims, dim_arr_gep); + let index_offsets = get_indices(self.llvm, ndims, dim_arr_gep)?; // calculate the required offset from the array pointer for the given accessor statements. this is // relatively straightforward for single-dimensional arrays, but is quite costly (O(n²)) for multi-dimensional arrays @@ -2534,47 +2610,47 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let Some(stmt) = access_statements.first() else { unreachable!("Must have exactly 1 access statement") }; - let access_value = self.generate_expression(stmt).map_err(|_| ())?; + let access_value = self.generate_expression(stmt)?; // if start offset is not 0, adjust the access value accordingly let Some(start_offset) = index_offsets.first().map(|(start, _)| *start) else { unreachable!("VLA must have information about dimension offsets") }; - self.create_llvm_int_binary_expression(&Operator::Minus, access_value, start_offset.into()) + self.create_llvm_int_binary_expression(&Operator::Minus, access_value, start_offset.into())? .into_int_value() } else { // see https://plc-lang.github.io/rusty/arch/codegen.html#multi-dimensional-arrays // for more details on multi-dimensional array accessor calculation let accessors = access_statements .iter() - .map(|it| { - self.generate_expression(it) - .expect("Uncaught invalid accessor statement") - .into_int_value() - }) - .collect::>(); + .map(|it| Ok(self.generate_expression(it)?.into_int_value())) + .collect::, Diagnostic>>()?; if access_statements.len() != index_offsets.len() { unreachable!("Amount of access statements and dimensions does not match.") } // length of a dimension is 'end - start + 1' - let lengths = get_dimension_lengths(self.llvm, &index_offsets); + let lengths = get_dimension_lengths(self.llvm, &index_offsets)?; // calculate the accessor multiplicators for each dimension. - let dimension_offsets = get_vla_accessor_factors(self.llvm, &lengths); + let dimension_offsets = get_vla_accessor_factors(self.llvm, &lengths)?; // adjust accessors for 0-indexing - let adjusted_accessors = normalize_offsets(self.llvm, &accessors, &index_offsets); + let adjusted_accessors = normalize_offsets(self.llvm, &accessors, &index_offsets)?; // calculate the resulting accessor for the given accessor statements and dimension offsets int_value_multiply_accumulate( self.llvm, &adjusted_accessors.iter().zip(&dimension_offsets).collect::>(), - ) + )? }; - Ok(unsafe { builder.build_in_bounds_gep(vla_arr_ptr, &[accessor], "arr_val") }) + Ok(unsafe { + builder + .build_in_bounds_gep(vla_arr_ptr, &[accessor], "arr_val") + .map_err(CodegenDiagnostic::from)? + }) } /// generates a reference expression (member, index, deref, etc.) @@ -2642,7 +2718,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let ptr = self.generate_expression_value(base)?; Ok(ExpressionValue::LValue( self.llvm - .load_pointer(&ptr.get_basic_value_enum().into_pointer_value(), "deref") + .load_pointer(&ptr.get_basic_value_enum().into_pointer_value(), "deref")? .into_pointer_value(), )) } @@ -2677,29 +2753,40 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { access: &DirectAccessType, index: &AstNode, ) -> Result, Diagnostic> { - let loaded_base_value = qualifier_value.as_r_value(self.llvm, self.get_load_name(qualifier)); + let loaded_base_value = qualifier_value.as_r_value(self.llvm, self.get_load_name(qualifier))?; let datatype = self.get_type_hint_info_for(member)?; let base_type = self.get_type_hint_for(qualifier)?; //Generate and load the index value let rhs = self.generate_direct_access_index(access, index, datatype, base_type)?; //Shift the qualifer value right by the index value - let shift = self.llvm.builder.build_right_shift( - loaded_base_value.into_int_value(), - rhs, - base_type.get_type_information().is_signed_int(), - "shift", - ); + let shift = self + .llvm + .builder + .build_right_shift( + loaded_base_value.into_int_value(), + rhs, + base_type.get_type_information().is_signed_int(), + "shift", + ) + .map_err(CodegenDiagnostic::from)?; //Trunc the result to the get only the target size - let value = self.llvm.builder.build_int_truncate_or_bit_cast( - shift, - self.llvm_index.get_associated_type(datatype.get_name())?.into_int_type(), - "", - ); + let value = self + .llvm + .builder + .build_int_truncate_or_bit_cast( + shift, + self.llvm_index.get_associated_type(datatype.get_name())?.into_int_type(), + "", + ) + .map_err(CodegenDiagnostic::from)?; let result = if datatype.get_type_information().is_bool() { // since booleans are i1 internally, but i8 in llvm, we need to bitwise-AND the value with 1 to make sure we end up with the expected value - self.llvm.builder.build_and(value, self.llvm.context.i8_type().const_int(1, false), "") + self.llvm + .builder + .build_and(value, self.llvm.context.i8_type().const_int(1, false), "") + .map_err(CodegenDiagnostic::from)? } else { value }; @@ -2745,11 +2832,11 @@ pub fn get_implicit_call_parameter<'a>( } /// turns the given IntValue into an i1 by comparing it to 0 (of the same size) -pub fn to_i1<'a>(value: IntValue<'a>, builder: &Builder<'a>) -> IntValue<'a> { +pub fn to_i1<'a>(value: IntValue<'a>, builder: &Builder<'a>) -> Result, CodegenDiagnostic> { if value.get_type().get_bit_width() > 1 { - builder.build_int_compare(IntPredicate::NE, value, value.get_type().const_int(0, false), "") + Ok(builder.build_int_compare(IntPredicate::NE, value, value.get_type().const_int(0, false), "")?) } else { - value + Ok(value) } } @@ -2762,7 +2849,7 @@ fn get_indices<'ink>( llvm: &Llvm<'ink>, ndims: usize, dimensions_array: PointerValue<'ink>, -) -> Vec<(IntValue<'ink>, IntValue<'ink>)> { +) -> Result, IntValue<'ink>)>, CodegenDiagnostic> { (0..ndims) .map(|i| unsafe { let (start_ptr, end_ptr) = ( @@ -2770,19 +2857,19 @@ fn get_indices<'ink>( dimensions_array, &[llvm.i32_type().const_zero(), llvm.i32_type().const_int(i as u64 * 2, false)], format!("start_idx_ptr{i}").as_str(), - ), + )?, llvm.builder.build_in_bounds_gep( dimensions_array, &[llvm.i32_type().const_zero(), llvm.i32_type().const_int(1 + i as u64 * 2, false)], format!("end_idx_ptr{i}").as_str(), - ), + )?, ); - ( - llvm.builder.build_load(start_ptr, format!("start_idx_value{i}").as_str()).into_int_value(), - llvm.builder.build_load(end_ptr, format!("end_idx_value{i}").as_str()).into_int_value(), - ) + Ok(( + llvm.builder.build_load(start_ptr, format!("start_idx_value{i}").as_str())?.into_int_value(), + llvm.builder.build_load(end_ptr, format!("end_idx_value{i}").as_str())?.into_int_value(), + )) }) - .collect::>() + .collect::, _>>() } /// Adjusts VLA accessor values to 0-indexed accessors @@ -2790,67 +2877,73 @@ fn normalize_offsets<'ink>( llvm: &Llvm<'ink>, accessors: &[IntValue<'ink>], offsets: &[(IntValue<'ink>, IntValue<'ink>)], -) -> Vec> { +) -> Result>, CodegenDiagnostic> { accessors .iter() .enumerate() .zip(offsets.iter().map(|(start, _)| start)) .map(|((idx, accessor), start_offset)| { - llvm.builder.build_int_sub(*accessor, *start_offset, format!("adj_access{idx}").as_str()) + Ok(llvm.builder.build_int_sub(*accessor, *start_offset, format!("adj_access{idx}").as_str())?) }) - .collect::>() + .collect::, _>>() } fn get_dimension_lengths<'ink>( llvm: &Llvm<'ink>, offsets: &[(IntValue<'ink>, IntValue<'ink>)], -) -> Vec> { +) -> Result>, CodegenDiagnostic> { offsets .iter() .enumerate() .map(|(idx, (start, end))| { - llvm.builder.build_int_add( + Ok(llvm.builder.build_int_add( llvm.i32_type().const_int(1, false), - llvm.builder.build_int_sub(*end, *start, ""), + llvm.builder.build_int_sub(*end, *start, "")?, format!("len_dim{idx}").as_str(), - ) + )?) }) - .collect::>() + .collect::, _>>() } -fn get_vla_accessor_factors<'ink>(llvm: &Llvm<'ink>, lengths: &[IntValue<'ink>]) -> Vec> { +fn get_vla_accessor_factors<'ink>( + llvm: &Llvm<'ink>, + lengths: &[IntValue<'ink>], +) -> Result>, CodegenDiagnostic> { (0..lengths.len()) .map(|idx| { if idx == lengths.len() - 1 { // the last dimension has a factor of 1 - llvm.i32_type().const_int(1, false) + Ok(llvm.i32_type().const_int(1, false)) } else { // for other dimensions, calculate size to the right - int_value_product(llvm, &lengths[idx + 1..lengths.len()]) + Ok(int_value_product(llvm, &lengths[idx + 1..lengths.len()])?) } }) - .collect::>() + .collect::, _>>() } /// Computes the product of all elements in a collection of IntValues /// /// a <- a * b -fn int_value_product<'ink>(llvm: &Llvm<'ink>, values: &[IntValue<'ink>]) -> IntValue<'ink> { +fn int_value_product<'ink>( + llvm: &Llvm<'ink>, + values: &[IntValue<'ink>], +) -> Result, CodegenDiagnostic> { // initialize the accumulator with 1 - let accum_ptr = llvm.builder.build_alloca(llvm.i32_type(), "accum"); - llvm.builder.build_store(accum_ptr, llvm.i32_type().const_int(1, false)); + let accum_ptr = llvm.builder.build_alloca(llvm.i32_type(), "accum")?; + llvm.builder.build_store(accum_ptr, llvm.i32_type().const_int(1, false))?; for val in values { // load previous value from accumulator and multiply with current value let product = llvm.builder.build_int_mul( - llvm.builder.build_load(accum_ptr, "load_accum").into_int_value(), + llvm.builder.build_load(accum_ptr, "load_accum")?.into_int_value(), *val, "product", - ); + )?; // store new value into accumulator - llvm.builder.build_store(accum_ptr, product); + llvm.builder.build_store(accum_ptr, product)?; } - llvm.builder.build_load(accum_ptr, "accessor_factor").into_int_value() + Ok(llvm.builder.build_load(accum_ptr, "accessor_factor")?.into_int_value()) } /// Iterates over a collection of tuples, computes the product of the two numbers @@ -2860,23 +2953,23 @@ fn int_value_product<'ink>(llvm: &Llvm<'ink>, values: &[IntValue<'ink>]) -> IntV fn int_value_multiply_accumulate<'ink>( llvm: &Llvm<'ink>, values: &[(&IntValue<'ink>, &IntValue<'ink>)], -) -> IntValue<'ink> { +) -> Result, CodegenDiagnostic> { // initialize the accumulator with 0 - let accum = llvm.builder.build_alloca(llvm.i32_type(), "accum"); - llvm.builder.build_store(accum, llvm.i32_type().const_zero()); + let accum = llvm.builder.build_alloca(llvm.i32_type(), "accum")?; + llvm.builder.build_store(accum, llvm.i32_type().const_zero())?; for (left, right) in values { // multiply accessor with dimension factor - let product = llvm.builder.build_int_mul(**left, **right, "multiply"); + let product = llvm.builder.build_int_mul(**left, **right, "multiply")?; // load previous value from accum and add product let curr = llvm.builder.build_int_add( - llvm.builder.build_load(accum, "load_accum").into_int_value(), + llvm.builder.build_load(accum, "load_accum")?.into_int_value(), product, "accumulate", - ); + )?; // store new value into accumulator - llvm.builder.build_store(accum, curr); + llvm.builder.build_store(accum, curr)?; } - llvm.builder.build_load(accum, "accessor").into_int_value() + Ok(llvm.builder.build_load(accum, "accessor")?.into_int_value()) } // XXX: Could be problematic with https://github.com/PLC-lang/rusty/issues/668 diff --git a/src/codegen/generators/llvm.rs b/src/codegen/generators/llvm.rs index 4dca0a578f..3fab7198aa 100644 --- a/src/codegen/generators/llvm.rs +++ b/src/codegen/generators/llvm.rs @@ -1,3 +1,4 @@ +use crate::codegen::diagnostics::CodegenDiagnostic; // Copyright (c) 2020 Ghaith Hachem and Mathias Rieder use crate::typesystem::{CHAR_TYPE, WCHAR_TYPE}; use inkwell::types::ArrayType; @@ -83,8 +84,12 @@ impl<'a> Llvm<'a> { /// /// - `name` the name of the local variable /// - `data_type` the variable's datatype - pub fn create_local_variable(&self, name: &str, data_type: &BasicTypeEnum<'a>) -> PointerValue<'a> { - self.builder.build_alloca(*data_type, name) + pub fn create_local_variable( + &self, + name: &str, + data_type: &BasicTypeEnum<'a>, + ) -> Result, CodegenDiagnostic> { + self.builder.build_alloca(*data_type, name).map_err(Into::into) } /// sets a const-zero initializer for the given global_value according to the given type @@ -114,8 +119,12 @@ impl<'a> Llvm<'a> { pointer_to_array_instance: PointerValue<'a>, accessor_sequence: &[IntValue<'a>], name: &str, - ) -> Result, Diagnostic> { - unsafe { Ok(self.builder.build_in_bounds_gep(pointer_to_array_instance, accessor_sequence, name)) } + ) -> Result, CodegenDiagnostic> { + unsafe { + self.builder + .build_in_bounds_gep(pointer_to_array_instance, accessor_sequence, name) + .map_err(Into::into) + } } /// creates a pointervalue that points to a member of a struct @@ -129,22 +138,21 @@ impl<'a> Llvm<'a> { pointer_to_struct_instance: PointerValue<'a>, member_index: u32, name: &str, - offset: &SourceLocation, - ) -> Result, Diagnostic> { - self.builder.build_struct_gep(pointer_to_struct_instance, member_index, name).map_err(|_| { - Diagnostic::codegen_error( - format!("Cannot generate qualified reference for {name:}"), - offset.clone(), - ) - }) + _offset: &SourceLocation, + ) -> Result, CodegenDiagnostic> { + self.builder.build_struct_gep(pointer_to_struct_instance, member_index, name).map_err(Into::into) } /// loads the value behind the given pointer /// /// - `lvalue` the pointer and it's datatype /// - `name` the name of the temporary variable - pub fn load_pointer(&self, lvalue: &PointerValue<'a>, name: &str) -> BasicValueEnum<'a> { - self.builder.build_load(lvalue.to_owned(), name) + pub fn load_pointer( + &self, + lvalue: &PointerValue<'a>, + name: &str, + ) -> Result, CodegenDiagnostic> { + self.builder.build_load(lvalue.to_owned(), name).map_err(Into::into) } /// creates a placeholder datatype for a struct with the given name @@ -187,7 +195,9 @@ impl<'a> Llvm<'a> { .ok_or_else(|| Diagnostic::codegen_error(format!("Cannot parse {value} as int"), location)) .map(BasicValueEnum::IntValue), BasicTypeEnum::FloatType { 0: float_type } => { - let value = float_type.const_float_from_string(value); + //todo: this is unsafe for now because llvm does no validaton, if we rely on the + //parsing having been done correctly we cound ignore the unsafe + let value = unsafe { float_type.const_float_from_string(value) }; Ok(BasicValueEnum::FloatValue(value)) } _ => Err(Diagnostic::codegen_error("expected numeric type", location)), diff --git a/src/codegen/generators/pou_generator.rs b/src/codegen/generators/pou_generator.rs index dbdc935285..2b695c4f6d 100644 --- a/src/codegen/generators/pou_generator.rs +++ b/src/codegen/generators/pou_generator.rs @@ -11,6 +11,7 @@ use super::{ use crate::{ codegen::{ debug::{Debug, DebugBuilderEnum}, + diagnostics::CodegenDiagnostic, llvm_index::LlvmTypedIndex, }, index::{self, ImplementationType}, @@ -40,7 +41,7 @@ use inkwell::{ values::PointerValue, }; use plc_ast::ast::{AstNode, Implementation, PouType}; -use plc_diagnostics::diagnostics::{Diagnostic, INTERNAL_LLVM_ERROR}; +use plc_diagnostics::diagnostics::Diagnostic; use plc_source::source_location::SourceLocation; use rustc_hash::FxHashMap; use section_mangler::{FunctionArgument, SectionMangler}; @@ -548,12 +549,12 @@ impl<'ink, 'cg> PouGenerator<'ink, 'cg> { let accessor = self.llvm.create_local_variable( ret_v.get_name(), &return_type.ptr_type(AddressSpace::from(ADDRESS_SPACE_GENERIC)).as_basic_type_enum(), - ); - self.llvm.builder.build_store(accessor, parameter); + )?; + self.llvm.builder.build_store(accessor, parameter).map_err(CodegenDiagnostic::from)?; accessor } else { // function return is a real return - self.llvm.create_local_variable(type_name, &return_type) + self.llvm.create_local_variable(type_name, &return_type)? }; index.associate_loaded_local_variable(type_name, ret_v.get_name(), return_variable)?; } @@ -569,7 +570,7 @@ impl<'ink, 'cg> PouGenerator<'ink, 'cg> { let member_type_name = m.get_type_name(); let type_info = self.index.get_type_information_or_void(member_type_name); let ty = index.get_associated_type(member_type_name)?; - let ptr = self.llvm.create_local_variable(m.get_name(), &ty); + let ptr = self.llvm.create_local_variable(m.get_name(), &ty)?; if let Some(block) = self.llvm.builder.get_insert_block() { debug.add_variable_declaration( m.get_qualified_name(), @@ -592,7 +593,12 @@ impl<'ink, 'cg> PouGenerator<'ink, 'cg> { } else { ty.into_struct_type().ptr_type(AddressSpace::from(ADDRESS_SPACE_GENERIC)) }; - let bitcast = self.llvm.builder.build_bitcast(ptr, ty, "bitcast").into_pointer_value(); + let bitcast = self + .llvm + .builder + .build_bit_cast(ptr, ty, "bitcast") + .map_err(CodegenDiagnostic::from)? + .into_pointer_value(); let (size, alignment) = if let DataTypeInformation::String { size, encoding } = type_info { // since passed string args might be larger than the local acceptor, we need to first memset the local variable to 0 @@ -608,7 +614,10 @@ impl<'ink, 'cg> PouGenerator<'ink, 'cg> { self.llvm.context.i8_type().const_zero(), self.llvm.context.i64_type().const_int(size * char_width as u64, true), ) - .map_err(|e| Diagnostic::codegen_error(e, m.source_location.clone()))?; + .map_err(|e| { + Diagnostic::from(CodegenDiagnostic::from(e)) + .with_location(m.source_location.clone()) + })?; ( // we then reduce the amount of bytes to be memcopied by the equivalent of one grapheme in bytes to preserve the null-terminator self.llvm.context.i64_type().const_int((size - 1) * char_width as u64, true), @@ -627,15 +636,18 @@ impl<'ink, 'cg> PouGenerator<'ink, 'cg> { self.llvm .builder .build_memcpy(bitcast, alignment, ptr_value.into_pointer_value(), alignment, size) - .map_err(|e| Diagnostic::codegen_error(e, m.source_location.clone()))?; + .map_err(|e| { + Diagnostic::from(CodegenDiagnostic::from(e)) + .with_location(m.source_location.clone()) + })?; } else { - self.llvm.builder.build_store(ptr, ptr_value); + self.llvm.builder.build_store(ptr, ptr_value).map_err(CodegenDiagnostic::from)?; }; (parameter_name, ptr) } else { let temp_type = index.get_associated_type(m.get_type_name())?; - let value = self.llvm.create_local_variable(parameter_name, &temp_type); + let value = self.llvm.create_local_variable(parameter_name, &temp_type)?; (parameter_name, value) }; @@ -681,13 +693,13 @@ impl<'ink, 'cg> PouGenerator<'ink, 'cg> { let (name, variable) = if m.is_temp() || m.is_return() { let temp_type = index.get_associated_type(m.get_type_name())?; - (parameter_name, self.llvm.create_local_variable(parameter_name, &temp_type)) + (parameter_name, self.llvm.create_local_variable(parameter_name, &temp_type)?) } else { let ptr = self .llvm .builder .build_struct_gep(param_pointer, var_count as u32, parameter_name) - .expect(INTERNAL_LLVM_ERROR); + .map_err(CodegenDiagnostic::from)?; var_count += 1; @@ -797,7 +809,11 @@ impl<'ink, 'cg> PouGenerator<'ink, 'cg> { let is_aggregate_type = variable_data_type.is_aggregate_type(); let variable_to_initialize = if variable.is_return() && is_aggregate_type { //if this is an out-pointer we need to deref it first - self.llvm.builder.build_load(variable_to_initialize, "deref").into_pointer_value() + self.llvm + .builder + .build_load(variable_to_initialize, "deref") + .map_err(CodegenDiagnostic::from)? + .into_pointer_value() } else { variable_to_initialize }; @@ -806,7 +822,7 @@ impl<'ink, 'cg> PouGenerator<'ink, 'cg> { if is_aggregate_type { // for arrays/structs, we prefere a memcpy, not a store operation // we assume that we got a global variable with the initial value that we can copy from - let init_result: Result<(), &str> = if value.is_pointer_value() { + let init_result: Result<(), CodegenDiagnostic> = if value.is_pointer_value() { // mem-copy from an global constant variable self.llvm .builder @@ -818,6 +834,7 @@ impl<'ink, 'cg> PouGenerator<'ink, 'cg> { type_size?, ) .map(|_| ()) + .map_err(|it| CodegenDiagnostic::from(it).with_location(variable.source_location.clone())) } else if value.is_int_value() { // mem-set the value (usually 0) over the whole memory-area self.llvm @@ -829,12 +846,13 @@ impl<'ink, 'cg> PouGenerator<'ink, 'cg> { type_size?, ) .map(|_| ()) + .map_err(|it| CodegenDiagnostic::from(it).with_location(variable.source_location.clone())) } else { unreachable!("initializing an array should be memcpy-able or memset-able"); }; - init_result.map_err(|msg| Diagnostic::codegen_error(msg, variable.source_location.clone()))?; + init_result?; } else { - self.llvm.builder.build_store(variable_to_initialize, value); + self.llvm.builder.build_store(variable_to_initialize, value).map_err(CodegenDiagnostic::from)?; } Ok(()) } diff --git a/src/codegen/generators/statement_generator.rs b/src/codegen/generators/statement_generator.rs index 79b314d4be..304657d8ee 100644 --- a/src/codegen/generators/statement_generator.rs +++ b/src/codegen/generators/statement_generator.rs @@ -6,6 +6,7 @@ use super::{ use crate::{ codegen::{ debug::{Debug, DebugBuilderEnum}, + diagnostics::CodegenDiagnostic, llvm_typesystem::cast_if_needed, LlvmTypedIndex, }, @@ -145,7 +146,7 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { if let Some(block) = self.function_context.blocks.get(name) { //unconditionally jump to the label self.register_debug_location(statement); - self.llvm.builder.build_unconditional_branch(*block); + self.llvm.builder.build_unconditional_branch(*block).map_err(CodegenDiagnostic::from)?; //Place the current instert block at the label statement self.llvm.builder.position_at_end(*block); } @@ -173,18 +174,20 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { let condition = expression_generator.generate_expression(condition)?; self.register_debug_location(statement); - self.llvm.builder.build_conditional_branch( - condition.into_int_value(), - *then_block, - else_block, - ); + self.llvm + .builder + .build_conditional_branch(condition.into_int_value(), *then_block, else_block) + .map_err(CodegenDiagnostic::from)?; // Make sure further code is at the else block self.llvm.builder.position_at_end(else_block); } AstStatement::ExitStatement(_) => { if let Some(exit_block) = &self.current_loop_exit { self.register_debug_location(statement); - self.llvm.builder.build_unconditional_branch(*exit_block); + self.llvm + .builder + .build_unconditional_branch(*exit_block) + .map_err(CodegenDiagnostic::from)?; self.generate_buffer_block(); } else { return Err(Diagnostic::codegen_error( @@ -195,7 +198,10 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { } AstStatement::ContinueStatement(_) => { if let Some(cont_block) = &self.current_loop_continue { - self.llvm.builder.build_unconditional_branch(*cont_block); + self.llvm + .builder + .build_unconditional_branch(*cont_block) + .map_err(CodegenDiagnostic::from)?; self.generate_buffer_block(); } else { return Err(Diagnostic::codegen_error( @@ -257,7 +263,10 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { }; let right_expr_val = ref_builtin.codegen(&exp, &[right], right.get_location())?; - self.llvm.builder.build_store(left_ptr_val, right_expr_val.get_basic_value_enum()); + self.llvm + .builder + .build_store(left_ptr_val, right_expr_val.get_basic_value_enum()) + .map_err(CodegenDiagnostic::from)?; Ok(()) } @@ -327,7 +336,7 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { unreachable!("Invalid direct-access expression: {left_statement:#?}") }; let left_expr_value = exp_gen.generate_expression_value(base)?; - let left_value = left_expr_value.as_r_value(self.llvm, None).into_int_value(); + let left_value = left_expr_value.as_r_value(self.llvm, None)?.into_int_value(); let left_pointer = left_expr_value.get_basic_value_enum().into_pointer_value(); // Generate an expression for the right size @@ -378,7 +387,7 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { || self.llvm.create_const_numeric(&cast_target_llty, "1", SourceLocation::internal()), |step_ty| { let step = exp_gen.generate_expression(by_step.as_ref().unwrap())?; - Ok(cast_if_needed!(exp_gen, cast_target_ty, step_ty, step, None)) + Ok(cast_if_needed!(exp_gen, cast_target_ty, step_ty, step, None)?) }, ) }; @@ -403,32 +412,40 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { .create_const_numeric(&cast_target_llty, "0", SourceLocation::internal())? .into_int_value(), "is_incrementing", - ); - builder.build_conditional_branch(is_incrementing, predicate_incrementing, predicate_decrementing); + ) + .map_err(CodegenDiagnostic::from)?; + builder.build_conditional_branch(is_incrementing, predicate_incrementing, predicate_decrementing) + .map_err(CodegenDiagnostic::from)?; // generate predicates for incrementing and decrementing counters - let generate_predicate = |predicate| { + let generate_predicate = |predicate| -> Result<(), Diagnostic> { builder.position_at_end(match predicate { inkwell::IntPredicate::SLE => predicate_incrementing, inkwell::IntPredicate::SGE => predicate_decrementing, _ => unreachable!(), }); - let end = exp_gen.generate_expression_value(end).unwrap(); + let end = exp_gen.generate_expression_value(end)?; let end_value = match end { - ExpressionValue::LValue(ptr) => builder.build_load(ptr, ""), + ExpressionValue::LValue(ptr) => { + builder.build_load(ptr, "").map_err(CodegenDiagnostic::from)? + } ExpressionValue::RValue(val) => val, }; - let counter_value = builder.build_load(counter, ""); - let cmp = builder.build_int_compare( - predicate, - cast_if_needed!(exp_gen, cast_target_ty, counter_ty, counter_value, None).into_int_value(), - cast_if_needed!(exp_gen, cast_target_ty, end_ty, end_value, None).into_int_value(), - "condition", - ); - builder.build_conditional_branch(cmp, loop_body, afterloop); + let counter_value = builder.build_load(counter, "").map_err(CodegenDiagnostic::from)?; + let cmp = builder + .build_int_compare( + predicate, + cast_if_needed!(exp_gen, cast_target_ty, counter_ty, counter_value, None)? + .into_int_value(), + cast_if_needed!(exp_gen, cast_target_ty, end_ty, end_value, None)?.into_int_value(), + "condition", + ) + .map_err(CodegenDiagnostic::from)?; + builder.build_conditional_branch(cmp, loop_body, afterloop).map_err(CodegenDiagnostic::from)?; + Ok(()) }; - generate_predicate(inkwell::IntPredicate::SLE); - generate_predicate(inkwell::IntPredicate::SGE); + generate_predicate(inkwell::IntPredicate::SLE)?; + generate_predicate(inkwell::IntPredicate::SGE)?; // generate loop body builder.position_at_end(loop_body); @@ -442,21 +459,30 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { body_builder.generate_body(body)?; // increment counter - builder.build_unconditional_branch(increment); + builder.build_unconditional_branch(increment).map_err(CodegenDiagnostic::from)?; builder.position_at_end(increment); - let counter_value = builder.build_load(counter, ""); - let inc = inkwell::values::BasicValue::as_basic_value_enum(&builder.build_int_add( - eval_step()?.into_int_value(), - cast_if_needed!(exp_gen, cast_target_ty, counter_ty, counter_value, None).into_int_value(), - "next", - )); - builder.build_store( - counter, - cast_if_needed!(exp_gen, counter_ty, cast_target_ty, inc, None).into_int_value(), + let counter_value = builder.build_load(counter, "").map_err(CodegenDiagnostic::from)?; + let inc = inkwell::values::BasicValue::as_basic_value_enum( + &builder + .build_int_add( + eval_step()?.into_int_value(), + cast_if_needed!(exp_gen, cast_target_ty, counter_ty, counter_value, None)? + .into_int_value(), + "next", + ) + .map_err(CodegenDiagnostic::from)?, ); + builder + .build_store( + counter, + cast_if_needed!(exp_gen, counter_ty, cast_target_ty, inc, None)?.into_int_value(), + ) + .map_err(CodegenDiagnostic::from)?; // check condition - builder.build_conditional_branch(is_incrementing, predicate_incrementing, predicate_decrementing); + builder + .build_conditional_branch(is_incrementing, predicate_incrementing, predicate_decrementing) + .map_err(CodegenDiagnostic::from)?; // continue builder.position_at_end(afterloop); Ok(()) @@ -519,19 +545,20 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { builder.position_at_end(case_block); self.generate_body(&conditional_block.body)?; // skiop all other case-bodies - builder.build_unconditional_branch(continue_block); + builder.build_unconditional_branch(continue_block).map_err(CodegenDiagnostic::from)?; } // current-else is the last else-block generated by the range-expressions builder.position_at_end(current_else_block); self.generate_body(else_body)?; - builder.build_unconditional_branch(continue_block); + builder.build_unconditional_branch(continue_block).map_err(CodegenDiagnostic::from)?; continue_block.move_after(current_else_block).expect(INTERNAL_LLVM_ERROR); // now that we collected all cases, go back to the initial block and generate the switch-statement builder.position_at_end(basic_block); - self.register_debug_location(selector); - builder.build_switch(selector_statement.into_int_value(), else_block, &cases); + builder + .build_switch(selector_statement.into_int_value(), else_block, &cases) + .map_err(CodegenDiagnostic::from)?; builder.position_at_end(continue_block); Ok(()) @@ -558,28 +585,24 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { let start_val = exp_gen.generate_expression(start)?; self.register_debug_location(selector); let selector_val = exp_gen.generate_expression(selector)?; - exp_gen.create_llvm_int_binary_expression(&Operator::GreaterOrEqual, selector_val, start_val) + exp_gen.create_llvm_int_binary_expression(&Operator::GreaterOrEqual, selector_val, start_val)? }; //jmp to continue if the value is smaller than start - builder.build_conditional_branch( - to_i1(lower_bound.into_int_value(), builder), - range_then, - range_else, - ); + builder + .build_conditional_branch(to_i1(lower_bound.into_int_value(), builder)?, range_then, range_else) + .map_err(CodegenDiagnostic::from)?; builder.position_at_end(range_then); let upper_bound = { self.register_debug_location(end); let end_val = exp_gen.generate_expression(end)?; self.register_debug_location(selector); let selector_val = exp_gen.generate_expression(selector)?; - exp_gen.create_llvm_int_binary_expression(&Operator::LessOrEqual, selector_val, end_val) + exp_gen.create_llvm_int_binary_expression(&Operator::LessOrEqual, selector_val, end_val)? }; - builder.build_conditional_branch( - to_i1(upper_bound.into_int_value(), builder), - match_block, - range_else, - ); + builder + .build_conditional_branch(to_i1(upper_bound.into_int_value(), builder)?, match_block, range_else) + .map_err(CodegenDiagnostic::from)?; Ok(range_else) } @@ -599,7 +622,7 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { let continue_block = builder.get_insert_block().expect(INTERNAL_LLVM_ERROR); builder.position_at_end(basic_block); - builder.build_unconditional_branch(condition_block); + builder.build_unconditional_branch(condition_block).map_err(CodegenDiagnostic::from)?; builder.position_at_end(continue_block); Ok(()) @@ -629,7 +652,7 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { let continue_block = builder.get_insert_block().expect(INTERNAL_LLVM_ERROR); builder.position_at_end(basic_block); - builder.build_unconditional_branch(while_block); + builder.build_unconditional_branch(while_block).map_err(CodegenDiagnostic::from)?; builder.position_at_end(continue_block); Ok(()) @@ -650,11 +673,13 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { builder.position_at_end(condition_check); self.register_debug_location(condition); let condition_value = self.create_expr_generator().generate_expression(condition)?; - builder.build_conditional_branch( - to_i1(condition_value.into_int_value(), builder), - while_body, - continue_block, - ); + builder + .build_conditional_branch( + to_i1(condition_value.into_int_value(), builder)?, + while_body, + continue_block, + ) + .map_err(CodegenDiagnostic::from)?; //Enter the for loop builder.position_at_end(while_body); @@ -667,7 +692,7 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { }; body_generator.generate_body(body)?; //Loop back - builder.build_unconditional_branch(condition_check); + builder.build_unconditional_branch(condition_check).map_err(CodegenDiagnostic::from)?; //Continue builder.position_at_end(continue_block); @@ -711,24 +736,26 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { let conditional_block = context.prepend_basic_block(else_block, "condition_body"); //Generate if statement condition - builder.build_conditional_branch( - to_i1(condition.into_int_value(), builder), - conditional_block, - else_block, - ); + builder + .build_conditional_branch( + to_i1(condition.into_int_value(), builder)?, + conditional_block, + else_block, + ) + .map_err(CodegenDiagnostic::from)?; //Generate if statement content builder.position_at_end(conditional_block); self.generate_body(&block.body)?; - builder.build_unconditional_branch(continue_block); + builder.build_unconditional_branch(continue_block).map_err(CodegenDiagnostic::from)?; } //Else if let Some(else_block) = else_block { builder.position_at_end(else_block); self.generate_body(else_body)?; - builder.build_unconditional_branch(continue_block); + builder.build_unconditional_branch(continue_block).map_err(CodegenDiagnostic::from)?; } //Continue builder.position_at_end(continue_block); @@ -749,7 +776,7 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { .unwrap_or(false) { //generate return void - self.llvm.builder.build_return(None); + self.llvm.builder.build_return(None).map_err(CodegenDiagnostic::from)?; } else { // renerate return statement let call_name = self.function_context.linking_context.get_call_name(); @@ -762,11 +789,11 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { SourceLocation::undefined(), ) })?; - let loaded_value = self.llvm.load_pointer(&value_ptr, var_name.as_str()); - self.llvm.builder.build_return(Some(&loaded_value)); + let loaded_value = self.llvm.load_pointer(&value_ptr, var_name.as_str())?; + self.llvm.builder.build_return(Some(&loaded_value)).map_err(CodegenDiagnostic::from)?; } } else { - self.llvm.builder.build_return(None); + self.llvm.builder.build_return(None).map_err(CodegenDiagnostic::from)?; } Ok(()) } @@ -786,11 +813,14 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { let then_block = self.llvm.context.append_basic_block(self.function_context.function, "then_block"); let else_block = self.llvm.context.append_basic_block(self.function_context.function, "else_block"); - self.llvm.builder.build_conditional_branch( - to_i1(condition.into_int_value(), &self.llvm.builder), - then_block, - else_block, - ); + self.llvm + .builder + .build_conditional_branch( + to_i1(condition.into_int_value(), &self.llvm.builder)?, + then_block, + else_block, + ) + .map_err(CodegenDiagnostic::from)?; self.llvm.builder.position_at_end(then_block); self.register_debug_location(statement); diff --git a/src/codegen/generators/variable_generator.rs b/src/codegen/generators/variable_generator.rs index 2601a657ad..30804c3598 100644 --- a/src/codegen/generators/variable_generator.rs +++ b/src/codegen/generators/variable_generator.rs @@ -164,7 +164,7 @@ impl<'ctx, 'b> VariableGenerator<'ctx, 'b> { let value = expr_generator.generate_expression(initializer)?; let target_type = self.global_index.get_effective_type_or_void_by_name(type_name); let value_type = self.annotations.get_type_or_void(initializer, self.global_index); - Some(cast_if_needed!(expr_generator, target_type, value_type, value, None)) + Some(cast_if_needed!(expr_generator, target_type, value_type, value, None)?) } } else { None diff --git a/src/codegen/llvm_typesystem.rs b/src/codegen/llvm_typesystem.rs index 5082365452..faeb12f6cd 100644 --- a/src/codegen/llvm_typesystem.rs +++ b/src/codegen/llvm_typesystem.rs @@ -2,7 +2,7 @@ use inkwell::{ context::Context, types::{FloatType, IntType}, - values::{ArrayValue, BasicValueEnum, FloatValue, IntValue, PointerValue}, + values::{ArrayValue, BasicValue, BasicValueEnum, FloatValue, IntValue, PointerValue}, }; use crate::{ @@ -11,7 +11,7 @@ use crate::{ typesystem::{DataType, DataTypeInformation, InternalType, StructSource}, }; -use super::{generators::llvm::Llvm, llvm_index::LlvmTypedIndex}; +use super::{diagnostics::CodegenDiagnostic, generators::llvm::Llvm, llvm_index::LlvmTypedIndex}; /// A convenience macro to call the `cast` function with fewer parameters. /// @@ -88,7 +88,7 @@ pub fn cast<'ctx>( value_type: &DataType, value: BasicValueEnum<'ctx>, annotation: Option<&StatementAnnotation>, -) -> BasicValueEnum<'ctx> { +) -> Result, CodegenDiagnostic> { value.cast(&CastInstructionData::new(llvm, index, llvm_type_index, value_type, target_type, annotation)) } @@ -126,31 +126,48 @@ impl<'ctx, 'cast> CastInstructionData<'ctx, 'cast> { } trait Castable<'ctx, 'cast> { - fn cast(self, cast_data: &CastInstructionData<'ctx, 'cast>) -> BasicValueEnum<'ctx>; + fn cast( + self, + cast_data: &CastInstructionData<'ctx, 'cast>, + ) -> Result, CodegenDiagnostic>; } trait Promotable<'ctx, 'cast> { - fn promote(self, lsize: u32, cast_data: &CastInstructionData<'ctx, 'cast>) -> BasicValueEnum<'ctx>; + fn promote( + self, + lsize: u32, + cast_data: &CastInstructionData<'ctx, 'cast>, + ) -> Result, CodegenDiagnostic>; } trait Truncatable<'ctx, 'cast> { - fn truncate(self, lsize: u32, cast_data: &CastInstructionData<'ctx, 'cast>) -> BasicValueEnum<'ctx>; + fn truncate( + self, + lsize: u32, + cast_data: &CastInstructionData<'ctx, 'cast>, + ) -> Result, CodegenDiagnostic>; } impl<'ctx, 'cast> Castable<'ctx, 'cast> for BasicValueEnum<'ctx> { - fn cast(self, cast_data: &CastInstructionData<'ctx, 'cast>) -> BasicValueEnum<'ctx> { + fn cast( + self, + cast_data: &CastInstructionData<'ctx, 'cast>, + ) -> Result, CodegenDiagnostic> { match self { BasicValueEnum::IntValue(val) => val.cast(cast_data), BasicValueEnum::FloatValue(val) => val.cast(cast_data), BasicValueEnum::PointerValue(val) => val.cast(cast_data), BasicValueEnum::ArrayValue(val) => val.cast(cast_data), - _ => self, + _ => Ok(self), } } } impl<'ctx, 'cast> Castable<'ctx, 'cast> for IntValue<'ctx> { - fn cast(self, cast_data: &CastInstructionData<'ctx, 'cast>) -> BasicValueEnum<'ctx> { + fn cast( + self, + cast_data: &CastInstructionData<'ctx, 'cast>, + ) -> Result, CodegenDiagnostic> { let lsize = cast_data.target_type.get_size_in_bits(cast_data.index); match cast_data.target_type { DataTypeInformation::Integer { .. } => { @@ -167,9 +184,19 @@ impl<'ctx, 'cast> Castable<'ctx, 'cast> for IntValue<'ctx> { DataTypeInformation::Float { .. } => { let float_type = get_llvm_float_type(cast_data.llvm.context, lsize, "Float"); if cast_data.value_type.is_signed_int() { - cast_data.llvm.builder.build_signed_int_to_float(self, float_type, "").into() + cast_data + .llvm + .builder + .build_signed_int_to_float(self, float_type, "") + .map(Into::into) + .map_err(Into::into) } else { - cast_data.llvm.builder.build_unsigned_int_to_float(self, float_type, "").into() + cast_data + .llvm + .builder + .build_unsigned_int_to_float(self, float_type, "") + .map(Into::into) + .map_err(Into::into) } } DataTypeInformation::Pointer { .. } => { @@ -182,7 +209,12 @@ impl<'ctx, 'cast> Castable<'ctx, 'cast> for IntValue<'ctx> { ) }; - cast_data.llvm.builder.build_int_to_ptr(self, associated_type.into_pointer_type(), "").into() + cast_data + .llvm + .builder + .build_int_to_ptr(self, associated_type.into_pointer_type(), "") + .map(Into::into) + .map_err(Into::into) } _ => unreachable!("Cannot cast integer value to {}", cast_data.target_type.get_name()), } @@ -190,7 +222,10 @@ impl<'ctx, 'cast> Castable<'ctx, 'cast> for IntValue<'ctx> { } impl<'ctx, 'cast> Castable<'ctx, 'cast> for FloatValue<'ctx> { - fn cast(self, cast_data: &CastInstructionData<'ctx, 'cast>) -> BasicValueEnum<'ctx> { + fn cast( + self, + cast_data: &CastInstructionData<'ctx, 'cast>, + ) -> Result, CodegenDiagnostic> { let rsize = &cast_data.value_type.get_size_in_bits(cast_data.index); match cast_data.target_type { DataTypeInformation::Float { size: lsize, .. } => { @@ -203,9 +238,19 @@ impl<'ctx, 'cast> Castable<'ctx, 'cast> for FloatValue<'ctx> { DataTypeInformation::Integer { signed, size: lsize, .. } => { let int_type = get_llvm_int_type(cast_data.llvm.context, *lsize, "Integer"); if *signed { - cast_data.llvm.builder.build_float_to_signed_int(self, int_type, "").into() + cast_data + .llvm + .builder + .build_float_to_signed_int(self, int_type, "") + .map(Into::into) + .map_err(Into::into) } else { - cast_data.llvm.builder.build_float_to_unsigned_int(self, int_type, "").into() + cast_data + .llvm + .builder + .build_float_to_unsigned_int(self, int_type, "") + .map(Into::into) + .map_err(Into::into) } } _ => unreachable!("Cannot cast floating-point value to {}", cast_data.target_type.get_name()), @@ -214,13 +259,17 @@ impl<'ctx, 'cast> Castable<'ctx, 'cast> for FloatValue<'ctx> { } impl<'ctx, 'cast> Castable<'ctx, 'cast> for PointerValue<'ctx> { - fn cast(self, cast_data: &CastInstructionData<'ctx, 'cast>) -> BasicValueEnum<'ctx> { + fn cast( + self, + cast_data: &CastInstructionData<'ctx, 'cast>, + ) -> Result, CodegenDiagnostic> { match &cast_data.target_type { DataTypeInformation::Integer { size: lsize, .. } => cast_data .llvm .builder .build_ptr_to_int(self, get_llvm_int_type(cast_data.llvm.context, *lsize, ""), "") - .into(), + .map(Into::into) + .map_err(Into::into), DataTypeInformation::Pointer { .. } => { let Ok(target_ptr_type) = cast_data.llvm_type_index.get_associated_type(cast_data.target_type.get_name()) @@ -232,10 +281,10 @@ impl<'ctx, 'cast> Castable<'ctx, 'cast> for PointerValue<'ctx> { }; if BasicValueEnum::from(self).get_type() != target_ptr_type { // bit-cast necessary - cast_data.llvm.builder.build_bitcast(self, target_ptr_type, "") + cast_data.llvm.builder.build_bit_cast(self, target_ptr_type, "").map_err(Into::into) } else { //this is ok, no cast required - self.into() + Ok(self.into()) } } DataTypeInformation::Struct { @@ -243,12 +292,13 @@ impl<'ctx, 'cast> Castable<'ctx, 'cast> for PointerValue<'ctx> { .. } => { // we are dealing with an auto-deref vla parameter. first we have to deref our array and build the fat pointer - let struct_val = cast_data.llvm.builder.build_load(self, "auto_deref").cast(cast_data); + let struct_val = cast_data.llvm.builder.build_load(self, "auto_deref")?.cast(cast_data)?; // create a pointer to the generated StructValue - let struct_ptr = cast_data.llvm.builder.build_alloca(struct_val.get_type(), "vla_struct_ptr"); - cast_data.llvm.builder.build_store(struct_ptr, struct_val); - struct_ptr.into() + let struct_ptr = + cast_data.llvm.builder.build_alloca(struct_val.get_type(), "vla_struct_ptr")?; + cast_data.llvm.builder.build_store(struct_ptr, struct_val)?; + Ok(struct_ptr.into()) } _ => unreachable!("Cannot cast pointer value to {}", cast_data.target_type.get_name()), } @@ -258,9 +308,12 @@ impl<'ctx, 'cast> Castable<'ctx, 'cast> for PointerValue<'ctx> { impl<'ctx, 'cast> Castable<'ctx, 'cast> for ArrayValue<'ctx> { /// Generates a fat pointer struct for an array if the target type is a VLA, /// otherwise returns the value as is. - fn cast(self, cast_data: &CastInstructionData<'ctx, 'cast>) -> BasicValueEnum<'ctx> { + fn cast( + self, + cast_data: &CastInstructionData<'ctx, 'cast>, + ) -> Result, CodegenDiagnostic> { if !cast_data.target_type.is_vla() { - return self.into(); + return Ok(self.into()); } let builder = &cast_data.llvm.builder; let zero = cast_data.llvm.i32_type().const_zero(); @@ -284,19 +337,15 @@ impl<'ctx, 'cast> Castable<'ctx, 'cast> for ArrayValue<'ctx> { .unwrap_or_else(|| unreachable!("passed array must be in the llvm index")); // gep into the original array. the resulting address will be stored in the VLA struct - let arr_gep = unsafe { builder.build_in_bounds_gep(array_pointer, &[zero, zero], "outer_arr_gep") }; + let arr_gep = unsafe { builder.build_in_bounds_gep(array_pointer, &[zero, zero], "outer_arr_gep")? }; // -- Generate struct & arr_ptr -- let ty = associated_type.into_struct_type(); - let vla_struct = builder.build_alloca(ty, "vla_struct"); + let vla_struct = builder.build_alloca(ty, "vla_struct")?; - let Ok(vla_arr_ptr) = builder.build_struct_gep(vla_struct, 0, "vla_array_gep") else { - unreachable!("Must have a valid, GEP-able fat-pointer struct at this stage") - }; + let vla_arr_ptr = builder.build_struct_gep(vla_struct, 0, "vla_array_gep")?; - let Ok(vla_dimensions_ptr) = builder.build_struct_gep(vla_struct, 1, "vla_dimensions_gep") else { - unreachable!("Must have a valid, GEP-able fat-pointer struct at this stage") - }; + let vla_dimensions_ptr = builder.build_struct_gep(vla_struct, 1, "vla_dimensions_gep")?; // -- Generate dimensions -- let DataTypeInformation::Array { dimensions, .. } = cast_data.value_type else { unreachable!() }; @@ -311,56 +360,77 @@ impl<'ctx, 'cast> Castable<'ctx, 'cast> for ArrayValue<'ctx> { dims.iter().map(|it| cast_data.llvm.i32_type().const_int(*it as u64, true)).collect::>(); let array_value = cast_data.llvm.i32_type().const_array(&dimensions); // FIXME: should be memcopied, but is an rvalue. can only initialize global variables with value types. any other way for alloca'd variables than using store? - builder.build_store(vla_dimensions_ptr, array_value); + builder.build_store(vla_dimensions_ptr, array_value)?; - builder.build_store(vla_arr_ptr, arr_gep); + builder.build_store(vla_arr_ptr, arr_gep)?; - builder.build_load(vla_struct, "") + Ok(builder.build_load(vla_struct, "")?) } } impl<'ctx, 'cast> Promotable<'ctx, 'cast> for IntValue<'ctx> { - fn promote(self, lsize: u32, cast_data: &CastInstructionData<'ctx, 'cast>) -> BasicValueEnum<'ctx> { + fn promote( + self, + lsize: u32, + cast_data: &CastInstructionData<'ctx, 'cast>, + ) -> Result, CodegenDiagnostic> { let llvm_int_type = get_llvm_int_type(cast_data.llvm.context, lsize, "Integer"); - if cast_data.value_type.is_signed_int() { - cast_data.llvm.builder.build_int_s_extend_or_bit_cast(self, llvm_int_type, "") - } else { - cast_data.llvm.builder.build_int_z_extend_or_bit_cast(self, llvm_int_type, "") - } - .into() + //FIXME: This breaks on new inkwell, we cannot cast in initizlizers + if cast_data.llvm.builder.get_insert_block().is_none() { + return Ok(self.as_basic_value_enum()) + }; + let value = + if cast_data.value_type.is_signed_int(){ + cast_data.llvm.builder.build_int_s_extend_or_bit_cast(self, llvm_int_type, "")? + } else { + cast_data.llvm.builder.build_int_z_extend_or_bit_cast(self, llvm_int_type, "")? + }; + Ok(value.into()) } } impl<'ctx, 'cast> Promotable<'ctx, 'cast> for FloatValue<'ctx> { - fn promote(self, lsize: u32, cast_data: &CastInstructionData<'ctx, 'cast>) -> BasicValueEnum<'ctx> { - cast_data + fn promote( + self, + lsize: u32, + cast_data: &CastInstructionData<'ctx, 'cast>, + ) -> Result, CodegenDiagnostic> { + Ok(cast_data .llvm .builder - .build_float_ext(self, get_llvm_float_type(cast_data.llvm.context, lsize, "Float"), "") - .into() + .build_float_ext(self, get_llvm_float_type(cast_data.llvm.context, lsize, "Float"), "")? + .into()) } } impl<'ctx, 'cast> Truncatable<'ctx, 'cast> for IntValue<'ctx> { - fn truncate(self, lsize: u32, cast_data: &CastInstructionData<'ctx, 'cast>) -> BasicValueEnum<'ctx> { - cast_data + fn truncate( + self, + lsize: u32, + cast_data: &CastInstructionData<'ctx, 'cast>, + ) -> Result, CodegenDiagnostic> { + Ok(cast_data .llvm .builder .build_int_truncate_or_bit_cast( self, get_llvm_int_type(cast_data.llvm.context, lsize, "Integer"), "", - ) - .into() + )? + .into()) } } impl<'ctx, 'cast> Truncatable<'ctx, 'cast> for FloatValue<'ctx> { - fn truncate(self, lsize: u32, cast_data: &CastInstructionData<'ctx, 'cast>) -> BasicValueEnum<'ctx> { - cast_data + fn truncate( + self, + lsize: u32, + cast_data: &CastInstructionData<'ctx, 'cast>, + ) -> Result, CodegenDiagnostic> { + Ok(cast_data .llvm .builder - .build_float_trunc(self, get_llvm_float_type(cast_data.llvm.context, lsize, "Float"), "") - .into() + .build_float_trunc(self, get_llvm_float_type(cast_data.llvm.context, lsize, "Float"), "")? + .into()) } } diff --git a/src/index/visitor.rs b/src/index/visitor.rs index 1943824076..e27fdb9118 100644 --- a/src/index/visitor.rs +++ b/src/index/visitor.rs @@ -706,6 +706,7 @@ fn visit_array( }) } + //TODO: that's not a codegen error _ => Err(Diagnostic::codegen_error( "Invalid array definition: RangeStatement expected", it.get_location(),