From da89a642cc024d63b48915dff36c3d399ec5affb Mon Sep 17 00:00:00 2001 From: Michael Haselberger Date: Mon, 22 Apr 2024 15:03:22 +0200 Subject: [PATCH 01/22] init --- .vscode/launch.json | 2 -- .../generators/expression_generator.rs | 24 ++++++++++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index c47ec790137..8d748f23860 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -20,9 +20,7 @@ } }, "args": [ - "--check", "target/demo.st", - "-i","libs/stdlib/iec61131-st/timers.st" ], "cwd": "${workspaceFolder}" }, diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index f28139b1ed6..5c775ce7dc1 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -556,7 +556,29 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { && !matches!(expression.get_stmt(), AstStatement::EmptyStatement { .. }) { { - let assigned_output = self.generate_lvalue(expression)?; + // if bitaccess rhs -> generate lvalue + let assigned_output = if let AstStatement::ReferenceExpr(ReferenceExpr { access: ReferenceAccess::Member(member), base }) = dbg!(expression.get_stmt()) { + let base_value = base.as_ref().map(|it| self.generate_expression_value(it)).transpose()?; + + if let AstStatement::DirectAccess (data) = member.as_ref().get_stmt() { + let (Some(base), Some(base_value)) = (base, base_value) else { + panic!() + }; + dbg!(&self.function_context.unwrap().linking_context.call_name); + let x = self.annotations.get_qualified_name(base).unwrap(); + let y = self.llvm_index.find_loaded_associated_variable_value(x).unwrap(); + + let expr = self.generate_direct_access_expression(base, &base_value, member, &data.access, &data.index); + + + // self.assign_output_value(param_context) + todo!() + } + todo!() + } else { + self.generate_lvalue(expression)? + }; + let assigned_output_type = self.annotations.get_type_or_void(expression, self.index).get_type_information(); From 19e35223c4b5488222849cba3489cce1dcf38ae3 Mon Sep 17 00:00:00 2001 From: Volkan Sagcan Date: Tue, 23 Apr 2024 13:36:23 +0200 Subject: [PATCH 02/22] working for example in github issue --- .../generators/expression_generator.rs | 209 ++++++++++++++---- src/resolver.rs | 2 + 2 files changed, 164 insertions(+), 47 deletions(-) diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index 5c775ce7dc1..4792a56ae9c 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -24,6 +24,7 @@ use inkwell::{ }, AddressSpace, FloatPredicate, IntPredicate, }; +use plc_ast::ast::Assignment; use plc_ast::{ ast::{ flatten_expression_list, AstFactory, AstNode, AstStatement, DirectAccessType, Operator, @@ -65,7 +66,7 @@ struct CallParameterAssignment<'a, 'b> { /// the name of the function we're calling function_name: &'b str, /// the position of the argument in the POU's argument's list - index: u32, + pub index: u32, /// a pointer to the struct instance that carries the call's arguments parameter_struct: PointerValue<'a>, } @@ -533,13 +534,13 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { } fn assign_output_value(&self, param_context: &CallParameterAssignment) -> Result<(), Diagnostic> { + dbg!(¶m_context.index); match param_context.assignment_statement.get_stmt() { AstStatement::OutputAssignment(data) | AstStatement::Assignment(data) => self .generate_explicit_output_assignment( param_context.parameter_struct, param_context.function_name, - &data.left, - &data.right, + ¶m_context.assignment_statement, ), _ => self.generate_output_assignment(param_context), } @@ -556,29 +557,90 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { && !matches!(expression.get_stmt(), AstStatement::EmptyStatement { .. }) { { - // if bitaccess rhs -> generate lvalue - let assigned_output = if let AstStatement::ReferenceExpr(ReferenceExpr { access: ReferenceAccess::Member(member), base }) = dbg!(expression.get_stmt()) { - let base_value = base.as_ref().map(|it| self.generate_expression_value(it)).transpose()?; - - if let AstStatement::DirectAccess (data) = member.as_ref().get_stmt() { - let (Some(base), Some(base_value)) = (base, base_value) else { - panic!() - }; - dbg!(&self.function_context.unwrap().linking_context.call_name); - let x = self.annotations.get_qualified_name(base).unwrap(); - let y = self.llvm_index.find_loaded_associated_variable_value(x).unwrap(); - - let expr = self.generate_direct_access_expression(base, &base_value, member, &data.access, &data.index); - - - // self.assign_output_value(param_context) - todo!() - } - todo!() + let assigned_output = if let (AstStatement::Assignment(data_assignment) + | AstStatement::OutputAssignment(data_assignment)) = + expression.get_stmt() + { + // if bitaccess rhs -> generate lvalue + let assigned_output = if let AstStatement::ReferenceExpr(ReferenceExpr { + access: ReferenceAccess::Member(member), + base, + }) = dbg!(&data_assignment.right.get_stmt()) + { + dbg!(&member); + // LVALUE error_bits + // RVALUE Q + // errro_bits OR Q => res + // store res, error_bits + let base_value_rvalue = + base.as_ref().map(|it| self.generate_expression_value(it)).transpose()?; + + if let AstStatement::DirectAccess(data) = member.as_ref().get_stmt() { + let (Some(base), Some(base_value)) = (base, base_value_rvalue) else { + panic!() + }; + // Data-index: Access Index (e.g, foo.5) + // Data.access: Width (e.g. %X, %W) + // foo(Q => error_bits.5) + // ^ ^^^^^^^^^^ ^ + // rhs lhs index + // 1. Fetch lhs of assignment in llvm index (LVALUE) and load (RVALUE) + // 2. GEP on rhs and load to acquire RVALUE + // 3. call generate_direct_access_index() to get index with consideration of width + // 4. left-shift rhs value with index of step 3 + // 5. RVALUE of step 1 ORed with value of step 4 + // 6. Store result of step 5 into lhs + + // Step 1 + let error_bits_lvalue = self + .llvm_index + .find_loaded_associated_variable_value( + self.annotations.get_qualified_name(base).unwrap(), + ) + .unwrap(); + let error_bits_rvalue = + self.llvm.builder.build_load(error_bits_lvalue, "aaa"); + + // Step 2 + let q_lvalue = self + .llvm + .builder + .build_struct_gep(parameter_struct, index, "xxx") + .unwrap(); + let q_rvalue = self.llvm.builder.build_load(q_lvalue, "yyy"); + + // Step 3 + let lhs_ty = self.get_type_hint_for(base)?.get_type_information(); + let rhs_ty = self.get_type_hint_for(&data_assignment.right)?; + let index = self + .generate_direct_access_index(&data.access, &data.index, &lhs_ty, &rhs_ty) + .unwrap(); + + // Step 4 + let left_shift = + self.llvm.builder.build_left_shift(q_rvalue.into_int_value(), index, ""); + + // Step 5 + let ored = self.llvm.builder.build_or( + error_bits_rvalue.into_int_value(), + left_shift, + "", + ); + + // Step 6 + let res = self.llvm.builder.build_store(error_bits_lvalue, ored); + } else { + unreachable!() + } + } else { + unreachable!() + }; + + assigned_output } else { - self.generate_lvalue(expression)? + todo!(""); + // self.generate_lvalue(expression)? }; - let assigned_output_type = self.annotations.get_type_or_void(expression, self.index).get_type_information(); @@ -593,48 +655,101 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let output_value_type = self.index.get_type_information_or_void(parameter.get_type_name()); - //Special string handling - if (assigned_output_type.is_string() && output_value_type.is_string()) - || (assigned_output_type.is_struct() && output_value_type.is_struct()) - || (assigned_output_type.is_array() && output_value_type.is_array()) - { - self.generate_string_store( - assigned_output, - assigned_output_type, - expression.get_location(), - output, - output_value_type, - parameter.source_location.clone(), - )?; - } else { - let output_value = builder.build_load(output, ""); - builder.build_store(assigned_output, output_value); - } + // //Special string handling + // if (assigned_output_type.is_string() && output_value_type.is_string()) + // || (assigned_output_type.is_struct() && output_value_type.is_struct()) + // || (assigned_output_type.is_array() && output_value_type.is_array()) + // { + // self.generate_string_store( + // assigned_output.get_basic_value_enum().into_pointer_value(), + // assigned_output_type, + // expression.get_location(), + // output, + // output_value_type, + // parameter.source_location.clone(), + // )?; + // } else { + // let output_value = builder.build_load(output, ""); + // builder.build_store( + // assigned_output.get_basic_value_enum().into_pointer_value(), + // output_value, + // ); + // } } } } Ok(()) } + /// generates a direct-access expression like `x.%B4` + /// - `qualifier` the qualifier statement (see `x` above) + /// - `qualifier_value` the generated value of the qualifier + /// - `member` the member AstStatement (see `%B4`above) + /// - `access` the type of access (see `B` above) + fn temp( + &self, + qualifier: &AstNode, + qualifier_value: &ExpressionValue<'ink>, + member: &AstNode, + access: &DirectAccessType, + index: &AstNode, + ) -> Result, Diagnostic> { + todo!(); + // 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", + // ); + // //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 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), "") + // } else { + // value + // }; + // + // Ok(ExpressionValue::RValue(result.as_basic_value_enum())) + } + fn generate_explicit_output_assignment( &self, parameter_struct: PointerValue<'ink>, function_name: &str, - left: &AstNode, - right: &AstNode, + assignment: &AstNode, ) -> Result<(), Diagnostic> { - if let Some(StatementAnnotation::Variable { qualified_name, .. }) = self.annotations.get(left) { + let (AstStatement::OutputAssignment(Assignment { left, right }) + | AstStatement::Assignment(Assignment { left, right })) = &assignment.stmt + else { + todo!() + }; + + if let Some(StatementAnnotation::Variable { qualified_name, .. }) = self.annotations.get(&left) { let parameter = self .index .find_fully_qualified_variable(qualified_name) .ok_or_else(|| Diagnostic::unresolved_reference(qualified_name, left.get_location()))?; let index = parameter.get_location_in_parent(); - self.assign_output_value(&CallParameterAssignment { - assignment_statement: right, + + self.generate_output_assignment(&CallParameterAssignment { + assignment_statement: assignment, function_name, index, parameter_struct, - })? + }); }; Ok(()) } diff --git a/src/resolver.rs b/src/resolver.rs index 2d5e714671f..5ab40242ad8 100644 --- a/src/resolver.rs +++ b/src/resolver.rs @@ -548,6 +548,8 @@ pub trait AnnotationMap { fn get_qualified_name(&self, s: &AstNode) -> Option<&str> { match self.get(s) { Some(StatementAnnotation::Function { qualified_name, .. }) => Some(qualified_name.as_str()), + Some(StatementAnnotation::Variable { qualified_name, .. }) => Some(qualified_name.as_str()), + //Some(StatementAnnotation::Program { qualified_name, .. }) => Some(qualified_name.as_str()), // TODO: Check if this breaks tests _ => self.get_call_name(s), } } From 9a9fe84665de6d61247c901aafbb613e18473fc9 Mon Sep 17 00:00:00 2001 From: Volkan Sagcan Date: Tue, 23 Apr 2024 14:51:49 +0200 Subject: [PATCH 03/22] Add tests --- .../generators/expression_generator.rs | 25 +-- src/codegen/generators/statement_generator.rs | 5 + src/codegen/tests/directaccess_test.rs | 153 ++++++++++++++++++ src/resolver.rs | 7 +- 4 files changed, 175 insertions(+), 15 deletions(-) diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index 4792a56ae9c..f79a35b8087 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -536,6 +536,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { fn assign_output_value(&self, param_context: &CallParameterAssignment) -> Result<(), Diagnostic> { dbg!(¶m_context.index); match param_context.assignment_statement.get_stmt() { + // TODO: AstStatement::Assignment should not be a part of this? AstStatement::OutputAssignment(data) | AstStatement::Assignment(data) => self .generate_explicit_output_assignment( param_context.parameter_struct, @@ -628,7 +629,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { ); // Step 6 - let res = self.llvm.builder.build_store(error_bits_lvalue, ored); + let _ = self.llvm.builder.build_store(error_bits_lvalue, ored); } else { unreachable!() } @@ -688,17 +689,17 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { /// - `access` the type of access (see `B` above) fn temp( &self, - qualifier: &AstNode, - qualifier_value: &ExpressionValue<'ink>, - member: &AstNode, - access: &DirectAccessType, - index: &AstNode, + _qualifier: &AstNode, + _qualifier_value: &ExpressionValue<'ink>, + _member: &AstNode, + _access: &DirectAccessType, + _index: &AstNode, ) -> Result, Diagnostic> { todo!(); // 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 @@ -714,14 +715,14 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { // self.llvm_index.get_associated_type(datatype.get_name())?.into_int_type(), // "", // ); - // + // // 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), "") // } else { // value // }; - // + // // Ok(ExpressionValue::RValue(result.as_basic_value_enum())) } @@ -731,8 +732,8 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { function_name: &str, assignment: &AstNode, ) -> Result<(), Diagnostic> { - let (AstStatement::OutputAssignment(Assignment { left, right }) - | AstStatement::Assignment(Assignment { left, right })) = &assignment.stmt + let (AstStatement::OutputAssignment(Assignment { left, right: _ }) + | AstStatement::Assignment(Assignment { left, right: _ })) = &assignment.stmt else { todo!() }; @@ -744,7 +745,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { .ok_or_else(|| Diagnostic::unresolved_reference(qualified_name, left.get_location()))?; let index = parameter.get_location_in_parent(); - self.generate_output_assignment(&CallParameterAssignment { + let _ = self.generate_output_assignment(&CallParameterAssignment { assignment_statement: assignment, function_name, index, diff --git a/src/codegen/generators/statement_generator.rs b/src/codegen/generators/statement_generator.rs index 513bc167cff..6c52fb06bf0 100644 --- a/src/codegen/generators/statement_generator.rs +++ b/src/codegen/generators/statement_generator.rs @@ -288,6 +288,11 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { //TODO : Validation let exp_gen = self.create_expr_generator(); + // STRUCT foo + // x : BIT + // END_STRUCT + // foo, foo.x + // given a complex direct-access assignemnt: a.b.c.%W3,%X1 // we want to deconstruct the targe-part (a.b.c) and the direct-access sequence (%W3.%X1) let Some((target, access_sequence)) = collect_base_and_direct_access_for_assignment(left_statement) diff --git a/src/codegen/tests/directaccess_test.rs b/src/codegen/tests/directaccess_test.rs index df69af8891a..83e9ca37e75 100644 --- a/src/codegen/tests/directaccess_test.rs +++ b/src/codegen/tests/directaccess_test.rs @@ -1,3 +1,4 @@ +use insta::assert_snapshot; // Copyright (c) 2020 Ghaith Hachem and Mathias Rieder use crate::test_utils::tests::codegen; @@ -112,3 +113,155 @@ fn qualified_reference_assignment() { ); insta::assert_snapshot!(prog); } + +#[test] +fn temp_explicit() { + let ir = codegen( + r" + FUNCTION_BLOCK FOO + VAR_OUTPUT + Q : BOOL; + END_VAR + END_FUNCTION_BLOCK + + FUNCTION main : DINT + VAR + error_bits : BYTE; + f : FOO; + END_VAR + + f(Q => error_bits.0); + END_FUNCTION + ", + ); + + // TODO: The OR here is wrong, what if foo(Q => bits.%X) where Q is false and the is true; + // the bit currently stay at 1 but should be 0 + insta::assert_snapshot!(ir, @r###" + ; ModuleID = 'main' + source_filename = "main" + + %FOO = type { i8 } + + @__FOO__init = unnamed_addr constant %FOO zeroinitializer + + define void @FOO(%FOO* %0) section "fn-FOO:v[u8]" { + entry: + %Q = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0 + ret void + } + + define i32 @main() section "fn-main:i32" { + entry: + %main = alloca i32, align 4 + %error_bits = alloca i8, align 1 + %f = alloca %FOO, align 8 + store i8 0, i8* %error_bits, align 1 + %0 = bitcast %FOO* %f to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false) + store i32 0, i32* %main, align 4 + call void @FOO(%FOO* %f) + %aaa = load i8, i8* %error_bits, align 1 + %xxx = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 + %yyy = load i8, i8* %xxx, align 1 + %1 = shl i8 %yyy, 0 + %2 = or i8 %aaa, %1 + store i8 %2, i8* %error_bits, align 1 + %3 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 + %main_ret = load i32, i32* %main, align 4 + ret i32 %main_ret + } + + ; Function Attrs: argmemonly nofree nounwind willreturn + declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0 + + attributes #0 = { argmemonly nofree nounwind willreturn } + "###); +} + +#[test] +fn temp_implicit() { + let ir = codegen( + r" + FUNCTION_BLOCK FOO + VAR_OUTPUT + Q : BOOL; + END_VAR + END_FUNCTION_BLOCK + + FUNCTION main : DINT + VAR + error_bits : BYTE; + f : FOO; + END_VAR + + f(error_bits.0); + END_FUNCTION + ", + ); + + assert_snapshot!(ir, @r""); +} + +#[test] +fn temp_output_and_normal_assignments() { + let ir = codegen( + r" + FUNCTION_BLOCK FOO + VAR_INPUT + X : BOOL; + END_VAR + VAR_OUTPUT + Y : BOOL; + END_VAR + END_FUNCTION_BLOCK + + FUNCTION main : DINT + VAR + error_bits : BYTE; + f : FOO; + END_VAR + + f(X := error_bits.0, Y => error_bits.0); + f(Y => error_bits.0, x := error_bits.0); + f(error_bits.0, error_bits.0); + f(X := error_bits.0, Y =>); + END_FUNCTION + ", + ); + + assert_snapshot!(ir, @r""); +} + +// TODO: Add correctness tests +#[test] +fn temp_complex_bit_access() { + let ir = codegen( + r" + TYPE foo_struct : STRUCT + bar : bar_struct; + END_STRUCT END_TYPE + + TYPE bar_struct : STRUCT + baz : LWORD; + END_STRUCT END_TYPE + + FUNCTION_BLOCK QUUX + VAR_OUTPUT + Q : BOOL; + END_VAR + END_FUNCTION_BLOCK + + FUNCTION main : DINT + VAR + foo : foo_struct; + f : QUUX; + END_VAR + + f(Q => foo.bar.baz.%W3.%X2); + END_FUNCTION + ", + ); + + assert_snapshot!(ir, @r""); +} diff --git a/src/resolver.rs b/src/resolver.rs index 5ab40242ad8..abb5f0a7fd0 100644 --- a/src/resolver.rs +++ b/src/resolver.rs @@ -547,9 +547,10 @@ pub trait AnnotationMap { fn get_qualified_name(&self, s: &AstNode) -> Option<&str> { match self.get(s) { - Some(StatementAnnotation::Function { qualified_name, .. }) => Some(qualified_name.as_str()), - Some(StatementAnnotation::Variable { qualified_name, .. }) => Some(qualified_name.as_str()), - //Some(StatementAnnotation::Program { qualified_name, .. }) => Some(qualified_name.as_str()), // TODO: Check if this breaks tests + Some(StatementAnnotation::Function { qualified_name, .. }) + | Some(StatementAnnotation::Variable { qualified_name, .. }) + | Some(StatementAnnotation::Program { qualified_name, .. }) => Some(qualified_name.as_str()), + _ => self.get_call_name(s), } } From 483ba0730c1626d7d3492579a0d06d67757fc78d Mon Sep 17 00:00:00 2001 From: Volkan Sagcan Date: Tue, 23 Apr 2024 15:36:36 +0200 Subject: [PATCH 04/22] pain --- .../generators/expression_generator.rs | 158 +++++++++++++++--- 1 file changed, 138 insertions(+), 20 deletions(-) diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index f79a35b8087..358d7a463a5 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -10,6 +10,7 @@ use crate::{ VariableIndexEntry, VariableType, }, resolver::{AnnotationMap, AstAnnotations, StatementAnnotation}, + typesystem, typesystem::{ is_same_type_class, DataType, DataTypeInformation, DataTypeInformationProvider, Dimension, StringEncoding, VarArgs, DINT_TYPE, INT_SIZE, INT_TYPE, LINT_TYPE, @@ -547,6 +548,118 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { } } + fn temp_xxx( + &self, + left_lvalue: PointerValue, + left_statement: &AstNode, + right_statement: &AstNode, + ) -> Result<(), Diagnostic> { + /// when generating an assignment to a direct-access (e.g. a.b.c.%W3.%X2 := 2;) + /// we want to deconstruct the sequence into the base-statement (a.b.c) and the sequence + /// of direct-access commands (vec![%W3, %X2]) + fn collect_base_and_direct_access_for_assignment( + left_statement: &AstNode, + ) -> Option<(&AstNode, Vec<&AstNode>)> { + let mut current = Some(left_statement); + let mut access_sequence = Vec::new(); + while let Some(AstStatement::ReferenceExpr(ReferenceExpr { + access: ReferenceAccess::Member(m), + base, + })) = current.map(|it| it.get_stmt()) + { + if matches!(m.get_stmt(), AstStatement::DirectAccess { .. }) { + access_sequence.insert(0, m.as_ref()); + current = base.as_deref(); + } else { + break; + } + } + current.zip(Some(access_sequence)) + } + //TODO : Validation + // STRUCT foo + // x : BIT + // END_STRUCT + // foo, foo.x + + // given a complex direct-access assignemnt: a.b.c.%W3,%X1 + // we want to deconstruct the targe-part (a.b.c) and the direct-access sequence (%W3.%X1) + let Some((target, access_sequence)) = collect_base_and_direct_access_for_assignment(left_statement) + else { + unreachable!("Invalid direct-access expression: {left_statement:#?}") + }; + + let left_type = self.get_type_hint_for(target)?; + let right_type = self.get_type_hint_for(right_statement)?; + + if let Some((element, direct_access)) = access_sequence.split_first() { + let mut rhs = if let AstStatement::DirectAccess(data, ..) = element.get_stmt() { + self.generate_direct_access_index( + &data.access, + &data.index, + right_type.get_type_information(), + left_type, + ) + } else { + //TODO: using the global context we could get a slice here + Err(Diagnostic::new(format!("{element:?} not a direct access")) + .with_error_code("E055") + .with_location(element.get_location())) + }?; + for element in direct_access { + let rhs_next = if let AstStatement::DirectAccess(data, ..) = element.get_stmt() { + self.generate_direct_access_index( + &data.access, + &data.index, + right_type.get_type_information(), + left_type, + ) + } else { + //TODO: using the global context we could get a slice here + Err(Diagnostic::new(&format!("{element:?} not a direct access")) + .with_error_code("E055") + .with_location(element.get_location())) + }?; + rhs = self.llvm.builder.build_int_add(rhs, rhs_next, ""); + } + + //Build mask for the index + //Get the target bit type as all ones + let rhs_type = self.llvm_index.get_associated_type(right_type.get_name())?.into_int_type(); + 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_lvalue.as_basic_value_enum().into_int_value().get_type(), + "ext", + ); + //Position the ones in their correct locations + let shifted_mask = self.llvm.builder.build_left_shift(extended_mask, rhs, "shift"); + //Invert the mask + let mask = self.llvm.builder.build_not(shifted_mask, "invert"); + //And the result with the mask to erase the set bits at the target location + let and_value = self.llvm.builder.build_and( + left_lvalue.as_basic_value_enum().into_int_value(), + mask, + "erase", + ); + + //Generate an expression for the right size + let right = self.generate_expression(right_statement)?; + //Cast the right side to the left side type + let lhs = cast_if_needed!(self, left_type, right_type, right, None).into_int_value(); + //Shift left by the direct access + let value = self.llvm.builder.build_left_shift(lhs, rhs, "value"); + + //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_lvalue, or_value); + } else { + unreachable!(); + } + Ok(()) + } + fn generate_output_assignment(&self, param_context: &CallParameterAssignment) -> Result<(), Diagnostic> { let builder = &self.llvm.builder; let expression = param_context.assignment_statement; @@ -610,26 +723,31 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { .unwrap(); let q_rvalue = self.llvm.builder.build_load(q_lvalue, "yyy"); - // Step 3 - let lhs_ty = self.get_type_hint_for(base)?.get_type_information(); - let rhs_ty = self.get_type_hint_for(&data_assignment.right)?; - let index = self - .generate_direct_access_index(&data.access, &data.index, &lhs_ty, &rhs_ty) - .unwrap(); - - // Step 4 - let left_shift = - self.llvm.builder.build_left_shift(q_rvalue.into_int_value(), index, ""); - - // Step 5 - let ored = self.llvm.builder.build_or( - error_bits_rvalue.into_int_value(), - left_shift, - "", - ); - - // Step 6 - let _ = self.llvm.builder.build_store(error_bits_lvalue, ored); + // lhs = lvalue + // rhs = astnode + self.temp_xxx(q_lvalue, &data_assignment.right, &data_assignment.left)?; + + // + // // Step 3 + // let lhs_ty = self.get_type_hint_for(base)?.get_type_information(); + // let rhs_ty = self.get_type_hint_for(&data_assignment.right)?; + // let index = self + // .generate_direct_access_index(&data.access, &data.index, &lhs_ty, &rhs_ty) + // .unwrap(); + // + // // Step 4 + // let left_shift = + // self.llvm.builder.build_left_shift(q_rvalue.into_int_value(), index, ""); + // + // // Step 5 + // let ored = self.llvm.builder.build_or( + // error_bits_rvalue.into_int_value(), + // left_shift, + // "", + // ); + // + // // Step 6 + // let _ = self.llvm.builder.build_store(error_bits_lvalue, ored); } else { unreachable!() } From 88ba4de3003ac2d2fe8aec7f6465452823550c36 Mon Sep 17 00:00:00 2001 From: Volkan Sagcan Date: Wed, 24 Apr 2024 11:04:48 +0200 Subject: [PATCH 05/22] rip --- .../generators/expression_generator.rs | 122 ++++++------------ 1 file changed, 36 insertions(+), 86 deletions(-) diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index 358d7a463a5..008774d0528 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -10,7 +10,6 @@ use crate::{ VariableIndexEntry, VariableType, }, resolver::{AnnotationMap, AstAnnotations, StatementAnnotation}, - typesystem, typesystem::{ is_same_type_class, DataType, DataTypeInformation, DataTypeInformationProvider, Dimension, StringEncoding, VarArgs, DINT_TYPE, INT_SIZE, INT_TYPE, LINT_TYPE, @@ -36,6 +35,7 @@ use plc_ast::{ use plc_diagnostics::diagnostics::{Diagnostic, INTERNAL_LLVM_ERROR}; use plc_source::source_location::SourceLocation; use plc_util::convention::qualified_name; +use std::fmt::Pointer; use std::{collections::HashSet, vec}; use super::{llvm::Llvm, statement_generator::FunctionContext, ADDRESS_SPACE_CONST, ADDRESS_SPACE_GENERIC}; @@ -551,6 +551,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { fn temp_xxx( &self, left_lvalue: PointerValue, + right_lvalue: PointerValue, left_statement: &AstNode, right_statement: &AstNode, ) -> Result<(), Diagnostic> { @@ -593,7 +594,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let right_type = self.get_type_hint_for(right_statement)?; if let Some((element, direct_access)) = access_sequence.split_first() { - let mut rhs = if let AstStatement::DirectAccess(data, ..) = element.get_stmt() { + let mut access_index = if let AstStatement::DirectAccess(data, ..) = element.get_stmt() { self.generate_direct_access_index( &data.access, &data.index, @@ -620,40 +621,36 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { .with_error_code("E055") .with_location(element.get_location())) }?; - rhs = self.llvm.builder.build_int_add(rhs, rhs_next, ""); + access_index = self.llvm.builder.build_int_add(access_index, rhs_next, ""); } //Build mask for the index //Get the target bit type as all ones - let rhs_type = self.llvm_index.get_associated_type(right_type.get_name())?.into_int_type(); + let rhs_type = self.llvm_index.get_associated_type(right_type.get_name())?.into_int_type(); //FIXME: we already have the lvalue -> can get type after loading let ones = rhs_type.const_all_ones(); + let left_value = self.llvm.builder.build_load(left_lvalue, ""); //Extend the mask to the target type - let extended_mask = self.llvm.builder.build_int_z_extend( - ones, - left_lvalue.as_basic_value_enum().into_int_value().get_type(), - "ext", - ); + let extended_mask = + self.llvm.builder.build_int_z_extend(ones, left_value.into_int_value().get_type(), "ext"); //Position the ones in their correct locations - let shifted_mask = self.llvm.builder.build_left_shift(extended_mask, rhs, "shift"); + let shifted_mask = self.llvm.builder.build_left_shift(extended_mask, access_index, "shift"); //Invert the mask let mask = self.llvm.builder.build_not(shifted_mask, "invert"); //And the result with the mask to erase the set bits at the target location - let and_value = self.llvm.builder.build_and( - left_lvalue.as_basic_value_enum().into_int_value(), - mask, - "erase", - ); + let and_value = self.llvm.builder.build_and(left_value.into_int_value(), mask, "erase"); //Generate an expression for the right size - let right = self.generate_expression(right_statement)?; + // let right = self.generate_expression(right_statement).unwrap(); //fixme: propagating with ? does not seem to work?! + + let right = self.llvm.builder.build_load(right_lvalue, "aaa"); //Cast the right side to the left side type let lhs = cast_if_needed!(self, left_type, right_type, right, None).into_int_value(); //Shift left by the direct access - let value = self.llvm.builder.build_left_shift(lhs, rhs, "value"); + let value = self.llvm.builder.build_left_shift(lhs, access_index, "value"); //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_lvalue, or_value); + self.llvm.builder.build_store(right_lvalue, or_value); } else { unreachable!(); } @@ -679,13 +676,8 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let assigned_output = if let AstStatement::ReferenceExpr(ReferenceExpr { access: ReferenceAccess::Member(member), base, - }) = dbg!(&data_assignment.right.get_stmt()) + }) = &data_assignment.right.get_stmt() { - dbg!(&member); - // LVALUE error_bits - // RVALUE Q - // errro_bits OR Q => res - // store res, error_bits let base_value_rvalue = base.as_ref().map(|it| self.generate_expression_value(it)).transpose()?; @@ -712,20 +704,22 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { self.annotations.get_qualified_name(base).unwrap(), ) .unwrap(); - let error_bits_rvalue = - self.llvm.builder.build_load(error_bits_lvalue, "aaa"); // Step 2 let q_lvalue = self .llvm .builder - .build_struct_gep(parameter_struct, index, "xxx") + .build_struct_gep(parameter_struct, index, "bbb") .unwrap(); - let q_rvalue = self.llvm.builder.build_load(q_lvalue, "yyy"); // lhs = lvalue // rhs = astnode - self.temp_xxx(q_lvalue, &data_assignment.right, &data_assignment.left)?; + self.temp_xxx( + q_lvalue, + error_bits_lvalue, + &data_assignment.right, + &data_assignment.left, + )?; // // // Step 3 @@ -760,19 +754,19 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { todo!(""); // self.generate_lvalue(expression)? }; - - let assigned_output_type = - self.annotations.get_type_or_void(expression, self.index).get_type_information(); - - let output = builder.build_struct_gep(parameter_struct, index, "").map_err(|_| { - Diagnostic::codegen_error( - format!("Cannot build generate parameter: {parameter:#?}"), - parameter.source_location.clone(), - ) - })?; - - let output_value_type = - self.index.get_type_information_or_void(parameter.get_type_name()); + // + // let assigned_output_type = + // self.annotations.get_type_or_void(expression, self.index).get_type_information(); + // + // let output = builder.build_struct_gep(parameter_struct, index, "").map_err(|_| { + // Diagnostic::codegen_error( + // format!("Cannot build generate parameter: {parameter:#?}"), + // parameter.source_location.clone(), + // ) + // })?; + // + // let output_value_type = + // self.index.get_type_information_or_void(parameter.get_type_name()); // //Special string handling // if (assigned_output_type.is_string() && output_value_type.is_string()) @@ -800,50 +794,6 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { Ok(()) } - /// generates a direct-access expression like `x.%B4` - /// - `qualifier` the qualifier statement (see `x` above) - /// - `qualifier_value` the generated value of the qualifier - /// - `member` the member AstStatement (see `%B4`above) - /// - `access` the type of access (see `B` above) - fn temp( - &self, - _qualifier: &AstNode, - _qualifier_value: &ExpressionValue<'ink>, - _member: &AstNode, - _access: &DirectAccessType, - _index: &AstNode, - ) -> Result, Diagnostic> { - todo!(); - // 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", - // ); - // //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 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), "") - // } else { - // value - // }; - // - // Ok(ExpressionValue::RValue(result.as_basic_value_enum())) - } - fn generate_explicit_output_assignment( &self, parameter_struct: PointerValue<'ink>, From afe00ab59b980ec24f5c24ff48fee96c7cc30ada Mon Sep 17 00:00:00 2001 From: Volkan Sagcan Date: Wed, 24 Apr 2024 15:04:48 +0200 Subject: [PATCH 06/22] working state --- .../generators/expression_generator.rs | 86 ++++++------------- src/codegen/generators/statement_generator.rs | 1 + 2 files changed, 29 insertions(+), 58 deletions(-) diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index 008774d0528..a6bc2bfd53f 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -10,6 +10,7 @@ use crate::{ VariableIndexEntry, VariableType, }, resolver::{AnnotationMap, AstAnnotations, StatementAnnotation}, + typesystem, typesystem::{ is_same_type_class, DataType, DataTypeInformation, DataTypeInformationProvider, Dimension, StringEncoding, VarArgs, DINT_TYPE, INT_SIZE, INT_TYPE, LINT_TYPE, @@ -577,14 +578,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { } current.zip(Some(access_sequence)) } - //TODO : Validation - // STRUCT foo - // x : BIT - // END_STRUCT - // foo, foo.x - - // given a complex direct-access assignemnt: a.b.c.%W3,%X1 - // we want to deconstruct the targe-part (a.b.c) and the direct-access sequence (%W3.%X1) + let Some((target, access_sequence)) = collect_base_and_direct_access_for_assignment(left_statement) else { unreachable!("Invalid direct-access expression: {left_statement:#?}") @@ -593,8 +587,21 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let left_type = self.get_type_hint_for(target)?; let right_type = self.get_type_hint_for(right_statement)?; + //special case if we deal with a single bit, then we need to switch to a faked u1 type + let right_type = + if let DataTypeInformation::Integer { semantic_size: Some(typesystem::U1_SIZE), .. } = + *right_type.get_type_information() + { + self.index.get_type_or_panic(typesystem::U1_TYPE) + } else { + right_type + }; + + let left_value = self.llvm.builder.build_load(left_lvalue, "").into_int_value(); + + //Build index if let Some((element, direct_access)) = access_sequence.split_first() { - let mut access_index = if let AstStatement::DirectAccess(data, ..) = element.get_stmt() { + let mut index = if let AstStatement::DirectAccess(data, ..) = element.get_stmt() { self.generate_direct_access_index( &data.access, &data.index, @@ -621,39 +628,36 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { .with_error_code("E055") .with_location(element.get_location())) }?; - access_index = self.llvm.builder.build_int_add(access_index, rhs_next, ""); + index = self.llvm.builder.build_int_add(index, rhs_next, ""); } - //Build mask for the index //Get the target bit type as all ones - let rhs_type = self.llvm_index.get_associated_type(right_type.get_name())?.into_int_type(); //FIXME: we already have the lvalue -> can get type after loading + let rhs_type = self.llvm_index.get_associated_type(right_type.get_name())?.into_int_type(); let ones = rhs_type.const_all_ones(); - let left_value = self.llvm.builder.build_load(left_lvalue, ""); + //Extend the mask to the target type - let extended_mask = - self.llvm.builder.build_int_z_extend(ones, left_value.into_int_value().get_type(), "ext"); + let extended_mask = self.llvm.builder.build_int_z_extend(ones, left_value.get_type(), "ext"); //Position the ones in their correct locations - let shifted_mask = self.llvm.builder.build_left_shift(extended_mask, access_index, "shift"); + let shifted_mask = self.llvm.builder.build_left_shift(extended_mask, index, "shift"); //Invert the mask let mask = self.llvm.builder.build_not(shifted_mask, "invert"); //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.into_int_value(), mask, "erase"); + let and_value = self.llvm.builder.build_and(left_value, mask, "erase"); //Generate an expression for the right size - // let right = self.generate_expression(right_statement).unwrap(); //fixme: propagating with ? does not seem to work?! - - let right = self.llvm.builder.build_load(right_lvalue, "aaa"); + let right = self.llvm.builder.build_load(right_lvalue, ""); //Cast the right side to the left side type let lhs = cast_if_needed!(self, left_type, right_type, right, None).into_int_value(); //Shift left by the direct access - let value = self.llvm.builder.build_left_shift(lhs, access_index, "value"); + let value = self.llvm.builder.build_left_shift(lhs, index, "value"); //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(right_lvalue, or_value); + self.llvm.builder.build_store(left_lvalue, or_value); } else { - unreachable!(); + unreachable!() } + Ok(()) } @@ -685,18 +689,6 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let (Some(base), Some(base_value)) = (base, base_value_rvalue) else { panic!() }; - // Data-index: Access Index (e.g, foo.5) - // Data.access: Width (e.g. %X, %W) - // foo(Q => error_bits.5) - // ^ ^^^^^^^^^^ ^ - // rhs lhs index - // 1. Fetch lhs of assignment in llvm index (LVALUE) and load (RVALUE) - // 2. GEP on rhs and load to acquire RVALUE - // 3. call generate_direct_access_index() to get index with consideration of width - // 4. left-shift rhs value with index of step 3 - // 5. RVALUE of step 1 ORed with value of step 4 - // 6. Store result of step 5 into lhs - // Step 1 let error_bits_lvalue = self .llvm_index @@ -715,33 +707,11 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { // lhs = lvalue // rhs = astnode self.temp_xxx( - q_lvalue, error_bits_lvalue, + q_lvalue, &data_assignment.right, &data_assignment.left, )?; - - // - // // Step 3 - // let lhs_ty = self.get_type_hint_for(base)?.get_type_information(); - // let rhs_ty = self.get_type_hint_for(&data_assignment.right)?; - // let index = self - // .generate_direct_access_index(&data.access, &data.index, &lhs_ty, &rhs_ty) - // .unwrap(); - // - // // Step 4 - // let left_shift = - // self.llvm.builder.build_left_shift(q_rvalue.into_int_value(), index, ""); - // - // // Step 5 - // let ored = self.llvm.builder.build_or( - // error_bits_rvalue.into_int_value(), - // left_shift, - // "", - // ); - // - // // Step 6 - // let _ = self.llvm.builder.build_store(error_bits_lvalue, ored); } else { unreachable!() } diff --git a/src/codegen/generators/statement_generator.rs b/src/codegen/generators/statement_generator.rs index 6c52fb06bf0..3158ce28bc6 100644 --- a/src/codegen/generators/statement_generator.rs +++ b/src/codegen/generators/statement_generator.rs @@ -362,6 +362,7 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { let and_value = self.llvm.builder.build_and(left_value, mask, "erase"); //Generate an expression for the right size + //TODO: debug on master let right = exp_gen.generate_expression(right_statement)?; //Cast the right side to the left side type let lhs = cast_if_needed!(self, left_type, right_type, right, None).into_int_value(); From a25097a485a3a642ffe18051348fa7b5cd4ca779 Mon Sep 17 00:00:00 2001 From: Volkan Sagcan Date: Thu, 25 Apr 2024 15:55:03 +0200 Subject: [PATCH 07/22] working state --- compiler/plc_ast/src/ast.rs | 4 + .../generators/expression_generator.rs | 261 ++++++++++-------- src/codegen/tests/directaccess_test.rs | 191 +++++++------ src/index.rs | 6 + 4 files changed, 265 insertions(+), 197 deletions(-) diff --git a/compiler/plc_ast/src/ast.rs b/compiler/plc_ast/src/ast.rs index 83a218d5ecd..e897112799d 100644 --- a/compiler/plc_ast/src/ast.rs +++ b/compiler/plc_ast/src/ast.rs @@ -855,6 +855,10 @@ impl AstNode { matches!(self.stmt, AstStatement::EmptyStatement(..)) } + pub fn is_assignment(&self) -> bool { + matches!(self.stmt, AstStatement::Assignment(..)) + } + pub fn is_reference(&self) -> bool { matches!(self.stmt, AstStatement::ReferenceExpr(..)) } diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index a6bc2bfd53f..b9e606e2e80 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -1,21 +1,6 @@ -// Copyright (c) 2020 Ghaith Hachem and Mathias Rieder -use crate::{ - codegen::{ - debug::{Debug, DebugBuilderEnum}, - llvm_index::LlvmTypedIndex, - llvm_typesystem::{cast_if_needed, get_llvm_int_type}, - }, - index::{ - const_expressions::ConstId, ArgumentType, ImplementationIndexEntry, Index, PouIndexEntry, - VariableIndexEntry, VariableType, - }, - resolver::{AnnotationMap, AstAnnotations, StatementAnnotation}, - typesystem, - typesystem::{ - is_same_type_class, DataType, DataTypeInformation, DataTypeInformationProvider, Dimension, - StringEncoding, VarArgs, DINT_TYPE, INT_SIZE, INT_TYPE, LINT_TYPE, - }, -}; +use std::fmt::Pointer; +use std::{collections::HashSet, vec}; + use inkwell::{ builder::Builder, types::{BasicType, BasicTypeEnum}, @@ -25,6 +10,7 @@ use inkwell::{ }, AddressSpace, FloatPredicate, IntPredicate, }; + use plc_ast::ast::Assignment; use plc_ast::{ ast::{ @@ -36,10 +22,28 @@ use plc_ast::{ use plc_diagnostics::diagnostics::{Diagnostic, INTERNAL_LLVM_ERROR}; use plc_source::source_location::SourceLocation; use plc_util::convention::qualified_name; -use std::fmt::Pointer; -use std::{collections::HashSet, vec}; + +// Copyright (c) 2020 Ghaith Hachem and Mathias Rieder +use crate::{ + codegen::{ + debug::{Debug, DebugBuilderEnum}, + llvm_index::LlvmTypedIndex, + llvm_typesystem::{cast_if_needed, get_llvm_int_type}, + }, + index::{ + const_expressions::ConstId, ArgumentType, ImplementationIndexEntry, Index, PouIndexEntry, + VariableIndexEntry, VariableType, + }, + resolver::{AnnotationMap, AstAnnotations, StatementAnnotation}, + typesystem, + typesystem::{ + is_same_type_class, DataType, DataTypeInformation, DataTypeInformationProvider, Dimension, + StringEncoding, VarArgs, DINT_TYPE, INT_SIZE, INT_TYPE, LINT_TYPE, + }, +}; use super::{llvm::Llvm, statement_generator::FunctionContext, ADDRESS_SPACE_CONST, ADDRESS_SPACE_GENERIC}; + /// the generator for expressions pub struct ExpressionCodeGenerator<'a, 'b> { pub llvm: &'b Llvm<'a>, @@ -418,8 +422,8 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { // find the pou we're calling let pou = self.annotations.get_call_name(operator).zip(self.annotations.get_qualified_name(operator)) .and_then(|(call_name, qualified_name)| self.index.find_pou(call_name) - // for some functions (builtins) the call name does not exist in the index, we try to call with the originally defined generic functions - .or_else(|| self.index.find_pou(qualified_name))) + // for some functions (builtins) the call name does not exist in the index, we try to call with the originally defined generic functions + .or_else(|| self.index.find_pou(qualified_name))) .or_else(|| // some rare situations have a callstatement that's not properly annotated (e.g. checkRange-call of ranged datatypes) if let Some(name) = operator.get_flat_reference_name() { @@ -524,6 +528,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { function_name: &str, parameters: Vec<&AstNode>, ) -> Result<(), Diagnostic> { + // TODO: Here maybe? for (index, assignment_statement) in parameters.into_iter().enumerate() { self.assign_output_value(&CallParameterAssignment { assignment_statement, @@ -554,7 +559,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { left_lvalue: PointerValue, right_lvalue: PointerValue, left_statement: &AstNode, - right_statement: &AstNode, + right_type: &DataType, ) -> Result<(), Diagnostic> { /// when generating an assignment to a direct-access (e.g. a.b.c.%W3.%X2 := 2;) /// we want to deconstruct the sequence into the base-statement (a.b.c) and the sequence @@ -585,7 +590,6 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { }; let left_type = self.get_type_hint_for(target)?; - let right_type = self.get_type_hint_for(right_statement)?; //special case if we deal with a single bit, then we need to switch to a faked u1 type let right_type = @@ -661,106 +665,123 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { Ok(()) } - fn generate_output_assignment(&self, param_context: &CallParameterAssignment) -> Result<(), Diagnostic> { + fn generate_output_assignment(&self, context: &CallParameterAssignment) -> Result<(), Diagnostic> { let builder = &self.llvm.builder; - let expression = param_context.assignment_statement; - let parameter_struct = param_context.parameter_struct; - let function_name = param_context.function_name; - let index = param_context.index; - if let Some(parameter) = self.index.get_declared_parameter(function_name, index) { - if matches!(parameter.get_variable_type(), VariableType::Output) - && !matches!(expression.get_stmt(), AstStatement::EmptyStatement { .. }) - { + let expression = context.assignment_statement; + let parameter_struct = context.parameter_struct; + let function_name = context.function_name; + let index = context.index; + + let Some(parameter) = self.index.get_declared_parameter(function_name, index) else { + panic!("or return?"); + }; + + if !parameter.get_variable_type().is_output() || expression.is_assignment() { + panic!("wtf..."); + } + + // TODO: How to trigger an empty statement here, this: `FOO(Q => );`? + if expression.is_empty_statement() { + panic!("we did it mom"); + } + + if !expression.is_empty_statement() { + // FOO(x => y) + // FOO(x => y.0) + let (node, access_type) = match expression.get_stmt() { + // TODO: Is the order (left, right) correct + AstStatement::OutputAssignment(data_assignment) + if data_assignment.right.has_direct_access() => { - let assigned_output = if let (AstStatement::Assignment(data_assignment) - | AstStatement::OutputAssignment(data_assignment)) = - expression.get_stmt() - { - // if bitaccess rhs -> generate lvalue - let assigned_output = if let AstStatement::ReferenceExpr(ReferenceExpr { - access: ReferenceAccess::Member(member), - base, - }) = &data_assignment.right.get_stmt() - { - let base_value_rvalue = - base.as_ref().map(|it| self.generate_expression_value(it)).transpose()?; - - if let AstStatement::DirectAccess(data) = member.as_ref().get_stmt() { - let (Some(base), Some(base_value)) = (base, base_value_rvalue) else { - panic!() - }; - // Step 1 - let error_bits_lvalue = self - .llvm_index - .find_loaded_associated_variable_value( - self.annotations.get_qualified_name(base).unwrap(), - ) - .unwrap(); - - // Step 2 - let q_lvalue = self - .llvm - .builder - .build_struct_gep(parameter_struct, index, "bbb") - .unwrap(); - - // lhs = lvalue - // rhs = astnode - self.temp_xxx( - error_bits_lvalue, - q_lvalue, - &data_assignment.right, - &data_assignment.left, - )?; - } else { - unreachable!() - } - } else { - unreachable!() - }; + dbg!(&data_assignment); + ( + data_assignment.right.as_ref(), + self.annotations.get_type_hint(&data_assignment.right, self.index).unwrap(), + ) + } - assigned_output - } else { - todo!(""); - // self.generate_lvalue(expression)? - }; - // - // let assigned_output_type = - // self.annotations.get_type_or_void(expression, self.index).get_type_information(); - // - // let output = builder.build_struct_gep(parameter_struct, index, "").map_err(|_| { - // Diagnostic::codegen_error( - // format!("Cannot build generate parameter: {parameter:#?}"), - // parameter.source_location.clone(), - // ) - // })?; - // - // let output_value_type = - // self.index.get_type_information_or_void(parameter.get_type_name()); - - // //Special string handling - // if (assigned_output_type.is_string() && output_value_type.is_string()) - // || (assigned_output_type.is_struct() && output_value_type.is_struct()) - // || (assigned_output_type.is_array() && output_value_type.is_array()) - // { - // self.generate_string_store( - // assigned_output.get_basic_value_enum().into_pointer_value(), - // assigned_output_type, - // expression.get_location(), - // output, - // output_value_type, - // parameter.source_location.clone(), - // )?; - // } else { - // let output_value = builder.build_load(output, ""); - // builder.build_store( - // assigned_output.get_basic_value_enum().into_pointer_value(), - // output_value, - // ); - // } + AstStatement::ReferenceExpr(expr) if expression.has_direct_access() => { + let _pou = dbg!(self.index.find_pou(function_name).unwrap()); + let _struct = &_pou.find_instance_struct_type(self.index).unwrap().information; + let DataTypeInformation::Struct { members, .. } = _struct else { panic!() }; + let param = dbg!(&members[index as usize]); // TODO: Create a test for this; this fucks up if populating the members is not in order + let dt = self.index.find_effective_type_by_name(¶m.data_type_name).unwrap(); + (expression, dt) } - } - } + + _ => todo!("handle fallthrough, return early"), + }; + + let assigned_output = if let AstStatement::ReferenceExpr(ReferenceExpr { + access: ReferenceAccess::Member(member), + base, + }) = &node.get_stmt() + { + let base_value_rvalue = + base.as_ref().map(|it| self.generate_expression_value(it)).transpose()?; + + if let AstStatement::DirectAccess(data) = member.as_ref().get_stmt() { + let (Some(base), Some(base_value)) = (base, base_value_rvalue) else { panic!() }; + // Step 1 + let error_bits_lvalue = self + .llvm_index + .find_loaded_associated_variable_value( + self.annotations.get_qualified_name(base).unwrap(), + ) + .unwrap(); + + // Step 2 + let q_lvalue = + self.llvm.builder.build_struct_gep(parameter_struct, index, "bbb").unwrap(); + + // lhs = lvalue + // rhs = astnode + self.temp_xxx(error_bits_lvalue, q_lvalue, &node, &access_type)?; + }; + } else { + unreachable!() + }; + + assigned_output + } else { + todo!(""); + // self.generate_lvalue(expression)? + }; + + // + // let assigned_output_type = + // self.annotations.get_type_or_void(expression, self.index).get_type_information(); + // + // let output = builder.build_struct_gep(parameter_struct, index, "").map_err(|_| { + // Diagnostic::codegen_error( + // format!("Cannot build generate parameter: {parameter:#?}"), + // parameter.source_location.clone(), + // ) + // })?; + // + // let output_value_type = + // self.index.get_type_information_or_void(parameter.get_type_name()); + + // //Special string handling + // if (assigned_output_type.is_string() && output_value_type.is_string()) + // || (assigned_output_type.is_struct() && output_value_type.is_struct()) + // || (assigned_output_type.is_array() && output_value_type.is_array()) + // { + // self.generate_string_store( + // assigned_output.get_basic_value_enum().into_pointer_value(), + // assigned_output_type, + // expression.get_location(), + // output, + // output_value_type, + // parameter.source_location.clone(), + // )?; + // } else { + // let output_value = builder.build_load(output, ""); + // builder.build_store( + // assigned_output.get_basic_value_enum().into_pointer_value(), + // output_value, + // ); + // } Ok(()) } diff --git a/src/codegen/tests/directaccess_test.rs b/src/codegen/tests/directaccess_test.rs index 83e9ca37e75..15e440a02a5 100644 --- a/src/codegen/tests/directaccess_test.rs +++ b/src/codegen/tests/directaccess_test.rs @@ -115,35 +115,96 @@ fn qualified_reference_assignment() { } #[test] -fn temp_explicit() { +fn temp_output_and_normal_assignments() { let ir = codegen( r" FUNCTION_BLOCK FOO + VAR_INPUT + X : BOOL; + END_VAR VAR_OUTPUT - Q : BOOL; + Y : BOOL; END_VAR END_FUNCTION_BLOCK - FUNCTION main : DINT + FUNCTION main : DINT VAR error_bits : BYTE; f : FOO; END_VAR - f(Q => error_bits.0); + f(X := error_bits.0, Y => error_bits.0); + f(Y => error_bits.0, x := error_bits.0); + f(error_bits.0, error_bits.0); + f(X := error_bits.0, Y =>); + END_FUNCTION + ", + ); + + assert_snapshot!(ir, @r""); +} + +// TODO: Add correctness tests +#[test] +fn temp_complex_bit_access() { + let ir = codegen( + r" + TYPE foo_struct : STRUCT + bar : bar_struct; + END_STRUCT END_TYPE + + TYPE bar_struct : STRUCT + baz : LWORD; + END_STRUCT END_TYPE + + FUNCTION_BLOCK QUUX + VAR_OUTPUT + Q : BOOL; + END_VAR + END_FUNCTION_BLOCK + + FUNCTION main : DINT + VAR + foo : foo_struct; + f : QUUX; + END_VAR + + f(Q => foo.bar.baz.%W3.%X2); + END_FUNCTION + ", + ); + + assert_snapshot!(ir, @r""); +} + +#[test] +fn temp_explicity() { + let ir = codegen( + r" + FUNCTION_BLOCK FOO + VAR_OUTPUT + Q : BOOL := TRUE; + END_VAR + END_FUNCTION_BLOCK + + FUNCTION main : DINT + VAR + error_bits : BYTE := 2#1110_1111; + f : FOO; + END_VAR + + f(Q => error_bits.4); END_FUNCTION ", ); - // TODO: The OR here is wrong, what if foo(Q => bits.%X) where Q is false and the is true; - // the bit currently stay at 1 but should be 0 - insta::assert_snapshot!(ir, @r###" + assert_snapshot!(ir, @r###" ; ModuleID = 'main' source_filename = "main" %FOO = type { i8 } - @__FOO__init = unnamed_addr constant %FOO zeroinitializer + @__FOO__init = unnamed_addr constant %FOO { i8 1 } define void @FOO(%FOO* %0) section "fn-FOO:v[u8]" { entry: @@ -156,18 +217,18 @@ fn temp_explicit() { %main = alloca i32, align 4 %error_bits = alloca i8, align 1 %f = alloca %FOO, align 8 - store i8 0, i8* %error_bits, align 1 + store i8 -17, i8* %error_bits, align 1 %0 = bitcast %FOO* %f to i8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false) store i32 0, i32* %main, align 4 call void @FOO(%FOO* %f) - %aaa = load i8, i8* %error_bits, align 1 - %xxx = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 - %yyy = load i8, i8* %xxx, align 1 - %1 = shl i8 %yyy, 0 - %2 = or i8 %aaa, %1 - store i8 %2, i8* %error_bits, align 1 - %3 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 + %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 + %1 = load i8, i8* %error_bits, align 1 + %erase = and i8 %1, -17 + %2 = load i8, i8* %bbb, align 1 + %value = shl i8 %2, 4 + %or = or i8 %erase, %value + store i8 %or, i8* %error_bits, align 1 %main_ret = load i32, i32* %main, align 4 ret i32 %main_ret } @@ -185,83 +246,59 @@ fn temp_implicit() { r" FUNCTION_BLOCK FOO VAR_OUTPUT - Q : BOOL; + Q : BOOL := TRUE; END_VAR END_FUNCTION_BLOCK FUNCTION main : DINT VAR - error_bits : BYTE; + error_bits : BYTE := 2#1110_1111; f : FOO; END_VAR - f(error_bits.0); + f(error_bits.4); END_FUNCTION ", ); - assert_snapshot!(ir, @r""); -} - -#[test] -fn temp_output_and_normal_assignments() { - let ir = codegen( - r" - FUNCTION_BLOCK FOO - VAR_INPUT - X : BOOL; - END_VAR - VAR_OUTPUT - Y : BOOL; - END_VAR - END_FUNCTION_BLOCK - - FUNCTION main : DINT - VAR - error_bits : BYTE; - f : FOO; - END_VAR + assert_snapshot!(ir, @r###" + ; ModuleID = 'main' + source_filename = "main" - f(X := error_bits.0, Y => error_bits.0); - f(Y => error_bits.0, x := error_bits.0); - f(error_bits.0, error_bits.0); - f(X := error_bits.0, Y =>); - END_FUNCTION - ", - ); + %FOO = type { i8 } - assert_snapshot!(ir, @r""); -} + @__FOO__init = unnamed_addr constant %FOO { i8 1 } -// TODO: Add correctness tests -#[test] -fn temp_complex_bit_access() { - let ir = codegen( - r" - TYPE foo_struct : STRUCT - bar : bar_struct; - END_STRUCT END_TYPE - - TYPE bar_struct : STRUCT - baz : LWORD; - END_STRUCT END_TYPE + define void @FOO(%FOO* %0) section "fn-FOO:v[u8]" { + entry: + %Q = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0 + ret void + } - FUNCTION_BLOCK QUUX - VAR_OUTPUT - Q : BOOL; - END_VAR - END_FUNCTION_BLOCK + define i32 @main() section "fn-main:i32" { + entry: + %main = alloca i32, align 4 + %error_bits = alloca i8, align 1 + %f = alloca %FOO, align 8 + store i8 -17, i8* %error_bits, align 1 + %0 = bitcast %FOO* %f to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false) + store i32 0, i32* %main, align 4 + call void @FOO(%FOO* %f) + %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 + %1 = load i8, i8* %error_bits, align 1 + %erase = and i8 %1, -17 + %2 = load i8, i8* %bbb, align 1 + %value = shl i8 %2, 4 + %or = or i8 %erase, %value + store i8 %or, i8* %error_bits, align 1 + %main_ret = load i32, i32* %main, align 4 + ret i32 %main_ret + } - FUNCTION main : DINT - VAR - foo : foo_struct; - f : QUUX; - END_VAR - - f(Q => foo.bar.baz.%W3.%X2); - END_FUNCTION - ", - ); + ; Function Attrs: argmemonly nofree nounwind willreturn + declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0 - assert_snapshot!(ir, @r""); + attributes #0 = { argmemonly nofree nounwind willreturn } + "###); } diff --git a/src/index.rs b/src/index.rs index f3dfea1499c..ff0989f8c88 100644 --- a/src/index.rs +++ b/src/index.rs @@ -336,6 +336,12 @@ pub enum VariableType { Return, } +impl VariableType { + pub fn is_output(&self) -> bool { + matches!(self, VariableType::Output) + } +} + impl std::fmt::Display for VariableType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { From cff0f629fd743a2b2f45b45dde66adb3ca2998ee Mon Sep 17 00:00:00 2001 From: Volkan Sagcan Date: Thu, 25 Apr 2024 16:43:45 +0200 Subject: [PATCH 08/22] wip --- .../generators/expression_generator.rs | 157 +++++++++--------- .../tests/.directaccess_test.rs.pending-snap | 6 + ...am_with_var_out_called_in_program.snap.new | 28 ++++ ...h_var_out_called_mixed_in_program.snap.new | 28 ++++ ...s_empty_statement_as_output_param.snap.new | 28 ++++ ...s_empty_statement_as_output_param.snap.new | 29 ++++ ..._all_parameters_assigned_explicit.snap.new | 37 +++++ ...s__program_empty_inout_assignment.snap.new | 34 ++++ ..._program_missing_input_assignment.snap.new | 31 ++++ src/tests/adr/.pou_adr.rs.pending-snap | 19 +++ 10 files changed, 320 insertions(+), 77 deletions(-) create mode 100644 src/codegen/tests/.directaccess_test.rs.pending-snap create mode 100644 src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_var_out_called_in_program.snap.new create mode 100644 src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_var_out_called_mixed_in_program.snap.new create mode 100644 src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__fb_accepts_empty_statement_as_output_param.snap.new create mode 100644 src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_accepts_empty_statement_as_output_param.snap.new create mode 100644 src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_all_parameters_assigned_explicit.snap.new create mode 100644 src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_empty_inout_assignment.snap.new create mode 100644 src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_missing_input_assignment.snap.new create mode 100644 src/tests/adr/.pou_adr.rs.pending-snap diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index b9e606e2e80..777796ac03c 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -506,12 +506,13 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { // after the call we need to copy the values for assigned outputs // this is only necessary for outputs defined as `rusty::index::ArgumentType::ByVal` (PROGRAM, FUNCTION_BLOCK) - // FUNCTION outputs are defined as `rusty::index::ArgumentType::ByRef` + // FUNCTION outputs are defined as `rusty::index::ArgumentType::ByRef` // FIXME(mhasel): for standard-compliance functions also need to support VAR_OUTPUT if !pou.is_function() { let parameter_struct = match arguments_list.first() { Some(v) => v.into_pointer_value(), None => self.generate_lvalue(operator)?, }; + self.assign_output_values(parameter_struct, implementation_name, parameters_list)? } @@ -522,20 +523,32 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { /// - `parameter_struct` a pointer to a struct-instance that holds all function-parameters /// - `function_name` the name of the callable /// - `parameters` vec of passed parameters to the call + // TODO: Rename this fucking function fn assign_output_values( &self, parameter_struct: PointerValue<'ink>, function_name: &str, parameters: Vec<&AstNode>, ) -> Result<(), Diagnostic> { - // TODO: Here maybe? + // self.index.get_declared_parameter(function_name, index) + + // Before + // parameter = vec![foo, bar, baz] + // ^^^ output, index = 1 + // After (filtered) + // parameter = vec![bar] + + let pou_info = self.index.get_declared_parameters(function_name); for (index, assignment_statement) in parameters.into_iter().enumerate() { - self.assign_output_value(&CallParameterAssignment { - assignment_statement, - function_name, - index: index as u32, - parameter_struct, - })? + // TODO: Filter this + if pou_info.get(index).is_some_and(|it| it.get_variable_type().is_output()) { + self.assign_output_value(&CallParameterAssignment { + assignment_statement, + function_name, + index: index as u32, + parameter_struct, + })? + } } Ok(()) } @@ -677,7 +690,8 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { }; if !parameter.get_variable_type().is_output() || expression.is_assignment() { - panic!("wtf..."); + panic!("wtf... {parameter:#?}"); + // return Ok(()); } // TODO: How to trigger an empty statement here, this: `FOO(Q => );`? @@ -709,79 +723,68 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { (expression, dt) } - _ => todo!("handle fallthrough, return early"), - }; + _ => { + dbg!(&expression); + let assigned_output = self.generate_lvalue(expression)?; - let assigned_output = if let AstStatement::ReferenceExpr(ReferenceExpr { - access: ReferenceAccess::Member(member), - base, - }) = &node.get_stmt() - { - let base_value_rvalue = - base.as_ref().map(|it| self.generate_expression_value(it)).transpose()?; - - if let AstStatement::DirectAccess(data) = member.as_ref().get_stmt() { - let (Some(base), Some(base_value)) = (base, base_value_rvalue) else { panic!() }; - // Step 1 - let error_bits_lvalue = self - .llvm_index - .find_loaded_associated_variable_value( - self.annotations.get_qualified_name(base).unwrap(), + let assigned_output_type = + self.annotations.get_type_or_void(expression, self.index).get_type_information(); + + let output = builder.build_struct_gep(parameter_struct, index, "").map_err(|_| { + Diagnostic::codegen_error( + format!("Cannot build generate parameter: {parameter:#?}"), + parameter.source_location.clone(), ) - .unwrap(); + })?; - // Step 2 - let q_lvalue = - self.llvm.builder.build_struct_gep(parameter_struct, index, "bbb").unwrap(); + let output_value_type = + self.index.get_type_information_or_void(parameter.get_type_name()); - // lhs = lvalue - // rhs = astnode - self.temp_xxx(error_bits_lvalue, q_lvalue, &node, &access_type)?; - }; - } else { - unreachable!() + //Special string handling + if (assigned_output_type.is_string() && output_value_type.is_string()) + || (assigned_output_type.is_struct() && output_value_type.is_struct()) + || (assigned_output_type.is_array() && output_value_type.is_array()) + { + self.generate_string_store( + assigned_output, + assigned_output_type, + expression.get_location(), + output, + output_value_type, + parameter.source_location.clone(), + )?; + } else { + let output_value = builder.build_load(output, ""); + builder.build_store(assigned_output, output_value); + } + return Ok(()); + // todo!("handle fallthrough, return early; {expression:#?}") + } }; - assigned_output - } else { - todo!(""); - // self.generate_lvalue(expression)? - }; + let AstStatement::ReferenceExpr(ReferenceExpr { access: ReferenceAccess::Member(member), base }) = + &node.get_stmt() + else { + unreachable!("must be a bitaccess, will return early for all other cases") + }; + let base_value_rvalue = base.as_ref().map(|it| self.generate_expression_value(it)).transpose()?; - // - // let assigned_output_type = - // self.annotations.get_type_or_void(expression, self.index).get_type_information(); - // - // let output = builder.build_struct_gep(parameter_struct, index, "").map_err(|_| { - // Diagnostic::codegen_error( - // format!("Cannot build generate parameter: {parameter:#?}"), - // parameter.source_location.clone(), - // ) - // })?; - // - // let output_value_type = - // self.index.get_type_information_or_void(parameter.get_type_name()); - - // //Special string handling - // if (assigned_output_type.is_string() && output_value_type.is_string()) - // || (assigned_output_type.is_struct() && output_value_type.is_struct()) - // || (assigned_output_type.is_array() && output_value_type.is_array()) - // { - // self.generate_string_store( - // assigned_output.get_basic_value_enum().into_pointer_value(), - // assigned_output_type, - // expression.get_location(), - // output, - // output_value_type, - // parameter.source_location.clone(), - // )?; - // } else { - // let output_value = builder.build_load(output, ""); - // builder.build_store( - // assigned_output.get_basic_value_enum().into_pointer_value(), - // output_value, - // ); - // } + if let AstStatement::DirectAccess(_) = member.as_ref().get_stmt() { + let (Some(base), _) = (base, ..) else { panic!() }; + // Step 1 + let error_bits_lvalue = self + .llvm_index + .find_loaded_associated_variable_value(self.annotations.get_qualified_name(base).unwrap()) + .unwrap(); + + // Step 2 + let q_lvalue = self.llvm.builder.build_struct_gep(parameter_struct, index, "bbb").unwrap(); + + // lhs = lvalue + // rhs = astnode + self.temp_xxx(error_bits_lvalue, q_lvalue, &node, &access_type)?; + }; + } Ok(()) } @@ -804,12 +807,12 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { .ok_or_else(|| Diagnostic::unresolved_reference(qualified_name, left.get_location()))?; let index = parameter.get_location_in_parent(); - let _ = self.generate_output_assignment(&CallParameterAssignment { + self.generate_output_assignment(&CallParameterAssignment { assignment_statement: assignment, function_name, index, parameter_struct, - }); + })? }; Ok(()) } diff --git a/src/codegen/tests/.directaccess_test.rs.pending-snap b/src/codegen/tests/.directaccess_test.rs.pending-snap new file mode 100644 index 00000000000..0614d7c19c2 --- /dev/null +++ b/src/codegen/tests/.directaccess_test.rs.pending-snap @@ -0,0 +1,6 @@ +{"run_id":"1714055182-669760809","line":144,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_output_and_normal_assignments","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":144,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8, i8 }\n\n@__FOO__init = unnamed_addr constant %FOO zeroinitializer\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8][u8]\" {\nentry:\n %X = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n %Y = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 1\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 0, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits = load i8, i8* %error_bits, align 1\n %shift = lshr i8 %load_error_bits, 0\n %2 = and i8 %shift, 1\n store i8 %2, i8* %1, align 1\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %3 = load i8, i8* %error_bits, align 1\n %erase = and i8 %3, -2\n %4 = load i8, i8* %bbb, align 1\n %value = shl i8 %4, 0\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits1 = load i8, i8* %error_bits, align 1\n %shift2 = lshr i8 %load_error_bits1, 0\n %6 = and i8 %shift2, 1\n store i8 %6, i8* %5, align 1\n call void @FOO(%FOO* %f)\n %7 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits3 = load i8, i8* %error_bits, align 1\n %shift4 = lshr i8 %load_error_bits3, 0\n %8 = and i8 %shift4, 1\n store i8 %8, i8* %7, align 1\n call void @FOO(%FOO* %f)\n %bbb5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %9 = load i8, i8* %error_bits, align 1\n %erase6 = and i8 %9, -2\n %10 = load i8, i8* %bbb5, align 1\n %value7 = shl i8 %10, 0\n %or8 = or i8 %erase6, %value7\n store i8 %or8, i8* %error_bits, align 1\n %11 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits9 = load i8, i8* %error_bits, align 1\n %shift10 = lshr i8 %load_error_bits9, 0\n %12 = and i8 %shift10, 1\n store i8 %12, i8* %11, align 1\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":""}} +{"run_id":"1714055307-365730799","line":201,"new":null,"old":null} +{"run_id":"1714055307-365730799","line":264,"new":null,"old":null} +{"run_id":"1714055307-365730799","line":144,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_output_and_normal_assignments","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":144,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8, i8 }\n\n@__FOO__init = unnamed_addr constant %FOO zeroinitializer\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8][u8]\" {\nentry:\n %X = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n %Y = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 1\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 0, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits = load i8, i8* %error_bits, align 1\n %shift = lshr i8 %load_error_bits, 0\n %2 = and i8 %shift, 1\n store i8 %2, i8* %1, align 1\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %3 = load i8, i8* %error_bits, align 1\n %erase = and i8 %3, -2\n %4 = load i8, i8* %bbb, align 1\n %value = shl i8 %4, 0\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits1 = load i8, i8* %error_bits, align 1\n %shift2 = lshr i8 %load_error_bits1, 0\n %6 = and i8 %shift2, 1\n store i8 %6, i8* %5, align 1\n call void @FOO(%FOO* %f)\n %7 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits3 = load i8, i8* %error_bits, align 1\n %shift4 = lshr i8 %load_error_bits3, 0\n %8 = and i8 %shift4, 1\n store i8 %8, i8* %7, align 1\n call void @FOO(%FOO* %f)\n %bbb5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %9 = load i8, i8* %error_bits, align 1\n %erase6 = and i8 %9, -2\n %10 = load i8, i8* %bbb5, align 1\n %value7 = shl i8 %10, 0\n %or8 = or i8 %erase6, %value7\n store i8 %or8, i8* %error_bits, align 1\n %11 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits9 = load i8, i8* %error_bits, align 1\n %shift10 = lshr i8 %load_error_bits9, 0\n %12 = and i8 %shift10, 1\n store i8 %12, i8* %11, align 1\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":""}} +{"run_id":"1714055699-714395630","line":264,"new":null,"old":null} +{"run_id":"1714055699-714395630","line":201,"new":null,"old":null} diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_var_out_called_in_program.snap.new b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_var_out_called_in_program.snap.new new file mode 100644 index 00000000000..f4069dd3dc1 --- /dev/null +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_var_out_called_in_program.snap.new @@ -0,0 +1,28 @@ +--- +source: src/codegen/tests/code_gen_tests.rs +assertion_line: 1747 +expression: result +--- +; ModuleID = 'main' +source_filename = "main" + +%foo = type { i32, i8 } +%prg = type { i8 } + +@foo_instance = global %foo zeroinitializer +@prg_instance = global %prg zeroinitializer + +define void @foo(%foo* %0) section "fn-foo:v[i32][u8]" { +entry: + %bar = getelementptr inbounds %foo, %foo* %0, i32 0, i32 0 + %buz = getelementptr inbounds %foo, %foo* %0, i32 0, i32 1 + ret void +} + +define void @prg(%prg* %0) section "fn-prg:v" { +entry: + %baz = getelementptr inbounds %prg, %prg* %0, i32 0, i32 0 + store i32 2, i32* getelementptr inbounds (%foo, %foo* @foo_instance, i32 0, i32 0), align 4 + call void @foo(%foo* @foo_instance) + ret void +} diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_var_out_called_mixed_in_program.snap.new b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_var_out_called_mixed_in_program.snap.new new file mode 100644 index 00000000000..d042037982c --- /dev/null +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_var_out_called_mixed_in_program.snap.new @@ -0,0 +1,28 @@ +--- +source: src/codegen/tests/code_gen_tests.rs +assertion_line: 1913 +expression: result +--- +; ModuleID = 'main' +source_filename = "main" + +%foo = type { i32, i8 } +%prg = type { i8 } + +@foo_instance = global %foo zeroinitializer +@prg_instance = global %prg zeroinitializer + +define void @foo(%foo* %0) section "fn-foo:v[i32][u8]" { +entry: + %bar = getelementptr inbounds %foo, %foo* %0, i32 0, i32 0 + %buz = getelementptr inbounds %foo, %foo* %0, i32 0, i32 1 + ret void +} + +define void @prg(%prg* %0) section "fn-prg:v" { +entry: + %baz = getelementptr inbounds %prg, %prg* %0, i32 0, i32 0 + store i32 2, i32* getelementptr inbounds (%foo, %foo* @foo_instance, i32 0, i32 0), align 4 + call void @foo(%foo* @foo_instance) + ret void +} diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__fb_accepts_empty_statement_as_output_param.snap.new b/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__fb_accepts_empty_statement_as_output_param.snap.new new file mode 100644 index 00000000000..2581d9cd323 --- /dev/null +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__fb_accepts_empty_statement_as_output_param.snap.new @@ -0,0 +1,28 @@ +--- +source: src/codegen/tests/parameters_tests.rs +assertion_line: 570 +expression: result +--- +; ModuleID = 'main' +source_filename = "main" + +%fb_t = type { i32, i32 } +%main = type { %fb_t, i32 } + +@__fb_t__init = unnamed_addr constant %fb_t zeroinitializer +@main_instance = global %main zeroinitializer + +define void @fb_t(%fb_t* %0) section "fn-fb_t:v[i32][i32]" { +entry: + %out1 = getelementptr inbounds %fb_t, %fb_t* %0, i32 0, i32 0 + %out2 = getelementptr inbounds %fb_t, %fb_t* %0, i32 0, i32 1 + ret void +} + +define void @main(%main* %0) section "fn-main:v" { +entry: + %fb = getelementptr inbounds %main, %main* %0, i32 0, i32 0 + %x = getelementptr inbounds %main, %main* %0, i32 0, i32 1 + call void @fb_t(%fb_t* %fb) + ret void +} diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_accepts_empty_statement_as_output_param.snap.new b/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_accepts_empty_statement_as_output_param.snap.new new file mode 100644 index 00000000000..74e50a47ed5 --- /dev/null +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_accepts_empty_statement_as_output_param.snap.new @@ -0,0 +1,29 @@ +--- +source: src/codegen/tests/parameters_tests.rs +assertion_line: 519 +expression: result +--- +; ModuleID = 'main' +source_filename = "main" + +%prog = type { i32, i32 } +%main = type { i32 } + +@prog_instance = global %prog zeroinitializer +@main_instance = global %main zeroinitializer + +define void @prog(%prog* %0) section "fn-prog:v[i32][i32]" { +entry: + %out1 = getelementptr inbounds %prog, %prog* %0, i32 0, i32 0 + %out2 = getelementptr inbounds %prog, %prog* %0, i32 0, i32 1 + store i32 1, i32* %out1, align 4 + store i32 2, i32* %out2, align 4 + ret void +} + +define void @main(%main* %0) section "fn-main:v" { +entry: + %x = getelementptr inbounds %main, %main* %0, i32 0, i32 0 + call void @prog(%prog* @prog_instance) + ret void +} diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_all_parameters_assigned_explicit.snap.new b/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_all_parameters_assigned_explicit.snap.new new file mode 100644 index 00000000000..c910f95b118 --- /dev/null +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_all_parameters_assigned_explicit.snap.new @@ -0,0 +1,37 @@ +--- +source: src/codegen/tests/parameters_tests.rs +assertion_line: 354 +expression: result +--- +; ModuleID = 'main' +source_filename = "main" + +%prog = type { i32, i32, i32* } +%main = type { i32, i32, i32 } + +@prog_instance = global %prog zeroinitializer +@main_instance = global %main zeroinitializer + +define void @prog(%prog* %0) section "fn-prog:v[i32][i32][pi32]" { +entry: + %input1 = getelementptr inbounds %prog, %prog* %0, i32 0, i32 0 + %output1 = getelementptr inbounds %prog, %prog* %0, i32 0, i32 1 + %inout1 = getelementptr inbounds %prog, %prog* %0, i32 0, i32 2 + ret void +} + +define void @main(%main* %0) section "fn-main:v" { +entry: + %var1 = getelementptr inbounds %main, %main* %0, i32 0, i32 0 + %var2 = getelementptr inbounds %main, %main* %0, i32 0, i32 1 + %var3 = getelementptr inbounds %main, %main* %0, i32 0, i32 2 + %load_var1 = load i32, i32* %var1, align 4 + store i32 %load_var1, i32* getelementptr inbounds (%prog, %prog* @prog_instance, i32 0, i32 0), align 4 + store i32* %var3, i32** getelementptr inbounds (%prog, %prog* @prog_instance, i32 0, i32 2), align 8 + call void @prog(%prog* @prog_instance) + store i32* %var3, i32** getelementptr inbounds (%prog, %prog* @prog_instance, i32 0, i32 2), align 8 + %load_var11 = load i32, i32* %var1, align 4 + store i32 %load_var11, i32* getelementptr inbounds (%prog, %prog* @prog_instance, i32 0, i32 0), align 4 + call void @prog(%prog* @prog_instance) + ret void +} diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_empty_inout_assignment.snap.new b/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_empty_inout_assignment.snap.new new file mode 100644 index 00000000000..8b2b801f908 --- /dev/null +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_empty_inout_assignment.snap.new @@ -0,0 +1,34 @@ +--- +source: src/codegen/tests/parameters_tests.rs +assertion_line: 412 +expression: result +--- +; ModuleID = 'main' +source_filename = "main" + +%prog = type { i32, i32, i32* } +%main = type { i32, i32, i32 } + +@prog_instance = global %prog zeroinitializer +@main_instance = global %main zeroinitializer + +define void @prog(%prog* %0) section "fn-prog:v[i32][i32][pi32]" { +entry: + %input1 = getelementptr inbounds %prog, %prog* %0, i32 0, i32 0 + %output1 = getelementptr inbounds %prog, %prog* %0, i32 0, i32 1 + %inout1 = getelementptr inbounds %prog, %prog* %0, i32 0, i32 2 + ret void +} + +define void @main(%main* %0) section "fn-main:v" { +entry: + %var1 = getelementptr inbounds %main, %main* %0, i32 0, i32 0 + %var2 = getelementptr inbounds %main, %main* %0, i32 0, i32 1 + %var3 = getelementptr inbounds %main, %main* %0, i32 0, i32 2 + %load_var1 = load i32, i32* %var1, align 4 + store i32 %load_var1, i32* getelementptr inbounds (%prog, %prog* @prog_instance, i32 0, i32 0), align 4 + %empty_varinout = alloca i32, align 4 + store i32* %empty_varinout, i32** getelementptr inbounds (%prog, %prog* @prog_instance, i32 0, i32 2), align 8 + call void @prog(%prog* @prog_instance) + ret void +} diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_missing_input_assignment.snap.new b/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_missing_input_assignment.snap.new new file mode 100644 index 00000000000..6632043cafd --- /dev/null +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_missing_input_assignment.snap.new @@ -0,0 +1,31 @@ +--- +source: src/codegen/tests/parameters_tests.rs +assertion_line: 441 +expression: result +--- +; ModuleID = 'main' +source_filename = "main" + +%prog = type { i32, i32, i32* } +%main = type { i32, i32, i32 } + +@prog_instance = global %prog zeroinitializer +@main_instance = global %main zeroinitializer + +define void @prog(%prog* %0) section "fn-prog:v[i32][i32][pi32]" { +entry: + %input1 = getelementptr inbounds %prog, %prog* %0, i32 0, i32 0 + %output1 = getelementptr inbounds %prog, %prog* %0, i32 0, i32 1 + %inout1 = getelementptr inbounds %prog, %prog* %0, i32 0, i32 2 + ret void +} + +define void @main(%main* %0) section "fn-main:v" { +entry: + %var1 = getelementptr inbounds %main, %main* %0, i32 0, i32 0 + %var2 = getelementptr inbounds %main, %main* %0, i32 0, i32 1 + %var3 = getelementptr inbounds %main, %main* %0, i32 0, i32 2 + store i32* %var3, i32** getelementptr inbounds (%prog, %prog* @prog_instance, i32 0, i32 2), align 8 + call void @prog(%prog* @prog_instance) + ret void +} diff --git a/src/tests/adr/.pou_adr.rs.pending-snap b/src/tests/adr/.pou_adr.rs.pending-snap new file mode 100644 index 00000000000..6793d770e45 --- /dev/null +++ b/src/tests/adr/.pou_adr.rs.pending-snap @@ -0,0 +1,19 @@ +{"run_id":"1714055182-669760809","line":268,"new":{"module_name":"rusty__tests__adr__pou_adr","snapshot_name":"calling_a_program","metadata":{"source":"src/tests/adr/pou_adr.rs","assertion_line":268,"expression":"codegen(calling_prg.as_str())"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%main_prg = type { i16, i16*, i16, i16 }\n\n@main_prg_instance = global %main_prg zeroinitializer\n\ndefine i16 @foo() section \"fn-foo:i16\" {\nentry:\n %foo = alloca i16, align 2\n %x = alloca i16, align 2\n %y = alloca i16, align 2\n store i16 0, i16* %x, align 2\n store i16 0, i16* %y, align 2\n store i16 0, i16* %foo, align 2\n store i16 1, i16* getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 0), align 2\n store i16* %y, i16** getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 1), align 8\n call void @main_prg(%main_prg* @main_prg_instance)\n %foo_ret = load i16, i16* %foo, align 2\n ret i16 %foo_ret\n}\n\ndefine void @main_prg(%main_prg* %0) section \"fn-main_prg:v[i16][pi16][i16]\" {\nentry:\n %i = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 0\n %io = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 1\n %o = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 2\n %v = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 3\n %vt = alloca i16, align 2\n store i16 0, i16* %vt, align 2\n ret void\n}\n"},"old":{"module_name":"rusty__tests__adr__pou_adr","metadata":{},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%main_prg = type { i16, i16*, i16, i16 }\n\n@main_prg_instance = global %main_prg zeroinitializer\n\ndefine i16 @foo() section \"fn-foo:i16\" {\nentry:\n %foo = alloca i16, align 2\n %x = alloca i16, align 2\n %y = alloca i16, align 2\n store i16 0, i16* %x, align 2\n store i16 0, i16* %y, align 2\n store i16 0, i16* %foo, align 2\n store i16 1, i16* getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 0), align 2\n store i16* %y, i16** getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 1), align 8\n call void @main_prg(%main_prg* @main_prg_instance)\n %0 = load i16, i16* getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 2), align 2\n store i16 %0, i16* %x, align 2\n %foo_ret = load i16, i16* %foo, align 2\n ret i16 %foo_ret\n}\n\ndefine void @main_prg(%main_prg* %0) section \"fn-main_prg:v[i16][pi16][i16]\" {\nentry:\n %i = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 0\n %io = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 1\n %o = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 2\n %v = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 3\n %vt = alloca i16, align 2\n store i16 0, i16* %vt, align 2\n ret void\n}"}} +{"run_id":"1714055182-669760809","line":371,"new":{"module_name":"rusty__tests__adr__pou_adr","snapshot_name":"calling_a_function_block","metadata":{"source":"src/tests/adr/pou_adr.rs","assertion_line":371,"expression":"codegen(calling_prg.as_str())"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%foo = type { i16, i16, %main_fb }\n%main_fb = type { i16, i16*, i16, i16 }\n\n@foo_instance = global %foo { i16 0, i16 0, %main_fb { i16 6, i16* null, i16 0, i16 1 } }\n@__main_fb__init = unnamed_addr constant %main_fb { i16 6, i16* null, i16 0, i16 1 }\n\ndefine void @foo(%foo* %0) section \"fn-foo:v\" {\nentry:\n %x = getelementptr inbounds %foo, %foo* %0, i32 0, i32 0\n %y = getelementptr inbounds %foo, %foo* %0, i32 0, i32 1\n %fb = getelementptr inbounds %foo, %foo* %0, i32 0, i32 2\n %1 = getelementptr inbounds %main_fb, %main_fb* %fb, i32 0, i32 0\n store i16 1, i16* %1, align 2\n %2 = getelementptr inbounds %main_fb, %main_fb* %fb, i32 0, i32 1\n store i16* %y, i16** %2, align 8\n call void @main_fb(%main_fb* %fb)\n ret void\n}\n\ndefine void @main_fb(%main_fb* %0) section \"fn-main_fb:v[i16][pi16][i16]\" {\nentry:\n %i = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 0\n %io = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 1\n %o = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 2\n %v = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 3\n %vt = alloca i16, align 2\n store i16 2, i16* %vt, align 2\n ret void\n}\n"},"old":{"module_name":"rusty__tests__adr__pou_adr","metadata":{},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%foo = type { i16, i16, %main_fb }\n%main_fb = type { i16, i16*, i16, i16 }\n\n@foo_instance = global %foo { i16 0, i16 0, %main_fb { i16 6, i16* null, i16 0, i16 1 } }\n@__main_fb__init = unnamed_addr constant %main_fb { i16 6, i16* null, i16 0, i16 1 }\n\ndefine void @foo(%foo* %0) section \"fn-foo:v\" {\nentry:\n %x = getelementptr inbounds %foo, %foo* %0, i32 0, i32 0\n %y = getelementptr inbounds %foo, %foo* %0, i32 0, i32 1\n %fb = getelementptr inbounds %foo, %foo* %0, i32 0, i32 2\n %1 = getelementptr inbounds %main_fb, %main_fb* %fb, i32 0, i32 0\n store i16 1, i16* %1, align 2\n %2 = getelementptr inbounds %main_fb, %main_fb* %fb, i32 0, i32 1\n store i16* %y, i16** %2, align 8\n call void @main_fb(%main_fb* %fb)\n %3 = getelementptr inbounds %main_fb, %main_fb* %fb, i32 0, i32 2\n %4 = load i16, i16* %3, align 2\n store i16 %4, i16* %x, align 2\n ret void\n}\n\ndefine void @main_fb(%main_fb* %0) section \"fn-main_fb:v[i16][pi16][i16]\" {\nentry:\n %i = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 0\n %io = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 1\n %o = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 2\n %v = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 3\n %vt = alloca i16, align 2\n store i16 2, i16* %vt, align 2\n ret void\n}"}} +{"run_id":"1714055307-365730799","line":230,"new":null,"old":null} +{"run_id":"1714055307-365730799","line":472,"new":null,"old":null} +{"run_id":"1714055307-365730799","line":332,"new":null,"old":null} +{"run_id":"1714055307-365730799","line":430,"new":null,"old":null} +{"run_id":"1714055307-365730799","line":605,"new":null,"old":null} +{"run_id":"1714055307-365730799","line":55,"new":null,"old":null} +{"run_id":"1714055307-365730799","line":534,"new":null,"old":null} +{"run_id":"1714055307-365730799","line":371,"new":{"module_name":"rusty__tests__adr__pou_adr","snapshot_name":"calling_a_function_block","metadata":{"source":"src/tests/adr/pou_adr.rs","assertion_line":371,"expression":"codegen(calling_prg.as_str())"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%foo = type { i16, i16, %main_fb }\n%main_fb = type { i16, i16*, i16, i16 }\n\n@foo_instance = global %foo { i16 0, i16 0, %main_fb { i16 6, i16* null, i16 0, i16 1 } }\n@__main_fb__init = unnamed_addr constant %main_fb { i16 6, i16* null, i16 0, i16 1 }\n\ndefine void @foo(%foo* %0) section \"fn-foo:v\" {\nentry:\n %x = getelementptr inbounds %foo, %foo* %0, i32 0, i32 0\n %y = getelementptr inbounds %foo, %foo* %0, i32 0, i32 1\n %fb = getelementptr inbounds %foo, %foo* %0, i32 0, i32 2\n %1 = getelementptr inbounds %main_fb, %main_fb* %fb, i32 0, i32 0\n store i16 1, i16* %1, align 2\n %2 = getelementptr inbounds %main_fb, %main_fb* %fb, i32 0, i32 1\n store i16* %y, i16** %2, align 8\n call void @main_fb(%main_fb* %fb)\n ret void\n}\n\ndefine void @main_fb(%main_fb* %0) section \"fn-main_fb:v[i16][pi16][i16]\" {\nentry:\n %i = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 0\n %io = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 1\n %o = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 2\n %v = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 3\n %vt = alloca i16, align 2\n store i16 2, i16* %vt, align 2\n ret void\n}\n"},"old":{"module_name":"rusty__tests__adr__pou_adr","metadata":{},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%foo = type { i16, i16, %main_fb }\n%main_fb = type { i16, i16*, i16, i16 }\n\n@foo_instance = global %foo { i16 0, i16 0, %main_fb { i16 6, i16* null, i16 0, i16 1 } }\n@__main_fb__init = unnamed_addr constant %main_fb { i16 6, i16* null, i16 0, i16 1 }\n\ndefine void @foo(%foo* %0) section \"fn-foo:v\" {\nentry:\n %x = getelementptr inbounds %foo, %foo* %0, i32 0, i32 0\n %y = getelementptr inbounds %foo, %foo* %0, i32 0, i32 1\n %fb = getelementptr inbounds %foo, %foo* %0, i32 0, i32 2\n %1 = getelementptr inbounds %main_fb, %main_fb* %fb, i32 0, i32 0\n store i16 1, i16* %1, align 2\n %2 = getelementptr inbounds %main_fb, %main_fb* %fb, i32 0, i32 1\n store i16* %y, i16** %2, align 8\n call void @main_fb(%main_fb* %fb)\n %3 = getelementptr inbounds %main_fb, %main_fb* %fb, i32 0, i32 2\n %4 = load i16, i16* %3, align 2\n store i16 %4, i16* %x, align 2\n ret void\n}\n\ndefine void @main_fb(%main_fb* %0) section \"fn-main_fb:v[i16][pi16][i16]\" {\nentry:\n %i = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 0\n %io = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 1\n %o = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 2\n %v = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 3\n %vt = alloca i16, align 2\n store i16 2, i16* %vt, align 2\n ret void\n}"}} +{"run_id":"1714055307-365730799","line":268,"new":{"module_name":"rusty__tests__adr__pou_adr","snapshot_name":"calling_a_program","metadata":{"source":"src/tests/adr/pou_adr.rs","assertion_line":268,"expression":"codegen(calling_prg.as_str())"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%main_prg = type { i16, i16*, i16, i16 }\n\n@main_prg_instance = global %main_prg zeroinitializer\n\ndefine i16 @foo() section \"fn-foo:i16\" {\nentry:\n %foo = alloca i16, align 2\n %x = alloca i16, align 2\n %y = alloca i16, align 2\n store i16 0, i16* %x, align 2\n store i16 0, i16* %y, align 2\n store i16 0, i16* %foo, align 2\n store i16 1, i16* getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 0), align 2\n store i16* %y, i16** getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 1), align 8\n call void @main_prg(%main_prg* @main_prg_instance)\n %foo_ret = load i16, i16* %foo, align 2\n ret i16 %foo_ret\n}\n\ndefine void @main_prg(%main_prg* %0) section \"fn-main_prg:v[i16][pi16][i16]\" {\nentry:\n %i = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 0\n %io = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 1\n %o = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 2\n %v = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 3\n %vt = alloca i16, align 2\n store i16 0, i16* %vt, align 2\n ret void\n}\n"},"old":{"module_name":"rusty__tests__adr__pou_adr","metadata":{},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%main_prg = type { i16, i16*, i16, i16 }\n\n@main_prg_instance = global %main_prg zeroinitializer\n\ndefine i16 @foo() section \"fn-foo:i16\" {\nentry:\n %foo = alloca i16, align 2\n %x = alloca i16, align 2\n %y = alloca i16, align 2\n store i16 0, i16* %x, align 2\n store i16 0, i16* %y, align 2\n store i16 0, i16* %foo, align 2\n store i16 1, i16* getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 0), align 2\n store i16* %y, i16** getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 1), align 8\n call void @main_prg(%main_prg* @main_prg_instance)\n %0 = load i16, i16* getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 2), align 2\n store i16 %0, i16* %x, align 2\n %foo_ret = load i16, i16* %foo, align 2\n ret i16 %foo_ret\n}\n\ndefine void @main_prg(%main_prg* %0) section \"fn-main_prg:v[i16][pi16][i16]\" {\nentry:\n %i = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 0\n %io = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 1\n %o = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 2\n %v = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 3\n %vt = alloca i16, align 2\n store i16 0, i16* %vt, align 2\n ret void\n}"}} +{"run_id":"1714055612-855744521","line":268,"new":{"module_name":"rusty__tests__adr__pou_adr","snapshot_name":"calling_a_program","metadata":{"source":"src/tests/adr/pou_adr.rs","assertion_line":268,"expression":"codegen(calling_prg.as_str())"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%main_prg = type { i16, i16*, i16, i16 }\n\n@main_prg_instance = global %main_prg zeroinitializer\n\ndefine i16 @foo() section \"fn-foo:i16\" {\nentry:\n %foo = alloca i16, align 2\n %x = alloca i16, align 2\n %y = alloca i16, align 2\n store i16 0, i16* %x, align 2\n store i16 0, i16* %y, align 2\n store i16 0, i16* %foo, align 2\n store i16 1, i16* getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 0), align 2\n store i16* %y, i16** getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 1), align 8\n call void @main_prg(%main_prg* @main_prg_instance)\n %foo_ret = load i16, i16* %foo, align 2\n ret i16 %foo_ret\n}\n\ndefine void @main_prg(%main_prg* %0) section \"fn-main_prg:v[i16][pi16][i16]\" {\nentry:\n %i = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 0\n %io = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 1\n %o = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 2\n %v = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 3\n %vt = alloca i16, align 2\n store i16 0, i16* %vt, align 2\n ret void\n}\n"},"old":{"module_name":"rusty__tests__adr__pou_adr","metadata":{},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%main_prg = type { i16, i16*, i16, i16 }\n\n@main_prg_instance = global %main_prg zeroinitializer\n\ndefine i16 @foo() section \"fn-foo:i16\" {\nentry:\n %foo = alloca i16, align 2\n %x = alloca i16, align 2\n %y = alloca i16, align 2\n store i16 0, i16* %x, align 2\n store i16 0, i16* %y, align 2\n store i16 0, i16* %foo, align 2\n store i16 1, i16* getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 0), align 2\n store i16* %y, i16** getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 1), align 8\n call void @main_prg(%main_prg* @main_prg_instance)\n %0 = load i16, i16* getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 2), align 2\n store i16 %0, i16* %x, align 2\n %foo_ret = load i16, i16* %foo, align 2\n ret i16 %foo_ret\n}\n\ndefine void @main_prg(%main_prg* %0) section \"fn-main_prg:v[i16][pi16][i16]\" {\nentry:\n %i = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 0\n %io = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 1\n %o = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 2\n %v = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 3\n %vt = alloca i16, align 2\n store i16 0, i16* %vt, align 2\n ret void\n}"}} +{"run_id":"1714055699-714395630","line":472,"new":null,"old":null} +{"run_id":"1714055699-714395630","line":230,"new":null,"old":null} +{"run_id":"1714055699-714395630","line":430,"new":null,"old":null} +{"run_id":"1714055699-714395630","line":332,"new":null,"old":null} +{"run_id":"1714055699-714395630","line":605,"new":null,"old":null} +{"run_id":"1714055699-714395630","line":55,"new":null,"old":null} +{"run_id":"1714055699-714395630","line":534,"new":null,"old":null} From 2d5332f19cf0181bdf3df3b49a92b43e5eb7c682 Mon Sep 17 00:00:00 2001 From: Volkan Sagcan Date: Thu, 25 Apr 2024 17:02:40 +0200 Subject: [PATCH 09/22] wip --- .../generators/expression_generator.rs | 92 ++++++++++--------- .../tests/.directaccess_test.rs.pending-snap | 2 + ...am_with_var_out_called_in_program.snap.new | 28 ------ ...s__program_empty_inout_assignment.snap.new | 34 ------- src/tests/adr/.pou_adr.rs.pending-snap | 9 ++ 5 files changed, 58 insertions(+), 107 deletions(-) delete mode 100644 src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_var_out_called_in_program.snap.new delete mode 100644 src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_empty_inout_assignment.snap.new diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index 777796ac03c..8b7bf4a4d3d 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -523,7 +523,6 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { /// - `parameter_struct` a pointer to a struct-instance that holds all function-parameters /// - `function_name` the name of the callable /// - `parameters` vec of passed parameters to the call - // TODO: Rename this fucking function fn assign_output_values( &self, parameter_struct: PointerValue<'ink>, @@ -557,14 +556,26 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { dbg!(¶m_context.index); match param_context.assignment_statement.get_stmt() { // TODO: AstStatement::Assignment should not be a part of this? + AstStatement::OutputAssignment(data) => self.generate_explicit_output_assignment( + param_context.parameter_struct, + param_context.function_name, + param_context.assignment_statement, + ), + _ => self.generate_output_assignment(param_context), + } + + /* + match param_context.assignment_statement.get_stmt() { AstStatement::OutputAssignment(data) | AstStatement::Assignment(data) => self .generate_explicit_output_assignment( param_context.parameter_struct, param_context.function_name, - ¶m_context.assignment_statement, + &data.left, + &data.right, ), _ => self.generate_output_assignment(param_context), } + */ } fn temp_xxx( @@ -689,7 +700,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { panic!("or return?"); }; - if !parameter.get_variable_type().is_output() || expression.is_assignment() { + if !parameter.get_variable_type().is_output() { panic!("wtf... {parameter:#?}"); // return Ok(()); } @@ -702,25 +713,42 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { if !expression.is_empty_statement() { // FOO(x => y) // FOO(x => y.0) - let (node, access_type) = match expression.get_stmt() { - // TODO: Is the order (left, right) correct - AstStatement::OutputAssignment(data_assignment) - if data_assignment.right.has_direct_access() => - { - dbg!(&data_assignment); - ( - data_assignment.right.as_ref(), - self.annotations.get_type_hint(&data_assignment.right, self.index).unwrap(), - ) - } - - AstStatement::ReferenceExpr(expr) if expression.has_direct_access() => { + match expression.get_stmt() { + AstStatement::ReferenceExpr(_) if expression.has_direct_access() => { let _pou = dbg!(self.index.find_pou(function_name).unwrap()); let _struct = &_pou.find_instance_struct_type(self.index).unwrap().information; let DataTypeInformation::Struct { members, .. } = _struct else { panic!() }; let param = dbg!(&members[index as usize]); // TODO: Create a test for this; this fucks up if populating the members is not in order let dt = self.index.find_effective_type_by_name(¶m.data_type_name).unwrap(); - (expression, dt) + + let AstStatement::ReferenceExpr(ReferenceExpr { + access: ReferenceAccess::Member(member), + base, + }) = &expression.get_stmt() + else { + unreachable!("must be a bitaccess, will return early for all other cases") + }; + let base_value_rvalue = + base.as_ref().map(|it| self.generate_expression_value(it)).transpose()?; + + if let AstStatement::DirectAccess(_) = member.as_ref().get_stmt() { + let (Some(base), S_) = (base, ..) else { panic!() }; + // Step 1 + let error_bits_lvalue = self + .llvm_index + .find_loaded_associated_variable_value( + self.annotations.get_qualified_name(base).unwrap(), + ) + .unwrap(); + + // Step 2 + let q_lvalue = + self.llvm.builder.build_struct_gep(parameter_struct, index, "bbb").unwrap(); + + // lhs = lvalue + // rhs = astnode + self.temp_xxx(error_bits_lvalue, q_lvalue, &expression, &dt)?; + }; } _ => { @@ -757,33 +785,9 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let output_value = builder.build_load(output, ""); builder.build_store(assigned_output, output_value); } - return Ok(()); // todo!("handle fallthrough, return early; {expression:#?}") } }; - - let AstStatement::ReferenceExpr(ReferenceExpr { access: ReferenceAccess::Member(member), base }) = - &node.get_stmt() - else { - unreachable!("must be a bitaccess, will return early for all other cases") - }; - let base_value_rvalue = base.as_ref().map(|it| self.generate_expression_value(it)).transpose()?; - - if let AstStatement::DirectAccess(_) = member.as_ref().get_stmt() { - let (Some(base), _) = (base, ..) else { panic!() }; - // Step 1 - let error_bits_lvalue = self - .llvm_index - .find_loaded_associated_variable_value(self.annotations.get_qualified_name(base).unwrap()) - .unwrap(); - - // Step 2 - let q_lvalue = self.llvm.builder.build_struct_gep(parameter_struct, index, "bbb").unwrap(); - - // lhs = lvalue - // rhs = astnode - self.temp_xxx(error_bits_lvalue, q_lvalue, &node, &access_type)?; - }; } Ok(()) } @@ -794,9 +798,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { function_name: &str, assignment: &AstNode, ) -> Result<(), Diagnostic> { - let (AstStatement::OutputAssignment(Assignment { left, right: _ }) - | AstStatement::Assignment(Assignment { left, right: _ })) = &assignment.stmt - else { + let AstStatement::OutputAssignment(Assignment { left, right, .. }) = assignment.get_stmt() else { todo!() }; @@ -808,7 +810,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let index = parameter.get_location_in_parent(); self.generate_output_assignment(&CallParameterAssignment { - assignment_statement: assignment, + assignment_statement: right, function_name, index, parameter_struct, diff --git a/src/codegen/tests/.directaccess_test.rs.pending-snap b/src/codegen/tests/.directaccess_test.rs.pending-snap index 0614d7c19c2..9348628d53a 100644 --- a/src/codegen/tests/.directaccess_test.rs.pending-snap +++ b/src/codegen/tests/.directaccess_test.rs.pending-snap @@ -4,3 +4,5 @@ {"run_id":"1714055307-365730799","line":144,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_output_and_normal_assignments","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":144,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8, i8 }\n\n@__FOO__init = unnamed_addr constant %FOO zeroinitializer\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8][u8]\" {\nentry:\n %X = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n %Y = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 1\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 0, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits = load i8, i8* %error_bits, align 1\n %shift = lshr i8 %load_error_bits, 0\n %2 = and i8 %shift, 1\n store i8 %2, i8* %1, align 1\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %3 = load i8, i8* %error_bits, align 1\n %erase = and i8 %3, -2\n %4 = load i8, i8* %bbb, align 1\n %value = shl i8 %4, 0\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits1 = load i8, i8* %error_bits, align 1\n %shift2 = lshr i8 %load_error_bits1, 0\n %6 = and i8 %shift2, 1\n store i8 %6, i8* %5, align 1\n call void @FOO(%FOO* %f)\n %7 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits3 = load i8, i8* %error_bits, align 1\n %shift4 = lshr i8 %load_error_bits3, 0\n %8 = and i8 %shift4, 1\n store i8 %8, i8* %7, align 1\n call void @FOO(%FOO* %f)\n %bbb5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %9 = load i8, i8* %error_bits, align 1\n %erase6 = and i8 %9, -2\n %10 = load i8, i8* %bbb5, align 1\n %value7 = shl i8 %10, 0\n %or8 = or i8 %erase6, %value7\n store i8 %or8, i8* %error_bits, align 1\n %11 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits9 = load i8, i8* %error_bits, align 1\n %shift10 = lshr i8 %load_error_bits9, 0\n %12 = and i8 %shift10, 1\n store i8 %12, i8* %11, align 1\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":""}} {"run_id":"1714055699-714395630","line":264,"new":null,"old":null} {"run_id":"1714055699-714395630","line":201,"new":null,"old":null} +{"run_id":"1714057317-197787208","line":201,"new":null,"old":null} +{"run_id":"1714057317-197787208","line":264,"new":null,"old":null} diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_var_out_called_in_program.snap.new b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_var_out_called_in_program.snap.new deleted file mode 100644 index f4069dd3dc1..00000000000 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_var_out_called_in_program.snap.new +++ /dev/null @@ -1,28 +0,0 @@ ---- -source: src/codegen/tests/code_gen_tests.rs -assertion_line: 1747 -expression: result ---- -; ModuleID = 'main' -source_filename = "main" - -%foo = type { i32, i8 } -%prg = type { i8 } - -@foo_instance = global %foo zeroinitializer -@prg_instance = global %prg zeroinitializer - -define void @foo(%foo* %0) section "fn-foo:v[i32][u8]" { -entry: - %bar = getelementptr inbounds %foo, %foo* %0, i32 0, i32 0 - %buz = getelementptr inbounds %foo, %foo* %0, i32 0, i32 1 - ret void -} - -define void @prg(%prg* %0) section "fn-prg:v" { -entry: - %baz = getelementptr inbounds %prg, %prg* %0, i32 0, i32 0 - store i32 2, i32* getelementptr inbounds (%foo, %foo* @foo_instance, i32 0, i32 0), align 4 - call void @foo(%foo* @foo_instance) - ret void -} diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_empty_inout_assignment.snap.new b/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_empty_inout_assignment.snap.new deleted file mode 100644 index 8b2b801f908..00000000000 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_empty_inout_assignment.snap.new +++ /dev/null @@ -1,34 +0,0 @@ ---- -source: src/codegen/tests/parameters_tests.rs -assertion_line: 412 -expression: result ---- -; ModuleID = 'main' -source_filename = "main" - -%prog = type { i32, i32, i32* } -%main = type { i32, i32, i32 } - -@prog_instance = global %prog zeroinitializer -@main_instance = global %main zeroinitializer - -define void @prog(%prog* %0) section "fn-prog:v[i32][i32][pi32]" { -entry: - %input1 = getelementptr inbounds %prog, %prog* %0, i32 0, i32 0 - %output1 = getelementptr inbounds %prog, %prog* %0, i32 0, i32 1 - %inout1 = getelementptr inbounds %prog, %prog* %0, i32 0, i32 2 - ret void -} - -define void @main(%main* %0) section "fn-main:v" { -entry: - %var1 = getelementptr inbounds %main, %main* %0, i32 0, i32 0 - %var2 = getelementptr inbounds %main, %main* %0, i32 0, i32 1 - %var3 = getelementptr inbounds %main, %main* %0, i32 0, i32 2 - %load_var1 = load i32, i32* %var1, align 4 - store i32 %load_var1, i32* getelementptr inbounds (%prog, %prog* @prog_instance, i32 0, i32 0), align 4 - %empty_varinout = alloca i32, align 4 - store i32* %empty_varinout, i32** getelementptr inbounds (%prog, %prog* @prog_instance, i32 0, i32 2), align 8 - call void @prog(%prog* @prog_instance) - ret void -} diff --git a/src/tests/adr/.pou_adr.rs.pending-snap b/src/tests/adr/.pou_adr.rs.pending-snap index 6793d770e45..1a901d103f0 100644 --- a/src/tests/adr/.pou_adr.rs.pending-snap +++ b/src/tests/adr/.pou_adr.rs.pending-snap @@ -17,3 +17,12 @@ {"run_id":"1714055699-714395630","line":605,"new":null,"old":null} {"run_id":"1714055699-714395630","line":55,"new":null,"old":null} {"run_id":"1714055699-714395630","line":534,"new":null,"old":null} +{"run_id":"1714057317-197787208","line":472,"new":null,"old":null} +{"run_id":"1714057317-197787208","line":371,"new":null,"old":null} +{"run_id":"1714057317-197787208","line":430,"new":null,"old":null} +{"run_id":"1714057317-197787208","line":268,"new":null,"old":null} +{"run_id":"1714057317-197787208","line":605,"new":null,"old":null} +{"run_id":"1714057317-197787208","line":332,"new":null,"old":null} +{"run_id":"1714057317-197787208","line":55,"new":null,"old":null} +{"run_id":"1714057317-197787208","line":230,"new":null,"old":null} +{"run_id":"1714057317-197787208","line":534,"new":null,"old":null} From 3b8b0fb979ee5d0cca99bb5f0b2079c18618e25c Mon Sep 17 00:00:00 2001 From: Volkan Sagcan Date: Tue, 30 Apr 2024 12:13:04 +0000 Subject: [PATCH 10/22] wip --- .../generators/expression_generator.rs | 201 +++++++++--------- .../tests/.directaccess_test.rs.pending-snap | 10 + src/codegen/tests/parameters_tests.rs | 2 +- ...s_empty_statement_as_output_param.snap.new | 28 --- ...s_empty_statement_as_output_param.snap.new | 29 --- src/tests/adr/.pou_adr.rs.pending-snap | 45 ++++ 6 files changed, 157 insertions(+), 158 deletions(-) delete mode 100644 src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__fb_accepts_empty_statement_as_output_param.snap.new delete mode 100644 src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_accepts_empty_statement_as_output_param.snap.new diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index 8b7bf4a4d3d..177941fa675 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -203,8 +203,8 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { ) -> Result, Diagnostic> { //see if this is a constant - maybe we can short curcuit this codegen if let Some(StatementAnnotation::Variable { - qualified_name, constant: true, resulting_type, .. - }) = self.annotations.get(expression) + qualified_name, constant: true, resulting_type, .. + }) = self.annotations.get(expression) { if !self.index.get_type_information_or_void(resulting_type).is_aggregate() { match self.generate_constant_expression(qualified_name, expression) { @@ -594,9 +594,9 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let mut current = Some(left_statement); let mut access_sequence = Vec::new(); while let Some(AstStatement::ReferenceExpr(ReferenceExpr { - access: ReferenceAccess::Member(m), - base, - })) = current.map(|it| it.get_stmt()) + access: ReferenceAccess::Member(m), + base, + })) = current.map(|it| it.get_stmt()) { if matches!(m.get_stmt(), AstStatement::DirectAccess { .. }) { access_sequence.insert(0, m.as_ref()); @@ -609,9 +609,9 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { } let Some((target, access_sequence)) = collect_base_and_direct_access_for_assignment(left_statement) - else { - unreachable!("Invalid direct-access expression: {left_statement:#?}") - }; + else { + unreachable!("Invalid direct-access expression: {left_statement:#?}") + }; let left_type = self.get_type_hint_for(target)?; @@ -707,88 +707,89 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { // TODO: How to trigger an empty statement here, this: `FOO(Q => );`? if expression.is_empty_statement() { - panic!("we did it mom"); + // Something like `foo(out1 => )`, which means we can just return here because no + // assignment should happen + return Ok(()); } - if !expression.is_empty_statement() { - // FOO(x => y) - // FOO(x => y.0) - match expression.get_stmt() { - AstStatement::ReferenceExpr(_) if expression.has_direct_access() => { - let _pou = dbg!(self.index.find_pou(function_name).unwrap()); - let _struct = &_pou.find_instance_struct_type(self.index).unwrap().information; - let DataTypeInformation::Struct { members, .. } = _struct else { panic!() }; - let param = dbg!(&members[index as usize]); // TODO: Create a test for this; this fucks up if populating the members is not in order - let dt = self.index.find_effective_type_by_name(¶m.data_type_name).unwrap(); - - let AstStatement::ReferenceExpr(ReferenceExpr { - access: ReferenceAccess::Member(member), - base, - }) = &expression.get_stmt() + // FOO(x => y) + // FOO(x => y.0) + match expression.get_stmt() { + AstStatement::ReferenceExpr(_) if expression.has_direct_access() => { + let _pou = dbg!(self.index.find_pou(function_name).unwrap()); + let _struct = &_pou.find_instance_struct_type(self.index).unwrap().information; + let DataTypeInformation::Struct { members, .. } = _struct else { panic!() }; + let param = dbg!(&members[index as usize]); // TODO: Create a test for this; this fucks up if populating the members is not in order + let dt = self.index.find_effective_type_by_name(¶m.data_type_name).unwrap(); + + let AstStatement::ReferenceExpr(ReferenceExpr { + access: ReferenceAccess::Member(member), + base, + }) = &expression.get_stmt() else { unreachable!("must be a bitaccess, will return early for all other cases") }; - let base_value_rvalue = - base.as_ref().map(|it| self.generate_expression_value(it)).transpose()?; - - if let AstStatement::DirectAccess(_) = member.as_ref().get_stmt() { - let (Some(base), S_) = (base, ..) else { panic!() }; - // Step 1 - let error_bits_lvalue = self - .llvm_index - .find_loaded_associated_variable_value( - self.annotations.get_qualified_name(base).unwrap(), - ) - .unwrap(); - - // Step 2 - let q_lvalue = - self.llvm.builder.build_struct_gep(parameter_struct, index, "bbb").unwrap(); + let base_value_rvalue = + base.as_ref().map(|it| self.generate_expression_value(it)).transpose()?; + + if let AstStatement::DirectAccess(_) = member.as_ref().get_stmt() { + let (Some(base), S_) = (base, ..) else { panic!() }; + // Step 1 + let error_bits_lvalue = self + .llvm_index + .find_loaded_associated_variable_value( + self.annotations.get_qualified_name(base).unwrap(), + ) + .unwrap(); - // lhs = lvalue - // rhs = astnode - self.temp_xxx(error_bits_lvalue, q_lvalue, &expression, &dt)?; - }; - } + // Step 2 + let q_lvalue = + self.llvm.builder.build_struct_gep(parameter_struct, index, "bbb").unwrap(); - _ => { + // lhs = lvalue + // rhs = astnode dbg!(&expression); - let assigned_output = self.generate_lvalue(expression)?; + self.temp_xxx(error_bits_lvalue, q_lvalue, &expression, &dt)?; + }; + } - let assigned_output_type = - self.annotations.get_type_or_void(expression, self.index).get_type_information(); + _ => { + dbg!(&expression); + let assigned_output = self.generate_lvalue(expression)?; - let output = builder.build_struct_gep(parameter_struct, index, "").map_err(|_| { - Diagnostic::codegen_error( - format!("Cannot build generate parameter: {parameter:#?}"), - parameter.source_location.clone(), - ) - })?; + let assigned_output_type = + self.annotations.get_type_or_void(expression, self.index).get_type_information(); - let output_value_type = - self.index.get_type_information_or_void(parameter.get_type_name()); + let output = builder.build_struct_gep(parameter_struct, index, "").map_err(|_| { + Diagnostic::codegen_error( + format!("Cannot build generate parameter: {parameter:#?}"), + parameter.source_location.clone(), + ) + })?; - //Special string handling - if (assigned_output_type.is_string() && output_value_type.is_string()) - || (assigned_output_type.is_struct() && output_value_type.is_struct()) - || (assigned_output_type.is_array() && output_value_type.is_array()) - { - self.generate_string_store( - assigned_output, - assigned_output_type, - expression.get_location(), - output, - output_value_type, - parameter.source_location.clone(), - )?; - } else { - let output_value = builder.build_load(output, ""); - builder.build_store(assigned_output, output_value); - } - // todo!("handle fallthrough, return early; {expression:#?}") + let output_value_type = + self.index.get_type_information_or_void(parameter.get_type_name()); + + //Special string handling + if (assigned_output_type.is_string() && output_value_type.is_string()) + || (assigned_output_type.is_struct() && output_value_type.is_struct()) + || (assigned_output_type.is_array() && output_value_type.is_array()) + { + self.generate_string_store( + assigned_output, + assigned_output_type, + expression.get_location(), + output, + output_value_type, + parameter.source_location.clone(), + )?; + } else { + let output_value = builder.build_load(output, ""); + builder.build_store(assigned_output, output_value); } - }; - } + // todo!("handle fallthrough, return early; {expression:#?}") + } + }; Ok(()) } @@ -845,18 +846,18 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { } // TODO: find a more reliable way to make sure if this is a call into a local action!! PouIndexEntry::Action { .. } - if matches!( + if matches!( operator.get_stmt(), AstStatement::ReferenceExpr(ReferenceExpr { base: None, .. }) ) => - { - // special handling for local actions, get the parameter from the function context - function_context - .function - .get_first_param() - .map(|call_ptr| (None, call_ptr.into_pointer_value())) - .ok_or_else(|| Diagnostic::cannot_generate_call_statement(operator))? - } + { + // special handling for local actions, get the parameter from the function context + function_context + .function + .get_first_param() + .map(|call_ptr| (None, call_ptr.into_pointer_value())) + .ok_or_else(|| Diagnostic::cannot_generate_call_statement(operator))? + } _ => { let call_ptr = self.generate_lvalue(operator)?; (None, call_ptr) @@ -949,7 +950,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { if pou.is_variadic() { let last_location = result.len(); for (i, parameter) in - self.generate_variadic_arguments_list(pou, &variadic_parameters)?.into_iter().enumerate() + self.generate_variadic_arguments_list(pou, &variadic_parameters)?.into_iter().enumerate() { result.push((i + last_location, parameter)); } @@ -1521,7 +1522,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { } else { 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> { @@ -2114,8 +2115,8 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { "Cannot generate String-Literal for type {}", expected_type.get_name() )) - .with_error_code("E074") - .with_location(location)), + .with_error_code("E074") + .with_location(location)), } } @@ -2397,7 +2398,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { return Err(Diagnostic::codegen_error( format!("Cannot generate phi-expression for operator {operator:}"), left.get_location(), - )) + )); } }; @@ -2447,7 +2448,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { self.get_type_hint_for(left)?.get_name(), self.get_type_hint_for(right)?.get_name(), ) - .as_str(), + .as_str(), left.get_location(), )) } @@ -2576,9 +2577,9 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { // array access is either directly on a reference or on another array access (ARRAY OF ARRAY) let StatementAnnotation::Variable { resulting_type: reference_type, .. } = reference_annotation - else { - unreachable!(); - }; + else { + unreachable!(); + }; let struct_ptr = reference.get_basic_value_enum().into_pointer_value(); @@ -2663,7 +2664,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { (ReferenceAccess::Member(member), base) => { let base_value = base.map(|it| self.generate_expression_value(it)).transpose()?; - if let AstStatement::DirectAccess (data) = member.as_ref().get_stmt() { + if let AstStatement::DirectAccess(data) = member.as_ref().get_stmt() { let (Some(base), Some(base_value)) = (base, base_value) else { return Err(Diagnostic::codegen_error("Cannot generate DirectAccess without base value.", original_expression.get_location())); }; @@ -2675,7 +2676,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { self.get_load_name(member).as_deref().unwrap_or(member_name), original_expression, ) - .map(ExpressionValue::LValue) + .map(ExpressionValue::LValue) } } @@ -2688,8 +2689,8 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { self.annotations.get(base).expect(""), array_idx.as_ref(), ) - .map_err(|_| unreachable!("invalid access statement")) - .map(ExpressionValue::LValue) + .map_err(|_| unreachable!("invalid access statement")) + .map(ExpressionValue::LValue) } else { // normal array expression self.generate_element_pointer_for_array(base, array_idx).map(ExpressionValue::LValue) @@ -2727,7 +2728,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { | (ReferenceAccess::Cast(_), None) // INT#; | (ReferenceAccess::Deref, None) // ^; | (ReferenceAccess::Address, None) // &; - => Err(Diagnostic::codegen_error( + => Err(Diagnostic::codegen_error( "Expected a base-expressions, but found none.", original_expression.get_location(), )), diff --git a/src/codegen/tests/.directaccess_test.rs.pending-snap b/src/codegen/tests/.directaccess_test.rs.pending-snap index 9348628d53a..13cb14c80ec 100644 --- a/src/codegen/tests/.directaccess_test.rs.pending-snap +++ b/src/codegen/tests/.directaccess_test.rs.pending-snap @@ -6,3 +6,13 @@ {"run_id":"1714055699-714395630","line":201,"new":null,"old":null} {"run_id":"1714057317-197787208","line":201,"new":null,"old":null} {"run_id":"1714057317-197787208","line":264,"new":null,"old":null} +{"run_id":"1714463899-874175903","line":264,"new":null,"old":null} +{"run_id":"1714463899-874175903","line":201,"new":null,"old":null} +{"run_id":"1714478129-236604043","line":201,"new":null,"old":null} +{"run_id":"1714478129-236604043","line":264,"new":null,"old":null} +{"run_id":"1714478680-12131851","line":201,"new":null,"old":null} +{"run_id":"1714478680-12131851","line":264,"new":null,"old":null} +{"run_id":"1714478890-666684973","line":201,"new":null,"old":null} +{"run_id":"1714478890-666684973","line":264,"new":null,"old":null} +{"run_id":"1714478983-408122767","line":201,"new":null,"old":null} +{"run_id":"1714478983-408122767","line":264,"new":null,"old":null} diff --git a/src/codegen/tests/parameters_tests.rs b/src/codegen/tests/parameters_tests.rs index 76530faa8bd..83adcbf8f70 100644 --- a/src/codegen/tests/parameters_tests.rs +++ b/src/codegen/tests/parameters_tests.rs @@ -20,7 +20,7 @@ fn function_all_parameters_assigned() { PROGRAM main VAR var1, var2, var3 : DINT; - END_VAR + END_VAprogram_accepts_empty_statement_as_output_paramR foo(var1, var2, var3); foo(input1 := var1, output1 => var2, inout1 := var3); foo(inout1 := var3, input1 := var1, output1 => var2); diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__fb_accepts_empty_statement_as_output_param.snap.new b/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__fb_accepts_empty_statement_as_output_param.snap.new deleted file mode 100644 index 2581d9cd323..00000000000 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__fb_accepts_empty_statement_as_output_param.snap.new +++ /dev/null @@ -1,28 +0,0 @@ ---- -source: src/codegen/tests/parameters_tests.rs -assertion_line: 570 -expression: result ---- -; ModuleID = 'main' -source_filename = "main" - -%fb_t = type { i32, i32 } -%main = type { %fb_t, i32 } - -@__fb_t__init = unnamed_addr constant %fb_t zeroinitializer -@main_instance = global %main zeroinitializer - -define void @fb_t(%fb_t* %0) section "fn-fb_t:v[i32][i32]" { -entry: - %out1 = getelementptr inbounds %fb_t, %fb_t* %0, i32 0, i32 0 - %out2 = getelementptr inbounds %fb_t, %fb_t* %0, i32 0, i32 1 - ret void -} - -define void @main(%main* %0) section "fn-main:v" { -entry: - %fb = getelementptr inbounds %main, %main* %0, i32 0, i32 0 - %x = getelementptr inbounds %main, %main* %0, i32 0, i32 1 - call void @fb_t(%fb_t* %fb) - ret void -} diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_accepts_empty_statement_as_output_param.snap.new b/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_accepts_empty_statement_as_output_param.snap.new deleted file mode 100644 index 74e50a47ed5..00000000000 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_accepts_empty_statement_as_output_param.snap.new +++ /dev/null @@ -1,29 +0,0 @@ ---- -source: src/codegen/tests/parameters_tests.rs -assertion_line: 519 -expression: result ---- -; ModuleID = 'main' -source_filename = "main" - -%prog = type { i32, i32 } -%main = type { i32 } - -@prog_instance = global %prog zeroinitializer -@main_instance = global %main zeroinitializer - -define void @prog(%prog* %0) section "fn-prog:v[i32][i32]" { -entry: - %out1 = getelementptr inbounds %prog, %prog* %0, i32 0, i32 0 - %out2 = getelementptr inbounds %prog, %prog* %0, i32 0, i32 1 - store i32 1, i32* %out1, align 4 - store i32 2, i32* %out2, align 4 - ret void -} - -define void @main(%main* %0) section "fn-main:v" { -entry: - %x = getelementptr inbounds %main, %main* %0, i32 0, i32 0 - call void @prog(%prog* @prog_instance) - ret void -} diff --git a/src/tests/adr/.pou_adr.rs.pending-snap b/src/tests/adr/.pou_adr.rs.pending-snap index 1a901d103f0..94cd56dc3cc 100644 --- a/src/tests/adr/.pou_adr.rs.pending-snap +++ b/src/tests/adr/.pou_adr.rs.pending-snap @@ -26,3 +26,48 @@ {"run_id":"1714057317-197787208","line":55,"new":null,"old":null} {"run_id":"1714057317-197787208","line":230,"new":null,"old":null} {"run_id":"1714057317-197787208","line":534,"new":null,"old":null} +{"run_id":"1714463899-874175903","line":472,"new":null,"old":null} +{"run_id":"1714463899-874175903","line":230,"new":null,"old":null} +{"run_id":"1714463899-874175903","line":371,"new":null,"old":null} +{"run_id":"1714463899-874175903","line":268,"new":null,"old":null} +{"run_id":"1714463899-874175903","line":605,"new":null,"old":null} +{"run_id":"1714463899-874175903","line":332,"new":null,"old":null} +{"run_id":"1714463899-874175903","line":55,"new":null,"old":null} +{"run_id":"1714463899-874175903","line":430,"new":null,"old":null} +{"run_id":"1714463899-874175903","line":534,"new":null,"old":null} +{"run_id":"1714478129-236604043","line":472,"new":null,"old":null} +{"run_id":"1714478129-236604043","line":371,"new":null,"old":null} +{"run_id":"1714478129-236604043","line":332,"new":null,"old":null} +{"run_id":"1714478129-236604043","line":268,"new":null,"old":null} +{"run_id":"1714478129-236604043","line":430,"new":null,"old":null} +{"run_id":"1714478129-236604043","line":230,"new":null,"old":null} +{"run_id":"1714478129-236604043","line":605,"new":null,"old":null} +{"run_id":"1714478129-236604043","line":55,"new":null,"old":null} +{"run_id":"1714478129-236604043","line":534,"new":null,"old":null} +{"run_id":"1714478680-12131851","line":230,"new":null,"old":null} +{"run_id":"1714478680-12131851","line":371,"new":null,"old":null} +{"run_id":"1714478680-12131851","line":268,"new":null,"old":null} +{"run_id":"1714478680-12131851","line":332,"new":null,"old":null} +{"run_id":"1714478680-12131851","line":55,"new":null,"old":null} +{"run_id":"1714478680-12131851","line":605,"new":null,"old":null} +{"run_id":"1714478680-12131851","line":430,"new":null,"old":null} +{"run_id":"1714478680-12131851","line":472,"new":null,"old":null} +{"run_id":"1714478680-12131851","line":534,"new":null,"old":null} +{"run_id":"1714478890-666684973","line":371,"new":null,"old":null} +{"run_id":"1714478890-666684973","line":268,"new":null,"old":null} +{"run_id":"1714478890-666684973","line":430,"new":null,"old":null} +{"run_id":"1714478890-666684973","line":332,"new":null,"old":null} +{"run_id":"1714478890-666684973","line":472,"new":null,"old":null} +{"run_id":"1714478890-666684973","line":605,"new":null,"old":null} +{"run_id":"1714478890-666684973","line":230,"new":null,"old":null} +{"run_id":"1714478890-666684973","line":55,"new":null,"old":null} +{"run_id":"1714478890-666684973","line":534,"new":null,"old":null} +{"run_id":"1714478983-408122767","line":472,"new":null,"old":null} +{"run_id":"1714478983-408122767","line":371,"new":null,"old":null} +{"run_id":"1714478983-408122767","line":268,"new":null,"old":null} +{"run_id":"1714478983-408122767","line":230,"new":null,"old":null} +{"run_id":"1714478983-408122767","line":332,"new":null,"old":null} +{"run_id":"1714478983-408122767","line":430,"new":null,"old":null} +{"run_id":"1714478983-408122767","line":605,"new":null,"old":null} +{"run_id":"1714478983-408122767","line":55,"new":null,"old":null} +{"run_id":"1714478983-408122767","line":534,"new":null,"old":null} From b6206892b35a625480425e4eb107d951da11ac3f Mon Sep 17 00:00:00 2001 From: Volkan Sagcan Date: Wed, 22 May 2024 10:16:09 +0200 Subject: [PATCH 11/22] fmt --- .../generators/expression_generator.rs | 65 +++++++++---------- .../tests/.directaccess_test.rs.pending-snap | 12 ++++ src/tests/adr/.pou_adr.rs.pending-snap | 54 +++++++++++++++ 3 files changed, 98 insertions(+), 33 deletions(-) diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index 177941fa675..1bd9de49fb8 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -203,8 +203,8 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { ) -> Result, Diagnostic> { //see if this is a constant - maybe we can short curcuit this codegen if let Some(StatementAnnotation::Variable { - qualified_name, constant: true, resulting_type, .. - }) = self.annotations.get(expression) + qualified_name, constant: true, resulting_type, .. + }) = self.annotations.get(expression) { if !self.index.get_type_information_or_void(resulting_type).is_aggregate() { match self.generate_constant_expression(qualified_name, expression) { @@ -594,9 +594,9 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let mut current = Some(left_statement); let mut access_sequence = Vec::new(); while let Some(AstStatement::ReferenceExpr(ReferenceExpr { - access: ReferenceAccess::Member(m), - base, - })) = current.map(|it| it.get_stmt()) + access: ReferenceAccess::Member(m), + base, + })) = current.map(|it| it.get_stmt()) { if matches!(m.get_stmt(), AstStatement::DirectAccess { .. }) { access_sequence.insert(0, m.as_ref()); @@ -609,9 +609,9 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { } let Some((target, access_sequence)) = collect_base_and_direct_access_for_assignment(left_statement) - else { - unreachable!("Invalid direct-access expression: {left_statement:#?}") - }; + else { + unreachable!("Invalid direct-access expression: {left_statement:#?}") + }; let left_type = self.get_type_hint_for(target)?; @@ -723,12 +723,12 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let dt = self.index.find_effective_type_by_name(¶m.data_type_name).unwrap(); let AstStatement::ReferenceExpr(ReferenceExpr { - access: ReferenceAccess::Member(member), - base, - }) = &expression.get_stmt() - else { - unreachable!("must be a bitaccess, will return early for all other cases") - }; + access: ReferenceAccess::Member(member), + base, + }) = &expression.get_stmt() + else { + unreachable!("must be a bitaccess, will return early for all other cases") + }; let base_value_rvalue = base.as_ref().map(|it| self.generate_expression_value(it)).transpose()?; @@ -767,8 +767,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { ) })?; - let output_value_type = - self.index.get_type_information_or_void(parameter.get_type_name()); + let output_value_type = self.index.get_type_information_or_void(parameter.get_type_name()); //Special string handling if (assigned_output_type.is_string() && output_value_type.is_string()) @@ -846,18 +845,18 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { } // TODO: find a more reliable way to make sure if this is a call into a local action!! PouIndexEntry::Action { .. } - if matches!( + if matches!( operator.get_stmt(), AstStatement::ReferenceExpr(ReferenceExpr { base: None, .. }) ) => - { - // special handling for local actions, get the parameter from the function context - function_context - .function - .get_first_param() - .map(|call_ptr| (None, call_ptr.into_pointer_value())) - .ok_or_else(|| Diagnostic::cannot_generate_call_statement(operator))? - } + { + // special handling for local actions, get the parameter from the function context + function_context + .function + .get_first_param() + .map(|call_ptr| (None, call_ptr.into_pointer_value())) + .ok_or_else(|| Diagnostic::cannot_generate_call_statement(operator))? + } _ => { let call_ptr = self.generate_lvalue(operator)?; (None, call_ptr) @@ -950,7 +949,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { if pou.is_variadic() { let last_location = result.len(); for (i, parameter) in - self.generate_variadic_arguments_list(pou, &variadic_parameters)?.into_iter().enumerate() + self.generate_variadic_arguments_list(pou, &variadic_parameters)?.into_iter().enumerate() { result.push((i + last_location, parameter)); } @@ -1522,7 +1521,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { } else { 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> { @@ -2115,8 +2114,8 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { "Cannot generate String-Literal for type {}", expected_type.get_name() )) - .with_error_code("E074") - .with_location(location)), + .with_error_code("E074") + .with_location(location)), } } @@ -2448,7 +2447,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { self.get_type_hint_for(left)?.get_name(), self.get_type_hint_for(right)?.get_name(), ) - .as_str(), + .as_str(), left.get_location(), )) } @@ -2577,9 +2576,9 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { // array access is either directly on a reference or on another array access (ARRAY OF ARRAY) let StatementAnnotation::Variable { resulting_type: reference_type, .. } = reference_annotation - else { - unreachable!(); - }; + else { + unreachable!(); + }; let struct_ptr = reference.get_basic_value_enum().into_pointer_value(); diff --git a/src/codegen/tests/.directaccess_test.rs.pending-snap b/src/codegen/tests/.directaccess_test.rs.pending-snap index 13cb14c80ec..369091c64b6 100644 --- a/src/codegen/tests/.directaccess_test.rs.pending-snap +++ b/src/codegen/tests/.directaccess_test.rs.pending-snap @@ -16,3 +16,15 @@ {"run_id":"1714478890-666684973","line":264,"new":null,"old":null} {"run_id":"1714478983-408122767","line":201,"new":null,"old":null} {"run_id":"1714478983-408122767","line":264,"new":null,"old":null} +{"run_id":"1716364259-328637857","line":264,"new":null,"old":null} +{"run_id":"1716364259-328637857","line":201,"new":null,"old":null} +{"run_id":"1716364327-746662311","line":264,"new":null,"old":null} +{"run_id":"1716364327-746662311","line":201,"new":null,"old":null} +{"run_id":"1716364821-96071461","line":201,"new":null,"old":null} +{"run_id":"1716364821-96071461","line":264,"new":null,"old":null} +{"run_id":"1716365133-78651533","line":201,"new":null,"old":null} +{"run_id":"1716365133-78651533","line":264,"new":null,"old":null} +{"run_id":"1716365147-313869683","line":201,"new":null,"old":null} +{"run_id":"1716365147-313869683","line":264,"new":null,"old":null} +{"run_id":"1716365158-976762975","line":264,"new":null,"old":null} +{"run_id":"1716365158-976762975","line":201,"new":null,"old":null} diff --git a/src/tests/adr/.pou_adr.rs.pending-snap b/src/tests/adr/.pou_adr.rs.pending-snap index 94cd56dc3cc..c380d60adfa 100644 --- a/src/tests/adr/.pou_adr.rs.pending-snap +++ b/src/tests/adr/.pou_adr.rs.pending-snap @@ -71,3 +71,57 @@ {"run_id":"1714478983-408122767","line":605,"new":null,"old":null} {"run_id":"1714478983-408122767","line":55,"new":null,"old":null} {"run_id":"1714478983-408122767","line":534,"new":null,"old":null} +{"run_id":"1716364259-328637857","line":230,"new":null,"old":null} +{"run_id":"1716364259-328637857","line":605,"new":null,"old":null} +{"run_id":"1716364259-328637857","line":268,"new":null,"old":null} +{"run_id":"1716364259-328637857","line":430,"new":null,"old":null} +{"run_id":"1716364259-328637857","line":332,"new":null,"old":null} +{"run_id":"1716364259-328637857","line":371,"new":null,"old":null} +{"run_id":"1716364259-328637857","line":55,"new":null,"old":null} +{"run_id":"1716364259-328637857","line":472,"new":null,"old":null} +{"run_id":"1716364259-328637857","line":534,"new":null,"old":null} +{"run_id":"1716364327-746662311","line":230,"new":null,"old":null} +{"run_id":"1716364327-746662311","line":332,"new":null,"old":null} +{"run_id":"1716364327-746662311","line":430,"new":null,"old":null} +{"run_id":"1716364327-746662311","line":472,"new":null,"old":null} +{"run_id":"1716364327-746662311","line":605,"new":null,"old":null} +{"run_id":"1716364327-746662311","line":268,"new":null,"old":null} +{"run_id":"1716364327-746662311","line":55,"new":null,"old":null} +{"run_id":"1716364327-746662311","line":371,"new":null,"old":null} +{"run_id":"1716364327-746662311","line":534,"new":null,"old":null} +{"run_id":"1716364821-96071461","line":55,"new":null,"old":null} +{"run_id":"1716364821-96071461","line":230,"new":null,"old":null} +{"run_id":"1716364821-96071461","line":430,"new":null,"old":null} +{"run_id":"1716364821-96071461","line":472,"new":null,"old":null} +{"run_id":"1716364821-96071461","line":371,"new":null,"old":null} +{"run_id":"1716364821-96071461","line":605,"new":null,"old":null} +{"run_id":"1716364821-96071461","line":268,"new":null,"old":null} +{"run_id":"1716364821-96071461","line":332,"new":null,"old":null} +{"run_id":"1716364821-96071461","line":534,"new":null,"old":null} +{"run_id":"1716365133-78651533","line":230,"new":null,"old":null} +{"run_id":"1716365133-78651533","line":430,"new":null,"old":null} +{"run_id":"1716365133-78651533","line":332,"new":null,"old":null} +{"run_id":"1716365133-78651533","line":605,"new":null,"old":null} +{"run_id":"1716365133-78651533","line":268,"new":null,"old":null} +{"run_id":"1716365133-78651533","line":55,"new":null,"old":null} +{"run_id":"1716365133-78651533","line":472,"new":null,"old":null} +{"run_id":"1716365133-78651533","line":534,"new":null,"old":null} +{"run_id":"1716365133-78651533","line":371,"new":null,"old":null} +{"run_id":"1716365147-313869683","line":230,"new":null,"old":null} +{"run_id":"1716365147-313869683","line":430,"new":null,"old":null} +{"run_id":"1716365147-313869683","line":472,"new":null,"old":null} +{"run_id":"1716365147-313869683","line":55,"new":null,"old":null} +{"run_id":"1716365147-313869683","line":605,"new":null,"old":null} +{"run_id":"1716365147-313869683","line":371,"new":null,"old":null} +{"run_id":"1716365147-313869683","line":268,"new":null,"old":null} +{"run_id":"1716365147-313869683","line":332,"new":null,"old":null} +{"run_id":"1716365147-313869683","line":534,"new":null,"old":null} +{"run_id":"1716365158-976762975","line":230,"new":null,"old":null} +{"run_id":"1716365158-976762975","line":430,"new":null,"old":null} +{"run_id":"1716365158-976762975","line":55,"new":null,"old":null} +{"run_id":"1716365158-976762975","line":268,"new":null,"old":null} +{"run_id":"1716365158-976762975","line":332,"new":null,"old":null} +{"run_id":"1716365158-976762975","line":371,"new":null,"old":null} +{"run_id":"1716365158-976762975","line":605,"new":null,"old":null} +{"run_id":"1716365158-976762975","line":472,"new":null,"old":null} +{"run_id":"1716365158-976762975","line":534,"new":null,"old":null} From 467e5ad9d42cd19c87ac696ebf0dcb8831caafd9 Mon Sep 17 00:00:00 2001 From: Volkan Sagcan Date: Thu, 23 May 2024 08:14:19 +0200 Subject: [PATCH 12/22] Fix test input --- .../generators/expression_generator.rs | 1 - .../tests/.directaccess_test.rs.pending-snap | 6 ++++ src/codegen/tests/parameters_tests.rs | 2 +- src/tests/adr/.pou_adr.rs.pending-snap | 30 +++++++++++++++++++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index 8ff80f8804d..257aff52f50 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -42,7 +42,6 @@ use crate::{ }, }; use rustc_hash::FxHashSet; -use std::vec; use super::{llvm::Llvm, statement_generator::FunctionContext, ADDRESS_SPACE_CONST, ADDRESS_SPACE_GENERIC}; diff --git a/src/codegen/tests/.directaccess_test.rs.pending-snap b/src/codegen/tests/.directaccess_test.rs.pending-snap index 369091c64b6..d16bc676d7e 100644 --- a/src/codegen/tests/.directaccess_test.rs.pending-snap +++ b/src/codegen/tests/.directaccess_test.rs.pending-snap @@ -28,3 +28,9 @@ {"run_id":"1716365147-313869683","line":264,"new":null,"old":null} {"run_id":"1716365158-976762975","line":264,"new":null,"old":null} {"run_id":"1716365158-976762975","line":201,"new":null,"old":null} +{"run_id":"1716444789-194071813","line":201,"new":null,"old":null} +{"run_id":"1716444789-194071813","line":264,"new":null,"old":null} +{"run_id":"1716444819-152604503","line":264,"new":null,"old":null} +{"run_id":"1716444819-152604503","line":201,"new":null,"old":null} +{"run_id":"1716444851-574207320","line":201,"new":null,"old":null} +{"run_id":"1716444851-574207320","line":264,"new":null,"old":null} diff --git a/src/codegen/tests/parameters_tests.rs b/src/codegen/tests/parameters_tests.rs index 07aae93e5f6..e816c43742f 100644 --- a/src/codegen/tests/parameters_tests.rs +++ b/src/codegen/tests/parameters_tests.rs @@ -21,7 +21,7 @@ fn function_all_parameters_assigned() { PROGRAM main VAR var1, var2, var3 : DINT; - END_VAprogram_accepts_empty_statement_as_output_paramR + END_VAR foo(var1, var2, var3); foo(input1 := var1, output1 => var2, inout1 := var3); foo(inout1 := var3, input1 := var1, output1 => var2); diff --git a/src/tests/adr/.pou_adr.rs.pending-snap b/src/tests/adr/.pou_adr.rs.pending-snap index c380d60adfa..8107ff8f1c3 100644 --- a/src/tests/adr/.pou_adr.rs.pending-snap +++ b/src/tests/adr/.pou_adr.rs.pending-snap @@ -125,3 +125,33 @@ {"run_id":"1716365158-976762975","line":605,"new":null,"old":null} {"run_id":"1716365158-976762975","line":472,"new":null,"old":null} {"run_id":"1716365158-976762975","line":534,"new":null,"old":null} +{"run_id":"1716444789-194071813","line":230,"new":null,"old":null} +{"run_id":"1716444789-194071813","line":430,"new":null,"old":null} +{"run_id":"1716444789-194071813","line":268,"new":null,"old":null} +{"run_id":"1716444789-194071813","line":371,"new":null,"old":null} +{"run_id":"1716444789-194071813","line":616,"new":null,"old":null} +{"run_id":"1716444789-194071813","line":332,"new":null,"old":null} +{"run_id":"1716444789-194071813","line":702,"new":null,"old":null} +{"run_id":"1716444789-194071813","line":472,"new":null,"old":null} +{"run_id":"1716444789-194071813","line":534,"new":null,"old":null} +{"run_id":"1716444789-194071813","line":55,"new":null,"old":null} +{"run_id":"1716444819-152604503","line":230,"new":null,"old":null} +{"run_id":"1716444819-152604503","line":430,"new":null,"old":null} +{"run_id":"1716444819-152604503","line":332,"new":null,"old":null} +{"run_id":"1716444819-152604503","line":268,"new":null,"old":null} +{"run_id":"1716444819-152604503","line":702,"new":null,"old":null} +{"run_id":"1716444819-152604503","line":371,"new":null,"old":null} +{"run_id":"1716444819-152604503","line":55,"new":null,"old":null} +{"run_id":"1716444819-152604503","line":472,"new":null,"old":null} +{"run_id":"1716444819-152604503","line":616,"new":null,"old":null} +{"run_id":"1716444819-152604503","line":534,"new":null,"old":null} +{"run_id":"1716444851-574207320","line":472,"new":null,"old":null} +{"run_id":"1716444851-574207320","line":230,"new":null,"old":null} +{"run_id":"1716444851-574207320","line":430,"new":null,"old":null} +{"run_id":"1716444851-574207320","line":332,"new":null,"old":null} +{"run_id":"1716444851-574207320","line":55,"new":null,"old":null} +{"run_id":"1716444851-574207320","line":371,"new":null,"old":null} +{"run_id":"1716444851-574207320","line":702,"new":null,"old":null} +{"run_id":"1716444851-574207320","line":268,"new":null,"old":null} +{"run_id":"1716444851-574207320","line":534,"new":null,"old":null} +{"run_id":"1716444851-574207320","line":616,"new":null,"old":null} From 268c59f9f740eb243b983c9f1155637ec462c272 Mon Sep 17 00:00:00 2001 From: Volkan Sagcan Date: Thu, 23 May 2024 09:06:24 +0200 Subject: [PATCH 13/22] fix tests --- compiler/plc_ast/src/ast.rs | 4 + .../generators/expression_generator.rs | 30 +++---- .../tests/.directaccess_test.rs.pending-snap | 22 +++++ ...h_var_out_called_mixed_in_program.snap.new | 28 ------- ..._all_parameters_assigned_explicit.snap.new | 37 --------- ..._program_missing_input_assignment.snap.new | 31 ------- src/tests/adr/.pou_adr.rs.pending-snap | 80 +++++++++++++++++++ 7 files changed, 118 insertions(+), 114 deletions(-) delete mode 100644 src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_var_out_called_mixed_in_program.snap.new delete mode 100644 src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_all_parameters_assigned_explicit.snap.new delete mode 100644 src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_missing_input_assignment.snap.new diff --git a/compiler/plc_ast/src/ast.rs b/compiler/plc_ast/src/ast.rs index e897112799d..cf623d98abe 100644 --- a/compiler/plc_ast/src/ast.rs +++ b/compiler/plc_ast/src/ast.rs @@ -859,6 +859,10 @@ impl AstNode { matches!(self.stmt, AstStatement::Assignment(..)) } + pub fn is_output_assignment(&self) -> bool { + matches!(self.stmt, AstStatement::OutputAssignment(..)) + } + pub fn is_reference(&self) -> bool { matches!(self.stmt, AstStatement::ReferenceExpr(..)) } diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index 257aff52f50..deed71782d4 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -539,9 +539,18 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { // parameter = vec![bar] let pou_info = self.index.get_declared_parameters(function_name); + let mut implicit = true; + for statement in parameters.iter() { + if statement.is_assignment() || statement.is_output_assignment() { + implicit = false; + break; + } + } + for (index, assignment_statement) in parameters.into_iter().enumerate() { + let temp = pou_info.get(index).is_some_and(|it| it.get_variable_type().is_output()); // TODO: Filter this - if pou_info.get(index).is_some_and(|it| it.get_variable_type().is_output()) { + if assignment_statement.is_output_assignment() || (implicit && temp) { self.assign_output_value(&CallParameterAssignment { assignment_statement, function_name, @@ -554,7 +563,6 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { } fn assign_output_value(&self, param_context: &CallParameterAssignment) -> Result<(), Diagnostic> { - dbg!(¶m_context.index); match param_context.assignment_statement.get_stmt() { // TODO: AstStatement::Assignment should not be a part of this? AstStatement::OutputAssignment(data) => self.generate_explicit_output_assignment( @@ -562,21 +570,9 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { param_context.function_name, param_context.assignment_statement, ), - _ => self.generate_output_assignment(param_context), - } - /* - match param_context.assignment_statement.get_stmt() { - AstStatement::OutputAssignment(data) | AstStatement::Assignment(data) => self - .generate_explicit_output_assignment( - param_context.parameter_struct, - param_context.function_name, - &data.left, - &data.right, - ), _ => self.generate_output_assignment(param_context), } - */ } fn temp_xxx( @@ -717,10 +713,10 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { // FOO(x => y.0) match expression.get_stmt() { AstStatement::ReferenceExpr(_) if expression.has_direct_access() => { - let _pou = dbg!(self.index.find_pou(function_name).unwrap()); + let _pou = self.index.find_pou(function_name).unwrap(); let _struct = &_pou.find_instance_struct_type(self.index).unwrap().information; let DataTypeInformation::Struct { members, .. } = _struct else { panic!() }; - let param = dbg!(&members[index as usize]); // TODO: Create a test for this; this fucks up if populating the members is not in order + let param = &members[index as usize]; // TODO: Create a test for this; this fucks up if populating the members is not in order let dt = self.index.find_effective_type_by_name(¶m.data_type_name).unwrap(); let AstStatement::ReferenceExpr(ReferenceExpr { @@ -749,13 +745,11 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { // lhs = lvalue // rhs = astnode - dbg!(&expression); self.temp_xxx(error_bits_lvalue, q_lvalue, &expression, &dt)?; }; } _ => { - dbg!(&expression); let assigned_output = self.generate_lvalue(expression)?; let assigned_output_type = diff --git a/src/codegen/tests/.directaccess_test.rs.pending-snap b/src/codegen/tests/.directaccess_test.rs.pending-snap index d16bc676d7e..1af2545de5d 100644 --- a/src/codegen/tests/.directaccess_test.rs.pending-snap +++ b/src/codegen/tests/.directaccess_test.rs.pending-snap @@ -34,3 +34,25 @@ {"run_id":"1716444819-152604503","line":201,"new":null,"old":null} {"run_id":"1716444851-574207320","line":201,"new":null,"old":null} {"run_id":"1716444851-574207320","line":264,"new":null,"old":null} +{"run_id":"1716444885-28893355","line":201,"new":null,"old":null} +{"run_id":"1716444885-28893355","line":264,"new":null,"old":null} +{"run_id":"1716446701-512418354","line":201,"new":null,"old":null} +{"run_id":"1716446701-512418354","line":264,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_implicit","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":264,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8 }\n\n@__FOO__init = unnamed_addr constant %FOO { i8 1 }\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8]\" {\nentry:\n %Q = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 -17, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8 }\n\n@__FOO__init = unnamed_addr constant %FOO { i8 1 }\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8]\" {\nentry:\n %Q = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 -17, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %1 = load i8, i8* %error_bits, align 1\n %erase = and i8 %1, -17\n %2 = load i8, i8* %bbb, align 1\n %value = shl i8 %2, 4\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }"}} +{"run_id":"1716446701-512418354","line":144,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_output_and_normal_assignments","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":144,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8, i8 }\n\n@__FOO__init = unnamed_addr constant %FOO zeroinitializer\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8][u8]\" {\nentry:\n %X = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n %Y = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 1\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 0, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits = load i8, i8* %error_bits, align 1\n %shift = lshr i8 %load_error_bits, 0\n %2 = and i8 %shift, 1\n store i8 %2, i8* %1, align 1\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %3 = load i8, i8* %error_bits, align 1\n %erase = and i8 %3, -2\n %4 = load i8, i8* %bbb, align 1\n %value = shl i8 %4, 0\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits1 = load i8, i8* %error_bits, align 1\n %shift2 = lshr i8 %load_error_bits1, 0\n %6 = and i8 %shift2, 1\n store i8 %6, i8* %5, align 1\n call void @FOO(%FOO* %f)\n %bbb3 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %7 = load i8, i8* %error_bits, align 1\n %erase4 = and i8 %7, -2\n %8 = load i8, i8* %bbb3, align 1\n %value5 = shl i8 %8, 0\n %or6 = or i8 %erase4, %value5\n store i8 %or6, i8* %error_bits, align 1\n %9 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits7 = load i8, i8* %error_bits, align 1\n %shift8 = lshr i8 %load_error_bits7, 0\n %10 = and i8 %shift8, 1\n store i8 %10, i8* %9, align 1\n call void @FOO(%FOO* %f)\n %11 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits9 = load i8, i8* %error_bits, align 1\n %shift10 = lshr i8 %load_error_bits9, 0\n %12 = and i8 %shift10, 1\n store i8 %12, i8* %11, align 1\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":""}} +{"run_id":"1716446800-319766652","line":201,"new":null,"old":null} +{"run_id":"1716446800-319766652","line":264,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_implicit","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":264,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8 }\n\n@__FOO__init = unnamed_addr constant %FOO { i8 1 }\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8]\" {\nentry:\n %Q = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 -17, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8 }\n\n@__FOO__init = unnamed_addr constant %FOO { i8 1 }\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8]\" {\nentry:\n %Q = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 -17, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %1 = load i8, i8* %error_bits, align 1\n %erase = and i8 %1, -17\n %2 = load i8, i8* %bbb, align 1\n %value = shl i8 %2, 4\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }"}} +{"run_id":"1716446800-319766652","line":144,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_output_and_normal_assignments","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":144,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8, i8 }\n\n@__FOO__init = unnamed_addr constant %FOO zeroinitializer\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8][u8]\" {\nentry:\n %X = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n %Y = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 1\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 0, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits = load i8, i8* %error_bits, align 1\n %shift = lshr i8 %load_error_bits, 0\n %2 = and i8 %shift, 1\n store i8 %2, i8* %1, align 1\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %3 = load i8, i8* %error_bits, align 1\n %erase = and i8 %3, -2\n %4 = load i8, i8* %bbb, align 1\n %value = shl i8 %4, 0\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits1 = load i8, i8* %error_bits, align 1\n %shift2 = lshr i8 %load_error_bits1, 0\n %6 = and i8 %shift2, 1\n store i8 %6, i8* %5, align 1\n call void @FOO(%FOO* %f)\n %bbb3 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %7 = load i8, i8* %error_bits, align 1\n %erase4 = and i8 %7, -2\n %8 = load i8, i8* %bbb3, align 1\n %value5 = shl i8 %8, 0\n %or6 = or i8 %erase4, %value5\n store i8 %or6, i8* %error_bits, align 1\n %9 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits7 = load i8, i8* %error_bits, align 1\n %shift8 = lshr i8 %load_error_bits7, 0\n %10 = and i8 %shift8, 1\n store i8 %10, i8* %9, align 1\n call void @FOO(%FOO* %f)\n %11 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits9 = load i8, i8* %error_bits, align 1\n %shift10 = lshr i8 %load_error_bits9, 0\n %12 = and i8 %shift10, 1\n store i8 %12, i8* %11, align 1\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":""}} +{"run_id":"1716446973-940537858","line":201,"new":null,"old":null} +{"run_id":"1716446973-940537858","line":264,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_implicit","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":264,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8 }\n\n@__FOO__init = unnamed_addr constant %FOO { i8 1 }\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8]\" {\nentry:\n %Q = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 -17, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8 }\n\n@__FOO__init = unnamed_addr constant %FOO { i8 1 }\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8]\" {\nentry:\n %Q = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 -17, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %1 = load i8, i8* %error_bits, align 1\n %erase = and i8 %1, -17\n %2 = load i8, i8* %bbb, align 1\n %value = shl i8 %2, 4\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }"}} +{"run_id":"1716446973-940537858","line":144,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_output_and_normal_assignments","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":144,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8, i8 }\n\n@__FOO__init = unnamed_addr constant %FOO zeroinitializer\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8][u8]\" {\nentry:\n %X = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n %Y = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 1\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 0, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits = load i8, i8* %error_bits, align 1\n %shift = lshr i8 %load_error_bits, 0\n %2 = and i8 %shift, 1\n store i8 %2, i8* %1, align 1\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %3 = load i8, i8* %error_bits, align 1\n %erase = and i8 %3, -2\n %4 = load i8, i8* %bbb, align 1\n %value = shl i8 %4, 0\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits1 = load i8, i8* %error_bits, align 1\n %shift2 = lshr i8 %load_error_bits1, 0\n %6 = and i8 %shift2, 1\n store i8 %6, i8* %5, align 1\n call void @FOO(%FOO* %f)\n %bbb3 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %7 = load i8, i8* %error_bits, align 1\n %erase4 = and i8 %7, -2\n %8 = load i8, i8* %bbb3, align 1\n %value5 = shl i8 %8, 0\n %or6 = or i8 %erase4, %value5\n store i8 %or6, i8* %error_bits, align 1\n %9 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits7 = load i8, i8* %error_bits, align 1\n %shift8 = lshr i8 %load_error_bits7, 0\n %10 = and i8 %shift8, 1\n store i8 %10, i8* %9, align 1\n call void @FOO(%FOO* %f)\n %11 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits9 = load i8, i8* %error_bits, align 1\n %shift10 = lshr i8 %load_error_bits9, 0\n %12 = and i8 %shift10, 1\n store i8 %12, i8* %11, align 1\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":""}} +{"run_id":"1716447100-47216366","line":201,"new":null,"old":null} +{"run_id":"1716447100-47216366","line":144,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_output_and_normal_assignments","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":144,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8, i8 }\n\n@__FOO__init = unnamed_addr constant %FOO zeroinitializer\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8][u8]\" {\nentry:\n %X = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n %Y = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 1\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 0, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits = load i8, i8* %error_bits, align 1\n %shift = lshr i8 %load_error_bits, 0\n %2 = and i8 %shift, 1\n store i8 %2, i8* %1, align 1\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %3 = load i8, i8* %error_bits, align 1\n %erase = and i8 %3, -2\n %4 = load i8, i8* %bbb, align 1\n %value = shl i8 %4, 0\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits1 = load i8, i8* %error_bits, align 1\n %shift2 = lshr i8 %load_error_bits1, 0\n %6 = and i8 %shift2, 1\n store i8 %6, i8* %5, align 1\n call void @FOO(%FOO* %f)\n %bbb3 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %7 = load i8, i8* %error_bits, align 1\n %erase4 = and i8 %7, -2\n %8 = load i8, i8* %bbb3, align 1\n %value5 = shl i8 %8, 0\n %or6 = or i8 %erase4, %value5\n store i8 %or6, i8* %error_bits, align 1\n %9 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits7 = load i8, i8* %error_bits, align 1\n %shift8 = lshr i8 %load_error_bits7, 0\n %10 = and i8 %shift8, 1\n store i8 %10, i8* %9, align 1\n call void @FOO(%FOO* %f)\n %11 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits9 = load i8, i8* %error_bits, align 1\n %shift10 = lshr i8 %load_error_bits9, 0\n %12 = and i8 %shift10, 1\n store i8 %12, i8* %11, align 1\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":""}} +{"run_id":"1716447100-47216366","line":264,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_implicit","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":264,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8 }\n\n@__FOO__init = unnamed_addr constant %FOO { i8 1 }\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8]\" {\nentry:\n %Q = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 -17, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8 }\n\n@__FOO__init = unnamed_addr constant %FOO { i8 1 }\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8]\" {\nentry:\n %Q = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 -17, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %1 = load i8, i8* %error_bits, align 1\n %erase = and i8 %1, -17\n %2 = load i8, i8* %bbb, align 1\n %value = shl i8 %2, 4\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }"}} +{"run_id":"1716447216-174828573","line":201,"new":null,"old":null} +{"run_id":"1716447216-174828573","line":264,"new":null,"old":null} +{"run_id":"1716447646-651555043","line":201,"new":null,"old":null} +{"run_id":"1716447646-651555043","line":264,"new":null,"old":null} +{"run_id":"1716447646-651555043","line":144,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_output_and_normal_assignments","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":144,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8, i8 }\n\n@__FOO__init = unnamed_addr constant %FOO zeroinitializer\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8][u8]\" {\nentry:\n %X = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n %Y = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 1\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 0, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits = load i8, i8* %error_bits, align 1\n %shift = lshr i8 %load_error_bits, 0\n %2 = and i8 %shift, 1\n store i8 %2, i8* %1, align 1\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %3 = load i8, i8* %error_bits, align 1\n %erase = and i8 %3, -2\n %4 = load i8, i8* %bbb, align 1\n %value = shl i8 %4, 0\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits1 = load i8, i8* %error_bits, align 1\n %shift2 = lshr i8 %load_error_bits1, 0\n %6 = and i8 %shift2, 1\n store i8 %6, i8* %5, align 1\n call void @FOO(%FOO* %f)\n %bbb3 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %7 = load i8, i8* %error_bits, align 1\n %erase4 = and i8 %7, -2\n %8 = load i8, i8* %bbb3, align 1\n %value5 = shl i8 %8, 0\n %or6 = or i8 %erase4, %value5\n store i8 %or6, i8* %error_bits, align 1\n %9 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits7 = load i8, i8* %error_bits, align 1\n %shift8 = lshr i8 %load_error_bits7, 0\n %10 = and i8 %shift8, 1\n store i8 %10, i8* %9, align 1\n call void @FOO(%FOO* %f)\n %bbb9 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %11 = load i8, i8* %error_bits, align 1\n %erase10 = and i8 %11, -2\n %12 = load i8, i8* %bbb9, align 1\n %value11 = shl i8 %12, 0\n %or12 = or i8 %erase10, %value11\n store i8 %or12, i8* %error_bits, align 1\n %13 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits13 = load i8, i8* %error_bits, align 1\n %shift14 = lshr i8 %load_error_bits13, 0\n %14 = and i8 %shift14, 1\n store i8 %14, i8* %13, align 1\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":""}} +{"run_id":"1716447783-899381420","line":264,"new":null,"old":null} +{"run_id":"1716447783-899381420","line":201,"new":null,"old":null} +{"run_id":"1716447783-899381420","line":144,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_output_and_normal_assignments","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":144,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8, i8 }\n\n@__FOO__init = unnamed_addr constant %FOO zeroinitializer\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8][u8]\" {\nentry:\n %X = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n %Y = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 1\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 0, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits = load i8, i8* %error_bits, align 1\n %shift = lshr i8 %load_error_bits, 0\n %2 = and i8 %shift, 1\n store i8 %2, i8* %1, align 1\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %3 = load i8, i8* %error_bits, align 1\n %erase = and i8 %3, -2\n %4 = load i8, i8* %bbb, align 1\n %value = shl i8 %4, 0\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits1 = load i8, i8* %error_bits, align 1\n %shift2 = lshr i8 %load_error_bits1, 0\n %6 = and i8 %shift2, 1\n store i8 %6, i8* %5, align 1\n call void @FOO(%FOO* %f)\n %bbb3 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %7 = load i8, i8* %error_bits, align 1\n %erase4 = and i8 %7, -2\n %8 = load i8, i8* %bbb3, align 1\n %value5 = shl i8 %8, 0\n %or6 = or i8 %erase4, %value5\n store i8 %or6, i8* %error_bits, align 1\n %9 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits7 = load i8, i8* %error_bits, align 1\n %shift8 = lshr i8 %load_error_bits7, 0\n %10 = and i8 %shift8, 1\n store i8 %10, i8* %9, align 1\n call void @FOO(%FOO* %f)\n %bbb9 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %11 = load i8, i8* %error_bits, align 1\n %erase10 = and i8 %11, -2\n %12 = load i8, i8* %bbb9, align 1\n %value11 = shl i8 %12, 0\n %or12 = or i8 %erase10, %value11\n store i8 %or12, i8* %error_bits, align 1\n %13 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits13 = load i8, i8* %error_bits, align 1\n %shift14 = lshr i8 %load_error_bits13, 0\n %14 = and i8 %shift14, 1\n store i8 %14, i8* %13, align 1\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":""}} diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_var_out_called_mixed_in_program.snap.new b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_var_out_called_mixed_in_program.snap.new deleted file mode 100644 index d042037982c..00000000000 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_var_out_called_mixed_in_program.snap.new +++ /dev/null @@ -1,28 +0,0 @@ ---- -source: src/codegen/tests/code_gen_tests.rs -assertion_line: 1913 -expression: result ---- -; ModuleID = 'main' -source_filename = "main" - -%foo = type { i32, i8 } -%prg = type { i8 } - -@foo_instance = global %foo zeroinitializer -@prg_instance = global %prg zeroinitializer - -define void @foo(%foo* %0) section "fn-foo:v[i32][u8]" { -entry: - %bar = getelementptr inbounds %foo, %foo* %0, i32 0, i32 0 - %buz = getelementptr inbounds %foo, %foo* %0, i32 0, i32 1 - ret void -} - -define void @prg(%prg* %0) section "fn-prg:v" { -entry: - %baz = getelementptr inbounds %prg, %prg* %0, i32 0, i32 0 - store i32 2, i32* getelementptr inbounds (%foo, %foo* @foo_instance, i32 0, i32 0), align 4 - call void @foo(%foo* @foo_instance) - ret void -} diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_all_parameters_assigned_explicit.snap.new b/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_all_parameters_assigned_explicit.snap.new deleted file mode 100644 index c910f95b118..00000000000 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_all_parameters_assigned_explicit.snap.new +++ /dev/null @@ -1,37 +0,0 @@ ---- -source: src/codegen/tests/parameters_tests.rs -assertion_line: 354 -expression: result ---- -; ModuleID = 'main' -source_filename = "main" - -%prog = type { i32, i32, i32* } -%main = type { i32, i32, i32 } - -@prog_instance = global %prog zeroinitializer -@main_instance = global %main zeroinitializer - -define void @prog(%prog* %0) section "fn-prog:v[i32][i32][pi32]" { -entry: - %input1 = getelementptr inbounds %prog, %prog* %0, i32 0, i32 0 - %output1 = getelementptr inbounds %prog, %prog* %0, i32 0, i32 1 - %inout1 = getelementptr inbounds %prog, %prog* %0, i32 0, i32 2 - ret void -} - -define void @main(%main* %0) section "fn-main:v" { -entry: - %var1 = getelementptr inbounds %main, %main* %0, i32 0, i32 0 - %var2 = getelementptr inbounds %main, %main* %0, i32 0, i32 1 - %var3 = getelementptr inbounds %main, %main* %0, i32 0, i32 2 - %load_var1 = load i32, i32* %var1, align 4 - store i32 %load_var1, i32* getelementptr inbounds (%prog, %prog* @prog_instance, i32 0, i32 0), align 4 - store i32* %var3, i32** getelementptr inbounds (%prog, %prog* @prog_instance, i32 0, i32 2), align 8 - call void @prog(%prog* @prog_instance) - store i32* %var3, i32** getelementptr inbounds (%prog, %prog* @prog_instance, i32 0, i32 2), align 8 - %load_var11 = load i32, i32* %var1, align 4 - store i32 %load_var11, i32* getelementptr inbounds (%prog, %prog* @prog_instance, i32 0, i32 0), align 4 - call void @prog(%prog* @prog_instance) - ret void -} diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_missing_input_assignment.snap.new b/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_missing_input_assignment.snap.new deleted file mode 100644 index 6632043cafd..00000000000 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__parameters_tests__program_missing_input_assignment.snap.new +++ /dev/null @@ -1,31 +0,0 @@ ---- -source: src/codegen/tests/parameters_tests.rs -assertion_line: 441 -expression: result ---- -; ModuleID = 'main' -source_filename = "main" - -%prog = type { i32, i32, i32* } -%main = type { i32, i32, i32 } - -@prog_instance = global %prog zeroinitializer -@main_instance = global %main zeroinitializer - -define void @prog(%prog* %0) section "fn-prog:v[i32][i32][pi32]" { -entry: - %input1 = getelementptr inbounds %prog, %prog* %0, i32 0, i32 0 - %output1 = getelementptr inbounds %prog, %prog* %0, i32 0, i32 1 - %inout1 = getelementptr inbounds %prog, %prog* %0, i32 0, i32 2 - ret void -} - -define void @main(%main* %0) section "fn-main:v" { -entry: - %var1 = getelementptr inbounds %main, %main* %0, i32 0, i32 0 - %var2 = getelementptr inbounds %main, %main* %0, i32 0, i32 1 - %var3 = getelementptr inbounds %main, %main* %0, i32 0, i32 2 - store i32* %var3, i32** getelementptr inbounds (%prog, %prog* @prog_instance, i32 0, i32 2), align 8 - call void @prog(%prog* @prog_instance) - ret void -} diff --git a/src/tests/adr/.pou_adr.rs.pending-snap b/src/tests/adr/.pou_adr.rs.pending-snap index 8107ff8f1c3..6c458aa4422 100644 --- a/src/tests/adr/.pou_adr.rs.pending-snap +++ b/src/tests/adr/.pou_adr.rs.pending-snap @@ -155,3 +155,83 @@ {"run_id":"1716444851-574207320","line":268,"new":null,"old":null} {"run_id":"1716444851-574207320","line":534,"new":null,"old":null} {"run_id":"1716444851-574207320","line":616,"new":null,"old":null} +{"run_id":"1716444885-28893355","line":430,"new":null,"old":null} +{"run_id":"1716444885-28893355","line":230,"new":null,"old":null} +{"run_id":"1716444885-28893355","line":332,"new":null,"old":null} +{"run_id":"1716444885-28893355","line":472,"new":null,"old":null} +{"run_id":"1716444885-28893355","line":371,"new":null,"old":null} +{"run_id":"1716444885-28893355","line":55,"new":null,"old":null} +{"run_id":"1716444885-28893355","line":268,"new":null,"old":null} +{"run_id":"1716444885-28893355","line":702,"new":null,"old":null} +{"run_id":"1716444885-28893355","line":616,"new":null,"old":null} +{"run_id":"1716444885-28893355","line":534,"new":null,"old":null} +{"run_id":"1716446701-512418354","line":230,"new":null,"old":null} +{"run_id":"1716446701-512418354","line":268,"new":null,"old":null} +{"run_id":"1716446701-512418354","line":430,"new":null,"old":null} +{"run_id":"1716446701-512418354","line":702,"new":null,"old":null} +{"run_id":"1716446701-512418354","line":371,"new":null,"old":null} +{"run_id":"1716446701-512418354","line":332,"new":null,"old":null} +{"run_id":"1716446701-512418354","line":616,"new":null,"old":null} +{"run_id":"1716446701-512418354","line":55,"new":null,"old":null} +{"run_id":"1716446701-512418354","line":472,"new":null,"old":null} +{"run_id":"1716446701-512418354","line":534,"new":null,"old":null} +{"run_id":"1716446800-319766652","line":430,"new":null,"old":null} +{"run_id":"1716446800-319766652","line":472,"new":null,"old":null} +{"run_id":"1716446800-319766652","line":268,"new":null,"old":null} +{"run_id":"1716446800-319766652","line":230,"new":null,"old":null} +{"run_id":"1716446800-319766652","line":371,"new":null,"old":null} +{"run_id":"1716446800-319766652","line":332,"new":null,"old":null} +{"run_id":"1716446800-319766652","line":616,"new":null,"old":null} +{"run_id":"1716446800-319766652","line":55,"new":null,"old":null} +{"run_id":"1716446800-319766652","line":702,"new":null,"old":null} +{"run_id":"1716446800-319766652","line":534,"new":null,"old":null} +{"run_id":"1716446973-940537858","line":430,"new":null,"old":null} +{"run_id":"1716446973-940537858","line":472,"new":null,"old":null} +{"run_id":"1716446973-940537858","line":55,"new":null,"old":null} +{"run_id":"1716446973-940537858","line":702,"new":null,"old":null} +{"run_id":"1716446973-940537858","line":268,"new":null,"old":null} +{"run_id":"1716446973-940537858","line":371,"new":null,"old":null} +{"run_id":"1716446973-940537858","line":332,"new":null,"old":null} +{"run_id":"1716446973-940537858","line":230,"new":null,"old":null} +{"run_id":"1716446973-940537858","line":616,"new":null,"old":null} +{"run_id":"1716446973-940537858","line":534,"new":null,"old":null} +{"run_id":"1716447100-47216366","line":332,"new":null,"old":null} +{"run_id":"1716447100-47216366","line":230,"new":null,"old":null} +{"run_id":"1716447100-47216366","line":268,"new":null,"old":null} +{"run_id":"1716447100-47216366","line":430,"new":null,"old":null} +{"run_id":"1716447100-47216366","line":702,"new":null,"old":null} +{"run_id":"1716447100-47216366","line":616,"new":null,"old":null} +{"run_id":"1716447100-47216366","line":371,"new":null,"old":null} +{"run_id":"1716447100-47216366","line":472,"new":null,"old":null} +{"run_id":"1716447100-47216366","line":55,"new":null,"old":null} +{"run_id":"1716447100-47216366","line":534,"new":null,"old":null} +{"run_id":"1716447216-174828573","line":230,"new":null,"old":null} +{"run_id":"1716447216-174828573","line":332,"new":null,"old":null} +{"run_id":"1716447216-174828573","line":430,"new":null,"old":null} +{"run_id":"1716447216-174828573","line":268,"new":null,"old":null} +{"run_id":"1716447216-174828573","line":371,"new":null,"old":null} +{"run_id":"1716447216-174828573","line":616,"new":null,"old":null} +{"run_id":"1716447216-174828573","line":55,"new":null,"old":null} +{"run_id":"1716447216-174828573","line":472,"new":null,"old":null} +{"run_id":"1716447216-174828573","line":702,"new":null,"old":null} +{"run_id":"1716447216-174828573","line":534,"new":null,"old":null} +{"run_id":"1716447646-651555043","line":230,"new":null,"old":null} +{"run_id":"1716447646-651555043","line":472,"new":null,"old":null} +{"run_id":"1716447646-651555043","line":371,"new":null,"old":null} +{"run_id":"1716447646-651555043","line":430,"new":null,"old":null} +{"run_id":"1716447646-651555043","line":332,"new":null,"old":null} +{"run_id":"1716447646-651555043","line":702,"new":null,"old":null} +{"run_id":"1716447646-651555043","line":268,"new":null,"old":null} +{"run_id":"1716447646-651555043","line":616,"new":null,"old":null} +{"run_id":"1716447646-651555043","line":534,"new":null,"old":null} +{"run_id":"1716447646-651555043","line":55,"new":null,"old":null} +{"run_id":"1716447783-899381420","line":332,"new":null,"old":null} +{"run_id":"1716447783-899381420","line":55,"new":null,"old":null} +{"run_id":"1716447783-899381420","line":472,"new":null,"old":null} +{"run_id":"1716447783-899381420","line":702,"new":null,"old":null} +{"run_id":"1716447783-899381420","line":371,"new":null,"old":null} +{"run_id":"1716447783-899381420","line":268,"new":null,"old":null} +{"run_id":"1716447783-899381420","line":230,"new":null,"old":null} +{"run_id":"1716447783-899381420","line":430,"new":null,"old":null} +{"run_id":"1716447783-899381420","line":616,"new":null,"old":null} +{"run_id":"1716447783-899381420","line":534,"new":null,"old":null} From 97c2cd88c653b2ab8152f3e52b0bd39d59988865 Mon Sep 17 00:00:00 2001 From: Volkan Sagcan Date: Thu, 23 May 2024 09:39:52 +0200 Subject: [PATCH 14/22] Update incorrect counter test input --- libs/stdlib/tests/counters_tests.rs | 144 ++++++++++++++-------------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/libs/stdlib/tests/counters_tests.rs b/libs/stdlib/tests/counters_tests.rs index d9793768b78..431f6ac253d 100644 --- a/libs/stdlib/tests/counters_tests.rs +++ b/libs/stdlib/tests/counters_tests.rs @@ -28,11 +28,11 @@ fn ctu() { END_VAR // count up until Q_res true and then reset CV_res IF Q_res THEN - ctu_inst(CU:= TRUE, R:= TRUE, PV:= INT#3, Q:= Q_res, CV:= CV_res); + ctu_inst(CU:= TRUE, R:= TRUE, PV:= INT#3, Q => Q_res, CV => CV_res); ELSE - ctu_inst(CU:= TRUE, R:= FALSE, PV:= INT#3, Q:= Q_res, CV:= CV_res); + ctu_inst(CU:= TRUE, R:= FALSE, PV:= INT#3, Q => Q_res, CV => CV_res); // input CU evaluated by R_EDGE, this call will enable to count up again - ctu_inst(CU:= FALSE, R:= FALSE, PV:= INT#3, Q:= Q_res, CV:= CV_res); + ctu_inst(CU:= FALSE, R:= FALSE, PV:= INT#3, Q => Q_res, CV => CV_res); END_IF END_PROGRAM "#; @@ -70,11 +70,11 @@ fn ctu_int() { END_VAR // count up until Q_res true and then reset CV_res IF Q_res THEN - ctu_inst(CU:= TRUE, R:= TRUE, PV:= INT#3, Q:= Q_res, CV:= CV_res); + ctu_inst(CU:= TRUE, R:= TRUE, PV:= INT#3, Q => Q_res, CV => CV_res); ELSE - ctu_inst(CU:= TRUE, R:= FALSE, PV:= INT#3, Q:= Q_res, CV:= CV_res); + ctu_inst(CU:= TRUE, R:= FALSE, PV:= INT#3, Q => Q_res, CV => CV_res); // input CU evaluated by R_EDGE, this call will enable to count up again - ctu_inst(CU:= FALSE, R:= FALSE, PV:= INT#3, Q:= Q_res, CV:= CV_res); + ctu_inst(CU:= FALSE, R:= FALSE, PV:= INT#3, Q => Q_res, CV => CV_res); END_IF END_PROGRAM "#; @@ -112,11 +112,11 @@ fn ctu_dint() { END_VAR // count up until Q_res true and then reset CV_res IF Q_res THEN - ctu_inst(CU:= TRUE, R:= TRUE, PV:= DINT#3, Q:= Q_res, CV:= CV_res); + ctu_inst(CU:= TRUE, R:= TRUE, PV:= DINT#3, Q => Q_res, CV => CV_res); ELSE - ctu_inst(CU:= TRUE, R:= FALSE, PV:= DINT#3, Q:= Q_res, CV:= CV_res); + ctu_inst(CU:= TRUE, R:= FALSE, PV:= DINT#3, Q => Q_res, CV => CV_res); // input CU evaluated by R_EDGE, this call will enable to count up again - ctu_inst(CU:= FALSE, R:= FALSE, PV:= DINT#3, Q:= Q_res, CV:= CV_res); + ctu_inst(CU:= FALSE, R:= FALSE, PV:= DINT#3, Q => Q_res, CV => CV_res); END_IF END_PROGRAM "#; @@ -154,11 +154,11 @@ fn ctu_udint() { END_VAR // count up until Q_res true and then reset CV_res IF Q_res THEN - ctu_inst(CU:= TRUE, R:= TRUE, PV:= UDINT#3, Q:= Q_res, CV:= CV_res); + ctu_inst(CU:= TRUE, R:= TRUE, PV:= UDINT#3, Q => Q_res, CV => CV_res); ELSE - ctu_inst(CU:= TRUE, R:= FALSE, PV:= UDINT#3, Q:= Q_res, CV:= CV_res); + ctu_inst(CU:= TRUE, R:= FALSE, PV:= UDINT#3, Q => Q_res, CV => CV_res); // input CU evaluated by R_EDGE, this call will enable to count up again - ctu_inst(CU:= FALSE, R:= FALSE, PV:= UDINT#3, Q:= Q_res, CV:= CV_res); + ctu_inst(CU:= FALSE, R:= FALSE, PV:= UDINT#3, Q => Q_res, CV => CV_res); END_IF END_PROGRAM "#; @@ -196,11 +196,11 @@ fn ctu_lint() { END_VAR // count up until Q_res true and then reset CV_res IF Q_res THEN - ctu_inst(CU:= TRUE, R:= TRUE, PV:= LINT#3, Q:= Q_res, CV:= CV_res); + ctu_inst(CU:= TRUE, R:= TRUE, PV:= LINT#3, Q => Q_res, CV => CV_res); ELSE - ctu_inst(CU:= TRUE, R:= FALSE, PV:= LINT#3, Q:= Q_res, CV:= CV_res); + ctu_inst(CU:= TRUE, R:= FALSE, PV:= LINT#3, Q => Q_res, CV => CV_res); // input CU evaluated by R_EDGE, this call will enable to count up again - ctu_inst(CU:= FALSE, R:= FALSE, PV:= LINT#3, Q:= Q_res, CV:= CV_res); + ctu_inst(CU:= FALSE, R:= FALSE, PV:= LINT#3, Q => Q_res, CV => CV_res); END_IF END_PROGRAM "#; @@ -238,11 +238,11 @@ fn ctu_ulint() { END_VAR // count up until Q_res true and then reset CV_res IF Q_res THEN - ctu_inst(CU:= TRUE, R:= TRUE, PV:= ULINT#3, Q:= Q_res, CV:= CV_res); + ctu_inst(CU:= TRUE, R:= TRUE, PV:= ULINT#3, Q => Q_res, CV => CV_res); ELSE - ctu_inst(CU:= TRUE, R:= FALSE, PV:= ULINT#3, Q:= Q_res, CV:= CV_res); + ctu_inst(CU:= TRUE, R:= FALSE, PV:= ULINT#3, Q => Q_res, CV => CV_res); // input CU evaluated by R_EDGE, this call will enable to count up again - ctu_inst(CU:= FALSE, R:= FALSE, PV:= ULINT#3, Q:= Q_res, CV:= CV_res); + ctu_inst(CU:= FALSE, R:= FALSE, PV:= ULINT#3, Q => Q_res, CV => CV_res); END_IF END_PROGRAM "#; @@ -290,12 +290,12 @@ fn ctd() { END_VAR // load PV value IF load THEN - ctd_inst(CD:= TRUE, LD:= load, PV:= INT#3, Q:= Q_res, CV:= CV_res); + ctd_inst(CD:= TRUE, LD:= load, PV:= INT#3, Q => Q_res, CV => CV_res); load := FALSE; END_IF - ctd_inst(CD:= TRUE, LD:= load, PV:= INT#3, Q:= Q_res, CV:= CV_res); + ctd_inst(CD:= TRUE, LD:= load, PV:= INT#3, Q => Q_res, CV => CV_res); // input CD evaluated by R_EDGE, this call will enable to count down again - ctd_inst(CD:= FALSE, LD:= load, PV:= INT#3, Q:= Q_res, CV:= CV_res); + ctd_inst(CD:= FALSE, LD:= load, PV:= INT#3, Q => Q_res, CV => CV_res); END_PROGRAM "#; @@ -333,12 +333,12 @@ fn ctd_int() { END_VAR // load PV value IF load THEN - ctd_inst(CD:= TRUE, LD:= load, PV:= INT#3, Q:= Q_res, CV:= CV_res); + ctd_inst(CD:= TRUE, LD:= load, PV:= INT#3, Q => Q_res, CV => CV_res); load := FALSE; END_IF - ctd_inst(CD:= TRUE, LD:= load, PV:= INT#3, Q:= Q_res, CV:= CV_res); + ctd_inst(CD:= TRUE, LD:= load, PV:= INT#3, Q => Q_res, CV => CV_res); // input CD evaluated by R_EDGE, this call will enable to count down again - ctd_inst(CD:= FALSE, LD:= load, PV:= INT#3, Q:= Q_res, CV:= CV_res); + ctd_inst(CD:= FALSE, LD:= load, PV:= INT#3, Q => Q_res, CV => CV_res); END_PROGRAM "#; @@ -376,12 +376,12 @@ fn ctd_dint() { END_VAR // load PV value IF load THEN - ctd_inst(CD:= TRUE, LD:= load, PV:= DINT#3, Q:= Q_res, CV:= CV_res); + ctd_inst(CD:= TRUE, LD:= load, PV:= DINT#3, Q => Q_res, CV => CV_res); load := FALSE; END_IF - ctd_inst(CD:= TRUE, LD:= load, PV:= DINT#3, Q:= Q_res, CV:= CV_res); + ctd_inst(CD:= TRUE, LD:= load, PV:= DINT#3, Q => Q_res, CV => CV_res); // input CD evaluated by R_EDGE, this call will enable to count down again - ctd_inst(CD:= FALSE, LD:= load, PV:= DINT#3, Q:= Q_res, CV:= CV_res); + ctd_inst(CD:= FALSE, LD:= load, PV:= DINT#3, Q => Q_res, CV => CV_res); END_PROGRAM "#; @@ -419,12 +419,12 @@ fn ctd_udint() { END_VAR // load PV value IF load THEN - ctd_inst(CD:= TRUE, LD:= load, PV:= UDINT#3, Q:= Q_res, CV:= CV_res); + ctd_inst(CD:= TRUE, LD:= load, PV:= UDINT#3, Q => Q_res, CV => CV_res); load := FALSE; END_IF - ctd_inst(CD:= TRUE, LD:= load, PV:= UDINT#3, Q:= Q_res, CV:= CV_res); + ctd_inst(CD:= TRUE, LD:= load, PV:= UDINT#3, Q => Q_res, CV => CV_res); // input CD evaluated by R_EDGE, this call will enable to count down again - ctd_inst(CD:= FALSE, LD:= load, PV:= UDINT#3, Q:= Q_res, CV:= CV_res); + ctd_inst(CD:= FALSE, LD:= load, PV:= UDINT#3, Q => Q_res, CV => CV_res); END_PROGRAM "#; @@ -462,12 +462,12 @@ fn ctd_lint() { END_VAR // load PV value IF load THEN - ctd_inst(CD:= TRUE, LD:= load, PV:= LINT#3, Q:= Q_res, CV:= CV_res); + ctd_inst(CD:= TRUE, LD:= load, PV:= LINT#3, Q => Q_res, CV => CV_res); load := FALSE; END_IF - ctd_inst(CD:= TRUE, LD:= load, PV:= LINT#3, Q:= Q_res, CV:= CV_res); + ctd_inst(CD:= TRUE, LD:= load, PV:= LINT#3, Q => Q_res, CV => CV_res); // input CD evaluated by R_EDGE, this call will enable to count down again - ctd_inst(CD:= FALSE, LD:= load, PV:= LINT#3, Q:= Q_res, CV:= CV_res); + ctd_inst(CD:= FALSE, LD:= load, PV:= LINT#3, Q => Q_res, CV => CV_res); END_PROGRAM "#; @@ -505,12 +505,12 @@ fn ctd_ulint() { END_VAR // load PV value IF load THEN - ctd_inst(CD:= TRUE, LD:= load, PV:= ULINT#3, Q:= Q_res, CV:= CV_res); + ctd_inst(CD:= TRUE, LD:= load, PV:= ULINT#3, Q => Q_res, CV => CV_res); load := FALSE; END_IF - ctd_inst(CD:= TRUE, LD:= load, PV:= ULINT#3, Q:= Q_res, CV:= CV_res); + ctd_inst(CD:= TRUE, LD:= load, PV:= ULINT#3, Q => Q_res, CV => CV_res); // input CD evaluated by R_EDGE, this call will enable to count down again - ctd_inst(CD:= FALSE, LD:= load, PV:= ULINT#3, Q:= Q_res, CV:= CV_res); + ctd_inst(CD:= FALSE, LD:= load, PV:= ULINT#3, Q => Q_res, CV => CV_res); END_PROGRAM "#; @@ -561,31 +561,31 @@ fn ctud() { END_VAR // 1st call, load PV value IF load THEN - ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= TRUE, PV:= INT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= TRUE, PV:= INT#1, QU => QU_res, QD => QD_res, CV => CV_res); load := FALSE; END_IF // 2nd call, CU/CD both true, nothing should happen IF i = 1 THEN - ctud_inst(CU:= TRUE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= INT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= TRUE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= INT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF // 3rd call, count down IF i = 2 THEN // input CD evaluated by R_EDGE, this call will enable count down again - ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= INT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); - ctud_inst(CU:= FALSE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= INT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= INT#1, QU => QU_res, QD => QD_res, CV => CV_res); + ctud_inst(CU:= FALSE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= INT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF // 4th call, count up IF i = 3 THEN // input CU evaluated by R_EDGE, third call enabled count up again - ctud_inst(CU:= TRUE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= INT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= TRUE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= INT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF // 5th call, reset IF i = 4 THEN - ctud_inst(CU:= FALSE, CD:= FALSE, R:= TRUE, LD:= FALSE, PV:= INT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= FALSE, CD:= FALSE, R:= TRUE, LD:= FALSE, PV:= INT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF i := i + 1; END_PROGRAM @@ -636,31 +636,31 @@ fn ctud_int() { END_VAR // 1st call, load PV value IF load THEN - ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= TRUE, PV:= INT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= TRUE, PV:= INT#1, QU => QU_res, QD => QD_res, CV => CV_res); load := FALSE; END_IF // 2nd call, CU/CD both true, nothing should happen IF i = 1 THEN - ctud_inst(CU:= TRUE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= INT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= TRUE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= INT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF // 3rd call, count down IF i = 2 THEN // input CD evaluated by R_EDGE, this call will enable count down again - ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= INT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); - ctud_inst(CU:= FALSE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= INT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= INT#1, QU => QU_res, QD => QD_res, CV => CV_res); + ctud_inst(CU:= FALSE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= INT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF // 4th call, count up IF i = 3 THEN // input CU evaluated by R_EDGE, third call enabled count up again - ctud_inst(CU:= TRUE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= INT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= TRUE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= INT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF // 5th call, reset IF i = 4 THEN - ctud_inst(CU:= FALSE, CD:= FALSE, R:= TRUE, LD:= FALSE, PV:= INT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= FALSE, CD:= FALSE, R:= TRUE, LD:= FALSE, PV:= INT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF i := i + 1; END_PROGRAM @@ -711,31 +711,31 @@ fn ctud_dint() { END_VAR // 1st call, load PV value IF load THEN - ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= TRUE, PV:= DINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= TRUE, PV:= DINT#1, QU => QU_res, QD => QD_res, CV => CV_res); load := FALSE; END_IF // 2nd call, CU/CD both true, nothing should happen IF i = 1 THEN - ctud_inst(CU:= TRUE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= DINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= TRUE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= DINT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF // 3rd call, count down IF i = 2 THEN // input CD evaluated by R_EDGE, this call will enable count down again - ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= DINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); - ctud_inst(CU:= FALSE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= DINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= DINT#1, QU => QU_res, QD => QD_res, CV => CV_res); + ctud_inst(CU:= FALSE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= DINT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF // 4th call, count up IF i = 3 THEN // input CU evaluated by R_EDGE, third call enabled count up again - ctud_inst(CU:= TRUE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= DINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= TRUE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= DINT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF // 5th call, reset IF i = 4 THEN - ctud_inst(CU:= FALSE, CD:= FALSE, R:= TRUE, LD:= FALSE, PV:= DINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= FALSE, CD:= FALSE, R:= TRUE, LD:= FALSE, PV:= DINT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF i := i + 1; END_PROGRAM @@ -786,31 +786,31 @@ fn ctud_udint() { END_VAR // 1st call, load PV value IF load THEN - ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= TRUE, PV:= UDINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= TRUE, PV:= UDINT#1, QU => QU_res, QD => QD_res, CV => CV_res); load := FALSE; END_IF // 2nd call, CU/CD both true, nothing should happen IF i = 1 THEN - ctud_inst(CU:= TRUE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= UDINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= TRUE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= UDINT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF // 3rd call, count down IF i = 2 THEN // input CD evaluated by R_EDGE, this call will enable count down again - ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= UDINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); - ctud_inst(CU:= FALSE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= UDINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= UDINT#1, QU => QU_res, QD => QD_res, CV => CV_res); + ctud_inst(CU:= FALSE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= UDINT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF // 4th call, count up IF i = 3 THEN // input CU evaluated by R_EDGE, third call enabled count up again - ctud_inst(CU:= TRUE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= UDINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= TRUE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= UDINT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF // 5th call, reset IF i = 4 THEN - ctud_inst(CU:= FALSE, CD:= FALSE, R:= TRUE, LD:= FALSE, PV:= UDINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= FALSE, CD:= FALSE, R:= TRUE, LD:= FALSE, PV:= UDINT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF i := i + 1; END_PROGRAM @@ -861,31 +861,31 @@ fn ctud_lint() { END_VAR // 1st call, load PV value IF load THEN - ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= TRUE, PV:= LINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= TRUE, PV:= LINT#1, QU => QU_res, QD => QD_res, CV => CV_res); load := FALSE; END_IF // 2nd call, CU/CD both true, nothing should happen IF i = 1 THEN - ctud_inst(CU:= TRUE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= LINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= TRUE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= LINT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF // 3rd call, count down IF i = 2 THEN // input CD evaluated by R_EDGE, this call will enable count down again - ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= LINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); - ctud_inst(CU:= FALSE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= LINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= LINT#1, QU => QU_res, QD => QD_res, CV => CV_res); + ctud_inst(CU:= FALSE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= LINT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF // 4th call, count up IF i = 3 THEN // input CU evaluated by R_EDGE, third call enabled count up again - ctud_inst(CU:= TRUE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= LINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= TRUE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= LINT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF // 5th call, reset IF i = 4 THEN - ctud_inst(CU:= FALSE, CD:= FALSE, R:= TRUE, LD:= FALSE, PV:= LINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= FALSE, CD:= FALSE, R:= TRUE, LD:= FALSE, PV:= LINT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF i := i + 1; END_PROGRAM @@ -936,31 +936,31 @@ fn ctud_ulint() { END_VAR // 1st call, load PV value IF load THEN - ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= TRUE, PV:= ULINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= TRUE, PV:= ULINT#1, QU => QU_res, QD => QD_res, CV => CV_res); load := FALSE; END_IF // 2nd call, CU/CD both true, nothing should happen IF i = 1 THEN - ctud_inst(CU:= TRUE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= ULINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= TRUE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= ULINT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF // 3rd call, count down IF i = 2 THEN // input CD evaluated by R_EDGE, this call will enable count down again - ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= ULINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); - ctud_inst(CU:= FALSE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= ULINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= FALSE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= ULINT#1, QU => QU_res, QD => QD_res, CV => CV_res); + ctud_inst(CU:= FALSE, CD:= TRUE, R:= FALSE, LD:= FALSE, PV:= ULINT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF // 4th call, count up IF i = 3 THEN // input CU evaluated by R_EDGE, third call enabled count up again - ctud_inst(CU:= TRUE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= ULINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= TRUE, CD:= FALSE, R:= FALSE, LD:= FALSE, PV:= ULINT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF // 5th call, reset IF i = 4 THEN - ctud_inst(CU:= FALSE, CD:= FALSE, R:= TRUE, LD:= FALSE, PV:= ULINT#1, QU:= QU_res, QD:= QD_res, CV:= CV_res); + ctud_inst(CU:= FALSE, CD:= FALSE, R:= TRUE, LD:= FALSE, PV:= ULINT#1, QU => QU_res, QD => QD_res, CV => CV_res); END_IF i := i + 1; END_PROGRAM From 58cfcec4544a6acb6fcab3ae594ddd0c52310b21 Mon Sep 17 00:00:00 2001 From: Volkan Sagcan Date: Thu, 23 May 2024 11:14:45 +0200 Subject: [PATCH 15/22] wip --- .vscode/launch.json | 2 +- .../generators/expression_generator.rs | 205 +++++++-------- src/codegen/generators/statement_generator.rs | 6 - .../tests/.directaccess_test.rs.pending-snap | 58 ----- src/codegen/tests/directaccess_test.rs | 80 +++++- src/tests/adr/.pou_adr.rs.pending-snap | 237 ------------------ 6 files changed, 169 insertions(+), 419 deletions(-) delete mode 100644 src/codegen/tests/.directaccess_test.rs.pending-snap delete mode 100644 src/tests/adr/.pou_adr.rs.pending-snap diff --git a/.vscode/launch.json b/.vscode/launch.json index 8d748f23860..21eab6ec81d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -46,4 +46,4 @@ "cwd": "${workspaceFolder}" }, ] -} +} \ No newline at end of file diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index deed71782d4..32141536d44 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -1,5 +1,4 @@ -use std::fmt::Pointer; -use std::{collections::HashSet, vec}; +// Copyright (c) 2020 Ghaith Hachem and Mathias Rieder use inkwell::{ builder::Builder, @@ -10,6 +9,7 @@ use inkwell::{ }, AddressSpace, FloatPredicate, IntPredicate, }; +use rustc_hash::FxHashSet; use plc_ast::ast::Assignment; use plc_ast::{ @@ -23,7 +23,6 @@ use plc_diagnostics::diagnostics::{Diagnostic, INTERNAL_LLVM_ERROR}; use plc_source::source_location::SourceLocation; use plc_util::convention::qualified_name; -// Copyright (c) 2020 Ghaith Hachem and Mathias Rieder use crate::{ codegen::{ debug::{Debug, DebugBuilderEnum}, @@ -41,7 +40,6 @@ use crate::{ StringEncoding, VarArgs, DINT_TYPE, INT_SIZE, INT_TYPE, LINT_TYPE, }, }; -use rustc_hash::FxHashSet; use super::{llvm::Llvm, statement_generator::FunctionContext, ADDRESS_SPACE_CONST, ADDRESS_SPACE_GENERIC}; @@ -69,11 +67,11 @@ pub struct ExpressionCodeGenerator<'a, 'b> { #[derive(Debug)] struct CallParameterAssignment<'a, 'b> { /// the assignmentstatement in the call-argument list (a:=3) - assignment_statement: &'b AstNode, + assignment: &'b AstNode, /// the name of the function we're calling function_name: &'b str, /// the position of the argument in the POU's argument's list - pub index: u32, + index: u32, /// a pointer to the struct instance that carries the call's arguments parameter_struct: PointerValue<'a>, } @@ -530,99 +528,62 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { function_name: &str, parameters: Vec<&AstNode>, ) -> Result<(), Diagnostic> { - // self.index.get_declared_parameter(function_name, index) - - // Before - // parameter = vec![foo, bar, baz] - // ^^^ output, index = 1 - // After (filtered) - // parameter = vec![bar] - let pou_info = self.index.get_declared_parameters(function_name); - let mut implicit = true; - for statement in parameters.iter() { - if statement.is_assignment() || statement.is_output_assignment() { - implicit = false; - break; - } - } + let implicit = is_implicit_function_call(¶meters); for (index, assignment_statement) in parameters.into_iter().enumerate() { - let temp = pou_info.get(index).is_some_and(|it| it.get_variable_type().is_output()); - // TODO: Filter this - if assignment_statement.is_output_assignment() || (implicit && temp) { + let is_output = pou_info.get(index).is_some_and(|param| param.get_variable_type().is_output()); + + if assignment_statement.is_output_assignment() || (implicit && is_output) { self.assign_output_value(&CallParameterAssignment { - assignment_statement, + assignment: assignment_statement, function_name, index: index as u32, parameter_struct, })? } } + Ok(()) } fn assign_output_value(&self, param_context: &CallParameterAssignment) -> Result<(), Diagnostic> { - match param_context.assignment_statement.get_stmt() { - // TODO: AstStatement::Assignment should not be a part of this? - AstStatement::OutputAssignment(data) => self.generate_explicit_output_assignment( + match ¶m_context.assignment.stmt { + AstStatement::OutputAssignment(assignment) => self.generate_explicit_output_assignment( param_context.parameter_struct, param_context.function_name, - param_context.assignment_statement, + assignment, ), _ => self.generate_output_assignment(param_context), } } - fn temp_xxx( + fn generate_bit_access( &self, - left_lvalue: PointerValue, - right_lvalue: PointerValue, - left_statement: &AstNode, - right_type: &DataType, + lvalue_lhs: PointerValue, + lvalue_rhs: PointerValue, + statement_lhs: &AstNode, + type_rhs: &DataType, ) -> Result<(), Diagnostic> { - /// when generating an assignment to a direct-access (e.g. a.b.c.%W3.%X2 := 2;) - /// we want to deconstruct the sequence into the base-statement (a.b.c) and the sequence - /// of direct-access commands (vec![%W3, %X2]) - fn collect_base_and_direct_access_for_assignment( - left_statement: &AstNode, - ) -> Option<(&AstNode, Vec<&AstNode>)> { - let mut current = Some(left_statement); - let mut access_sequence = Vec::new(); - while let Some(AstStatement::ReferenceExpr(ReferenceExpr { - access: ReferenceAccess::Member(m), - base, - })) = current.map(|it| it.get_stmt()) - { - if matches!(m.get_stmt(), AstStatement::DirectAccess { .. }) { - access_sequence.insert(0, m.as_ref()); - current = base.as_deref(); - } else { - break; - } - } - current.zip(Some(access_sequence)) - } - - let Some((target, access_sequence)) = collect_base_and_direct_access_for_assignment(left_statement) + let Some((target, access_sequence)) = collect_base_and_direct_access_for_assignment(statement_lhs) else { - unreachable!("Invalid direct-access expression: {left_statement:#?}") + unreachable!("Invalid direct-access expression: {statement_lhs:#?}") }; - let left_type = self.get_type_hint_for(target)?; + let type_left = self.get_type_hint_for(target)?; //special case if we deal with a single bit, then we need to switch to a faked u1 type - let right_type = + let type_right = if let DataTypeInformation::Integer { semantic_size: Some(typesystem::U1_SIZE), .. } = - *right_type.get_type_information() + *type_rhs.get_type_information() { self.index.get_type_or_panic(typesystem::U1_TYPE) } else { - right_type + type_rhs }; - let left_value = self.llvm.builder.build_load(left_lvalue, "").into_int_value(); + let value_lhs = self.llvm.builder.build_load(lvalue_lhs, "").into_int_value(); //Build index if let Some((element, direct_access)) = access_sequence.split_first() { @@ -630,8 +591,8 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { self.generate_direct_access_index( &data.access, &data.index, - right_type.get_type_information(), - left_type, + type_right.get_type_information(), + type_left, ) } else { //TODO: using the global context we could get a slice here @@ -644,8 +605,8 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { self.generate_direct_access_index( &data.access, &data.index, - right_type.get_type_information(), - left_type, + type_right.get_type_information(), + type_left, ) } else { //TODO: using the global context we could get a slice here @@ -657,28 +618,28 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { } //Build mask for the index //Get the target bit type as all ones - let rhs_type = self.llvm_index.get_associated_type(right_type.get_name())?.into_int_type(); + let rhs_type = self.llvm_index.get_associated_type(type_right.get_name())?.into_int_type(); 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, value_lhs.get_type(), "ext"); //Position the ones in their correct locations let shifted_mask = self.llvm.builder.build_left_shift(extended_mask, index, "shift"); //Invert the mask let mask = self.llvm.builder.build_not(shifted_mask, "invert"); //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(value_lhs, mask, "erase"); //Generate an expression for the right size - let right = self.llvm.builder.build_load(right_lvalue, ""); + let right = self.llvm.builder.build_load(lvalue_rhs, ""); //Cast the right side to the left side type - let lhs = cast_if_needed!(self, left_type, right_type, right, None).into_int_value(); + let lhs = cast_if_needed!(self, type_left, type_right, right, None).into_int_value(); //Shift left by the direct access let value = self.llvm.builder.build_left_shift(lhs, index, "value"); //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_lvalue, or_value); + self.llvm.builder.build_store(lvalue_lhs, or_value); } else { unreachable!() } @@ -687,32 +648,23 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { } fn generate_output_assignment(&self, context: &CallParameterAssignment) -> Result<(), Diagnostic> { + let &CallParameterAssignment { assignment, function_name, index, parameter_struct } = context; let builder = &self.llvm.builder; - let expression = context.assignment_statement; - let parameter_struct = context.parameter_struct; - let function_name = context.function_name; - let index = context.index; let Some(parameter) = self.index.get_declared_parameter(function_name, index) else { panic!("or return?"); }; + assert!(parameter.get_variable_type().is_output()); - if !parameter.get_variable_type().is_output() { - panic!("wtf... {parameter:#?}"); - // return Ok(()); - } - - // TODO: How to trigger an empty statement here, this: `FOO(Q => );`? - if expression.is_empty_statement() { - // Something like `foo(out1 => )`, which means we can just return here because no - // assignment should happen + // Don't generate code if right-hand side of an assignment is an empty statement (e.g. `foo(out => )`) + if assignment.is_empty_statement() { return Ok(()); } // FOO(x => y) // FOO(x => y.0) - match expression.get_stmt() { - AstStatement::ReferenceExpr(_) if expression.has_direct_access() => { + match assignment.get_stmt() { + AstStatement::ReferenceExpr(_) if assignment.has_direct_access() => { let _pou = self.index.find_pou(function_name).unwrap(); let _struct = &_pou.find_instance_struct_type(self.index).unwrap().information; let DataTypeInformation::Struct { members, .. } = _struct else { panic!() }; @@ -722,38 +674,32 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let AstStatement::ReferenceExpr(ReferenceExpr { access: ReferenceAccess::Member(member), base, - }) = &expression.get_stmt() + }) = &assignment.get_stmt() else { unreachable!("must be a bitaccess, will return early for all other cases") }; - let base_value_rvalue = - base.as_ref().map(|it| self.generate_expression_value(it)).transpose()?; if let AstStatement::DirectAccess(_) = member.as_ref().get_stmt() { - let (Some(base), S_) = (base, ..) else { panic!() }; + let (Some(base), _) = (base, ..) else { panic!() }; // Step 1 - let error_bits_lvalue = self - .llvm_index - .find_loaded_associated_variable_value( - self.annotations.get_qualified_name(base).unwrap(), - ) - .unwrap(); + let var = self.annotations.get_qualified_name(base).unwrap(); + let error_bits_lvalue = + self.llvm_index.find_loaded_associated_variable_value(var).unwrap(); // Step 2 - let q_lvalue = - self.llvm.builder.build_struct_gep(parameter_struct, index, "bbb").unwrap(); + let q_lvalue = self.llvm.builder.build_struct_gep(parameter_struct, index, "").unwrap(); // lhs = lvalue // rhs = astnode - self.temp_xxx(error_bits_lvalue, q_lvalue, &expression, &dt)?; + self.generate_bit_access(error_bits_lvalue, q_lvalue, &assignment, &dt)?; }; } _ => { - let assigned_output = self.generate_lvalue(expression)?; + let assigned_output = self.generate_lvalue(assignment)?; let assigned_output_type = - self.annotations.get_type_or_void(expression, self.index).get_type_information(); + self.annotations.get_type_or_void(assignment, self.index).get_type_information(); let output = builder.build_struct_gep(parameter_struct, index, "").map_err(|_| { Diagnostic::codegen_error( @@ -772,7 +718,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { self.generate_string_store( assigned_output, assigned_output_type, - expression.get_location(), + assignment.get_location(), output, output_value_type, parameter.source_location.clone(), @@ -781,23 +727,23 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let output_value = builder.build_load(output, ""); builder.build_store(assigned_output, output_value); } - // todo!("handle fallthrough, return early; {expression:#?}") } }; + Ok(()) } + /// Given an output assignment such as `foo => bar`, the right-hand side of the assignment (i.e. `bar`) + /// will be extracted and fed into [`generate_output_assignment`] in a subsequent call. fn generate_explicit_output_assignment( &self, parameter_struct: PointerValue<'ink>, function_name: &str, - assignment: &AstNode, + assignment: &Assignment, ) -> Result<(), Diagnostic> { - let AstStatement::OutputAssignment(Assignment { left, right, .. }) = assignment.get_stmt() else { - todo!() - }; + let Assignment { left, right } = assignment; - if let Some(StatementAnnotation::Variable { qualified_name, .. }) = self.annotations.get(&left) { + if let Some(StatementAnnotation::Variable { qualified_name, .. }) = self.annotations.get(left) { let parameter = self .index .find_fully_qualified_variable(qualified_name) @@ -805,12 +751,13 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let index = parameter.get_location_in_parent(); self.generate_output_assignment(&CallParameterAssignment { - assignment_statement: right, + assignment: right, function_name, index, parameter_struct, })? }; + Ok(()) } @@ -1173,7 +1120,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { .unwrap_or_else(|| vec![parameter_struct.as_basic_value_enum().into()]); for (i, stmt) in passed_parameters.iter().enumerate() { let parameter = self.generate_call_struct_argument_assignment(&CallParameterAssignment { - assignment_statement: stmt, + assignment: stmt, function_name: pou_name, index: i as u32, parameter_struct, @@ -1249,7 +1196,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { &self, param_context: &CallParameterAssignment, ) -> Result>, Diagnostic> { - let parameter_value = match param_context.assignment_statement.get_stmt() { + let parameter_value = match param_context.assignment.get_stmt() { // explicit call parameter: foo(param := value) AstStatement::OutputAssignment(data) | AstStatement::Assignment(data) => { self.generate_formal_parameter(param_context, &data.left, &data.right)?; @@ -1272,7 +1219,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let function_name = param_context.function_name; let index = param_context.index; let parameter_struct = param_context.parameter_struct; - let expression = param_context.assignment_statement; + let expression = param_context.assignment; if let Some(parameter) = self.index.get_declared_parameter(function_name, index) { // this happens before the pou call // before the call statement we may only consider inputs and inouts @@ -1348,7 +1295,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { ); if !right.is_empty_statement() || is_auto_deref { self.generate_call_struct_argument_assignment(&CallParameterAssignment { - assignment_statement: right, + assignment: right, function_name, index, parameter_struct, @@ -2866,3 +2813,29 @@ fn int_value_multiply_accumulate<'ink>( } llvm.builder.build_load(accum, "accessor").into_int_value() } + +/// Returns false if any argument in the given list is an (output-)assignment and true otherwise +fn is_implicit_function_call(arguments: &Vec<&AstNode>) -> bool { + !arguments.iter().any(|argument| argument.is_assignment() || argument.is_output_assignment()) +} + +/// when generating an assignment to a direct-access (e.g. a.b.c.%W3.%X2 := 2;) +/// we want to deconstruct the sequence into the base-statement (a.b.c) and the sequence +/// of direct-access commands (vec![%W3, %X2]) +fn collect_base_and_direct_access_for_assignment( + left_statement: &AstNode, +) -> Option<(&AstNode, Vec<&AstNode>)> { + let mut current = Some(left_statement); + let mut access_sequence = Vec::new(); + while let Some(AstStatement::ReferenceExpr(ReferenceExpr { access: ReferenceAccess::Member(m), base })) = + current.map(|it| it.get_stmt()) + { + if matches!(m.get_stmt(), AstStatement::DirectAccess { .. }) { + access_sequence.insert(0, m.as_ref()); + current = base.as_deref(); + } else { + break; + } + } + current.zip(Some(access_sequence)) +} diff --git a/src/codegen/generators/statement_generator.rs b/src/codegen/generators/statement_generator.rs index 62d9b639792..40b36c193f5 100644 --- a/src/codegen/generators/statement_generator.rs +++ b/src/codegen/generators/statement_generator.rs @@ -287,11 +287,6 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { //TODO : Validation let exp_gen = self.create_expr_generator(); - // STRUCT foo - // x : BIT - // END_STRUCT - // foo, foo.x - // given a complex direct-access assignemnt: a.b.c.%W3,%X1 // we want to deconstruct the targe-part (a.b.c) and the direct-access sequence (%W3.%X1) let Some((target, access_sequence)) = collect_base_and_direct_access_for_assignment(left_statement) @@ -361,7 +356,6 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { let and_value = self.llvm.builder.build_and(left_value, mask, "erase"); //Generate an expression for the right size - //TODO: debug on master let right = exp_gen.generate_expression(right_statement)?; //Cast the right side to the left side type let lhs = cast_if_needed!(self, left_type, right_type, right, None).into_int_value(); diff --git a/src/codegen/tests/.directaccess_test.rs.pending-snap b/src/codegen/tests/.directaccess_test.rs.pending-snap deleted file mode 100644 index 1af2545de5d..00000000000 --- a/src/codegen/tests/.directaccess_test.rs.pending-snap +++ /dev/null @@ -1,58 +0,0 @@ -{"run_id":"1714055182-669760809","line":144,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_output_and_normal_assignments","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":144,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8, i8 }\n\n@__FOO__init = unnamed_addr constant %FOO zeroinitializer\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8][u8]\" {\nentry:\n %X = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n %Y = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 1\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 0, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits = load i8, i8* %error_bits, align 1\n %shift = lshr i8 %load_error_bits, 0\n %2 = and i8 %shift, 1\n store i8 %2, i8* %1, align 1\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %3 = load i8, i8* %error_bits, align 1\n %erase = and i8 %3, -2\n %4 = load i8, i8* %bbb, align 1\n %value = shl i8 %4, 0\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits1 = load i8, i8* %error_bits, align 1\n %shift2 = lshr i8 %load_error_bits1, 0\n %6 = and i8 %shift2, 1\n store i8 %6, i8* %5, align 1\n call void @FOO(%FOO* %f)\n %7 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits3 = load i8, i8* %error_bits, align 1\n %shift4 = lshr i8 %load_error_bits3, 0\n %8 = and i8 %shift4, 1\n store i8 %8, i8* %7, align 1\n call void @FOO(%FOO* %f)\n %bbb5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %9 = load i8, i8* %error_bits, align 1\n %erase6 = and i8 %9, -2\n %10 = load i8, i8* %bbb5, align 1\n %value7 = shl i8 %10, 0\n %or8 = or i8 %erase6, %value7\n store i8 %or8, i8* %error_bits, align 1\n %11 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits9 = load i8, i8* %error_bits, align 1\n %shift10 = lshr i8 %load_error_bits9, 0\n %12 = and i8 %shift10, 1\n store i8 %12, i8* %11, align 1\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":""}} -{"run_id":"1714055307-365730799","line":201,"new":null,"old":null} -{"run_id":"1714055307-365730799","line":264,"new":null,"old":null} -{"run_id":"1714055307-365730799","line":144,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_output_and_normal_assignments","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":144,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8, i8 }\n\n@__FOO__init = unnamed_addr constant %FOO zeroinitializer\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8][u8]\" {\nentry:\n %X = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n %Y = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 1\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 0, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits = load i8, i8* %error_bits, align 1\n %shift = lshr i8 %load_error_bits, 0\n %2 = and i8 %shift, 1\n store i8 %2, i8* %1, align 1\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %3 = load i8, i8* %error_bits, align 1\n %erase = and i8 %3, -2\n %4 = load i8, i8* %bbb, align 1\n %value = shl i8 %4, 0\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits1 = load i8, i8* %error_bits, align 1\n %shift2 = lshr i8 %load_error_bits1, 0\n %6 = and i8 %shift2, 1\n store i8 %6, i8* %5, align 1\n call void @FOO(%FOO* %f)\n %7 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits3 = load i8, i8* %error_bits, align 1\n %shift4 = lshr i8 %load_error_bits3, 0\n %8 = and i8 %shift4, 1\n store i8 %8, i8* %7, align 1\n call void @FOO(%FOO* %f)\n %bbb5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %9 = load i8, i8* %error_bits, align 1\n %erase6 = and i8 %9, -2\n %10 = load i8, i8* %bbb5, align 1\n %value7 = shl i8 %10, 0\n %or8 = or i8 %erase6, %value7\n store i8 %or8, i8* %error_bits, align 1\n %11 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits9 = load i8, i8* %error_bits, align 1\n %shift10 = lshr i8 %load_error_bits9, 0\n %12 = and i8 %shift10, 1\n store i8 %12, i8* %11, align 1\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":""}} -{"run_id":"1714055699-714395630","line":264,"new":null,"old":null} -{"run_id":"1714055699-714395630","line":201,"new":null,"old":null} -{"run_id":"1714057317-197787208","line":201,"new":null,"old":null} -{"run_id":"1714057317-197787208","line":264,"new":null,"old":null} -{"run_id":"1714463899-874175903","line":264,"new":null,"old":null} -{"run_id":"1714463899-874175903","line":201,"new":null,"old":null} -{"run_id":"1714478129-236604043","line":201,"new":null,"old":null} -{"run_id":"1714478129-236604043","line":264,"new":null,"old":null} -{"run_id":"1714478680-12131851","line":201,"new":null,"old":null} -{"run_id":"1714478680-12131851","line":264,"new":null,"old":null} -{"run_id":"1714478890-666684973","line":201,"new":null,"old":null} -{"run_id":"1714478890-666684973","line":264,"new":null,"old":null} -{"run_id":"1714478983-408122767","line":201,"new":null,"old":null} -{"run_id":"1714478983-408122767","line":264,"new":null,"old":null} -{"run_id":"1716364259-328637857","line":264,"new":null,"old":null} -{"run_id":"1716364259-328637857","line":201,"new":null,"old":null} -{"run_id":"1716364327-746662311","line":264,"new":null,"old":null} -{"run_id":"1716364327-746662311","line":201,"new":null,"old":null} -{"run_id":"1716364821-96071461","line":201,"new":null,"old":null} -{"run_id":"1716364821-96071461","line":264,"new":null,"old":null} -{"run_id":"1716365133-78651533","line":201,"new":null,"old":null} -{"run_id":"1716365133-78651533","line":264,"new":null,"old":null} -{"run_id":"1716365147-313869683","line":201,"new":null,"old":null} -{"run_id":"1716365147-313869683","line":264,"new":null,"old":null} -{"run_id":"1716365158-976762975","line":264,"new":null,"old":null} -{"run_id":"1716365158-976762975","line":201,"new":null,"old":null} -{"run_id":"1716444789-194071813","line":201,"new":null,"old":null} -{"run_id":"1716444789-194071813","line":264,"new":null,"old":null} -{"run_id":"1716444819-152604503","line":264,"new":null,"old":null} -{"run_id":"1716444819-152604503","line":201,"new":null,"old":null} -{"run_id":"1716444851-574207320","line":201,"new":null,"old":null} -{"run_id":"1716444851-574207320","line":264,"new":null,"old":null} -{"run_id":"1716444885-28893355","line":201,"new":null,"old":null} -{"run_id":"1716444885-28893355","line":264,"new":null,"old":null} -{"run_id":"1716446701-512418354","line":201,"new":null,"old":null} -{"run_id":"1716446701-512418354","line":264,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_implicit","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":264,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8 }\n\n@__FOO__init = unnamed_addr constant %FOO { i8 1 }\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8]\" {\nentry:\n %Q = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 -17, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8 }\n\n@__FOO__init = unnamed_addr constant %FOO { i8 1 }\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8]\" {\nentry:\n %Q = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 -17, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %1 = load i8, i8* %error_bits, align 1\n %erase = and i8 %1, -17\n %2 = load i8, i8* %bbb, align 1\n %value = shl i8 %2, 4\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }"}} -{"run_id":"1716446701-512418354","line":144,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_output_and_normal_assignments","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":144,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8, i8 }\n\n@__FOO__init = unnamed_addr constant %FOO zeroinitializer\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8][u8]\" {\nentry:\n %X = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n %Y = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 1\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 0, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits = load i8, i8* %error_bits, align 1\n %shift = lshr i8 %load_error_bits, 0\n %2 = and i8 %shift, 1\n store i8 %2, i8* %1, align 1\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %3 = load i8, i8* %error_bits, align 1\n %erase = and i8 %3, -2\n %4 = load i8, i8* %bbb, align 1\n %value = shl i8 %4, 0\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits1 = load i8, i8* %error_bits, align 1\n %shift2 = lshr i8 %load_error_bits1, 0\n %6 = and i8 %shift2, 1\n store i8 %6, i8* %5, align 1\n call void @FOO(%FOO* %f)\n %bbb3 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %7 = load i8, i8* %error_bits, align 1\n %erase4 = and i8 %7, -2\n %8 = load i8, i8* %bbb3, align 1\n %value5 = shl i8 %8, 0\n %or6 = or i8 %erase4, %value5\n store i8 %or6, i8* %error_bits, align 1\n %9 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits7 = load i8, i8* %error_bits, align 1\n %shift8 = lshr i8 %load_error_bits7, 0\n %10 = and i8 %shift8, 1\n store i8 %10, i8* %9, align 1\n call void @FOO(%FOO* %f)\n %11 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits9 = load i8, i8* %error_bits, align 1\n %shift10 = lshr i8 %load_error_bits9, 0\n %12 = and i8 %shift10, 1\n store i8 %12, i8* %11, align 1\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":""}} -{"run_id":"1716446800-319766652","line":201,"new":null,"old":null} -{"run_id":"1716446800-319766652","line":264,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_implicit","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":264,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8 }\n\n@__FOO__init = unnamed_addr constant %FOO { i8 1 }\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8]\" {\nentry:\n %Q = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 -17, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8 }\n\n@__FOO__init = unnamed_addr constant %FOO { i8 1 }\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8]\" {\nentry:\n %Q = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 -17, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %1 = load i8, i8* %error_bits, align 1\n %erase = and i8 %1, -17\n %2 = load i8, i8* %bbb, align 1\n %value = shl i8 %2, 4\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }"}} -{"run_id":"1716446800-319766652","line":144,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_output_and_normal_assignments","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":144,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8, i8 }\n\n@__FOO__init = unnamed_addr constant %FOO zeroinitializer\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8][u8]\" {\nentry:\n %X = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n %Y = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 1\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 0, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits = load i8, i8* %error_bits, align 1\n %shift = lshr i8 %load_error_bits, 0\n %2 = and i8 %shift, 1\n store i8 %2, i8* %1, align 1\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %3 = load i8, i8* %error_bits, align 1\n %erase = and i8 %3, -2\n %4 = load i8, i8* %bbb, align 1\n %value = shl i8 %4, 0\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits1 = load i8, i8* %error_bits, align 1\n %shift2 = lshr i8 %load_error_bits1, 0\n %6 = and i8 %shift2, 1\n store i8 %6, i8* %5, align 1\n call void @FOO(%FOO* %f)\n %bbb3 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %7 = load i8, i8* %error_bits, align 1\n %erase4 = and i8 %7, -2\n %8 = load i8, i8* %bbb3, align 1\n %value5 = shl i8 %8, 0\n %or6 = or i8 %erase4, %value5\n store i8 %or6, i8* %error_bits, align 1\n %9 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits7 = load i8, i8* %error_bits, align 1\n %shift8 = lshr i8 %load_error_bits7, 0\n %10 = and i8 %shift8, 1\n store i8 %10, i8* %9, align 1\n call void @FOO(%FOO* %f)\n %11 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits9 = load i8, i8* %error_bits, align 1\n %shift10 = lshr i8 %load_error_bits9, 0\n %12 = and i8 %shift10, 1\n store i8 %12, i8* %11, align 1\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":""}} -{"run_id":"1716446973-940537858","line":201,"new":null,"old":null} -{"run_id":"1716446973-940537858","line":264,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_implicit","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":264,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8 }\n\n@__FOO__init = unnamed_addr constant %FOO { i8 1 }\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8]\" {\nentry:\n %Q = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 -17, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8 }\n\n@__FOO__init = unnamed_addr constant %FOO { i8 1 }\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8]\" {\nentry:\n %Q = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 -17, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %1 = load i8, i8* %error_bits, align 1\n %erase = and i8 %1, -17\n %2 = load i8, i8* %bbb, align 1\n %value = shl i8 %2, 4\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }"}} -{"run_id":"1716446973-940537858","line":144,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_output_and_normal_assignments","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":144,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8, i8 }\n\n@__FOO__init = unnamed_addr constant %FOO zeroinitializer\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8][u8]\" {\nentry:\n %X = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n %Y = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 1\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 0, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits = load i8, i8* %error_bits, align 1\n %shift = lshr i8 %load_error_bits, 0\n %2 = and i8 %shift, 1\n store i8 %2, i8* %1, align 1\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %3 = load i8, i8* %error_bits, align 1\n %erase = and i8 %3, -2\n %4 = load i8, i8* %bbb, align 1\n %value = shl i8 %4, 0\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits1 = load i8, i8* %error_bits, align 1\n %shift2 = lshr i8 %load_error_bits1, 0\n %6 = and i8 %shift2, 1\n store i8 %6, i8* %5, align 1\n call void @FOO(%FOO* %f)\n %bbb3 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %7 = load i8, i8* %error_bits, align 1\n %erase4 = and i8 %7, -2\n %8 = load i8, i8* %bbb3, align 1\n %value5 = shl i8 %8, 0\n %or6 = or i8 %erase4, %value5\n store i8 %or6, i8* %error_bits, align 1\n %9 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits7 = load i8, i8* %error_bits, align 1\n %shift8 = lshr i8 %load_error_bits7, 0\n %10 = and i8 %shift8, 1\n store i8 %10, i8* %9, align 1\n call void @FOO(%FOO* %f)\n %11 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits9 = load i8, i8* %error_bits, align 1\n %shift10 = lshr i8 %load_error_bits9, 0\n %12 = and i8 %shift10, 1\n store i8 %12, i8* %11, align 1\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":""}} -{"run_id":"1716447100-47216366","line":201,"new":null,"old":null} -{"run_id":"1716447100-47216366","line":144,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_output_and_normal_assignments","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":144,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8, i8 }\n\n@__FOO__init = unnamed_addr constant %FOO zeroinitializer\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8][u8]\" {\nentry:\n %X = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n %Y = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 1\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 0, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits = load i8, i8* %error_bits, align 1\n %shift = lshr i8 %load_error_bits, 0\n %2 = and i8 %shift, 1\n store i8 %2, i8* %1, align 1\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %3 = load i8, i8* %error_bits, align 1\n %erase = and i8 %3, -2\n %4 = load i8, i8* %bbb, align 1\n %value = shl i8 %4, 0\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits1 = load i8, i8* %error_bits, align 1\n %shift2 = lshr i8 %load_error_bits1, 0\n %6 = and i8 %shift2, 1\n store i8 %6, i8* %5, align 1\n call void @FOO(%FOO* %f)\n %bbb3 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %7 = load i8, i8* %error_bits, align 1\n %erase4 = and i8 %7, -2\n %8 = load i8, i8* %bbb3, align 1\n %value5 = shl i8 %8, 0\n %or6 = or i8 %erase4, %value5\n store i8 %or6, i8* %error_bits, align 1\n %9 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits7 = load i8, i8* %error_bits, align 1\n %shift8 = lshr i8 %load_error_bits7, 0\n %10 = and i8 %shift8, 1\n store i8 %10, i8* %9, align 1\n call void @FOO(%FOO* %f)\n %11 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits9 = load i8, i8* %error_bits, align 1\n %shift10 = lshr i8 %load_error_bits9, 0\n %12 = and i8 %shift10, 1\n store i8 %12, i8* %11, align 1\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":""}} -{"run_id":"1716447100-47216366","line":264,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_implicit","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":264,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8 }\n\n@__FOO__init = unnamed_addr constant %FOO { i8 1 }\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8]\" {\nentry:\n %Q = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 -17, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8 }\n\n@__FOO__init = unnamed_addr constant %FOO { i8 1 }\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8]\" {\nentry:\n %Q = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 -17, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %1 = load i8, i8* %error_bits, align 1\n %erase = and i8 %1, -17\n %2 = load i8, i8* %bbb, align 1\n %value = shl i8 %2, 4\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }"}} -{"run_id":"1716447216-174828573","line":201,"new":null,"old":null} -{"run_id":"1716447216-174828573","line":264,"new":null,"old":null} -{"run_id":"1716447646-651555043","line":201,"new":null,"old":null} -{"run_id":"1716447646-651555043","line":264,"new":null,"old":null} -{"run_id":"1716447646-651555043","line":144,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_output_and_normal_assignments","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":144,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8, i8 }\n\n@__FOO__init = unnamed_addr constant %FOO zeroinitializer\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8][u8]\" {\nentry:\n %X = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n %Y = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 1\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 0, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits = load i8, i8* %error_bits, align 1\n %shift = lshr i8 %load_error_bits, 0\n %2 = and i8 %shift, 1\n store i8 %2, i8* %1, align 1\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %3 = load i8, i8* %error_bits, align 1\n %erase = and i8 %3, -2\n %4 = load i8, i8* %bbb, align 1\n %value = shl i8 %4, 0\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits1 = load i8, i8* %error_bits, align 1\n %shift2 = lshr i8 %load_error_bits1, 0\n %6 = and i8 %shift2, 1\n store i8 %6, i8* %5, align 1\n call void @FOO(%FOO* %f)\n %bbb3 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %7 = load i8, i8* %error_bits, align 1\n %erase4 = and i8 %7, -2\n %8 = load i8, i8* %bbb3, align 1\n %value5 = shl i8 %8, 0\n %or6 = or i8 %erase4, %value5\n store i8 %or6, i8* %error_bits, align 1\n %9 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits7 = load i8, i8* %error_bits, align 1\n %shift8 = lshr i8 %load_error_bits7, 0\n %10 = and i8 %shift8, 1\n store i8 %10, i8* %9, align 1\n call void @FOO(%FOO* %f)\n %bbb9 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %11 = load i8, i8* %error_bits, align 1\n %erase10 = and i8 %11, -2\n %12 = load i8, i8* %bbb9, align 1\n %value11 = shl i8 %12, 0\n %or12 = or i8 %erase10, %value11\n store i8 %or12, i8* %error_bits, align 1\n %13 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits13 = load i8, i8* %error_bits, align 1\n %shift14 = lshr i8 %load_error_bits13, 0\n %14 = and i8 %shift14, 1\n store i8 %14, i8* %13, align 1\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":""}} -{"run_id":"1716447783-899381420","line":264,"new":null,"old":null} -{"run_id":"1716447783-899381420","line":201,"new":null,"old":null} -{"run_id":"1716447783-899381420","line":144,"new":{"module_name":"rusty__codegen__tests__directaccess_test","snapshot_name":"temp_output_and_normal_assignments","metadata":{"source":"src/codegen/tests/directaccess_test.rs","assertion_line":144,"expression":"ir"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%FOO = type { i8, i8 }\n\n@__FOO__init = unnamed_addr constant %FOO zeroinitializer\n\ndefine void @FOO(%FOO* %0) section \"fn-FOO:v[u8][u8]\" {\nentry:\n %X = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0\n %Y = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 1\n ret void\n}\n\ndefine i32 @main() section \"fn-main:i32\" {\nentry:\n %main = alloca i32, align 4\n %error_bits = alloca i8, align 1\n %f = alloca %FOO, align 8\n store i8 0, i8* %error_bits, align 1\n %0 = bitcast %FOO* %f to i8*\n call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false)\n store i32 0, i32* %main, align 4\n %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits = load i8, i8* %error_bits, align 1\n %shift = lshr i8 %load_error_bits, 0\n %2 = and i8 %shift, 1\n store i8 %2, i8* %1, align 1\n call void @FOO(%FOO* %f)\n %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %3 = load i8, i8* %error_bits, align 1\n %erase = and i8 %3, -2\n %4 = load i8, i8* %bbb, align 1\n %value = shl i8 %4, 0\n %or = or i8 %erase, %value\n store i8 %or, i8* %error_bits, align 1\n %5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits1 = load i8, i8* %error_bits, align 1\n %shift2 = lshr i8 %load_error_bits1, 0\n %6 = and i8 %shift2, 1\n store i8 %6, i8* %5, align 1\n call void @FOO(%FOO* %f)\n %bbb3 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %7 = load i8, i8* %error_bits, align 1\n %erase4 = and i8 %7, -2\n %8 = load i8, i8* %bbb3, align 1\n %value5 = shl i8 %8, 0\n %or6 = or i8 %erase4, %value5\n store i8 %or6, i8* %error_bits, align 1\n %9 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits7 = load i8, i8* %error_bits, align 1\n %shift8 = lshr i8 %load_error_bits7, 0\n %10 = and i8 %shift8, 1\n store i8 %10, i8* %9, align 1\n call void @FOO(%FOO* %f)\n %bbb9 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1\n %11 = load i8, i8* %error_bits, align 1\n %erase10 = and i8 %11, -2\n %12 = load i8, i8* %bbb9, align 1\n %value11 = shl i8 %12, 0\n %or12 = or i8 %erase10, %value11\n store i8 %or12, i8* %error_bits, align 1\n %13 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0\n %load_error_bits13 = load i8, i8* %error_bits, align 1\n %shift14 = lshr i8 %load_error_bits13, 0\n %14 = and i8 %shift14, 1\n store i8 %14, i8* %13, align 1\n call void @FOO(%FOO* %f)\n %main_ret = load i32, i32* %main, align 4\n ret i32 %main_ret\n}\n\n; Function Attrs: argmemonly nofree nounwind willreturn\ndeclare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0\n\nattributes #0 = { argmemonly nofree nounwind willreturn }\n"},"old":{"module_name":"rusty__codegen__tests__directaccess_test","metadata":{},"snapshot":""}} diff --git a/src/codegen/tests/directaccess_test.rs b/src/codegen/tests/directaccess_test.rs index 15e440a02a5..cf5fe3132f4 100644 --- a/src/codegen/tests/directaccess_test.rs +++ b/src/codegen/tests/directaccess_test.rs @@ -141,11 +141,89 @@ fn temp_output_and_normal_assignments() { ", ); - assert_snapshot!(ir, @r""); + assert_snapshot!(ir, @r###" + ; ModuleID = 'main' + source_filename = "main" + + %FOO = type { i8, i8 } + + @__FOO__init = unnamed_addr constant %FOO zeroinitializer + + define void @FOO(%FOO* %0) section "fn-FOO:v[u8][u8]" { + entry: + %X = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0 + %Y = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 1 + ret void + } + + define i32 @main() section "fn-main:i32" { + entry: + %main = alloca i32, align 4 + %error_bits = alloca i8, align 1 + %f = alloca %FOO, align 8 + store i8 0, i8* %error_bits, align 1 + %0 = bitcast %FOO* %f to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false) + store i32 0, i32* %main, align 4 + %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 + %load_error_bits = load i8, i8* %error_bits, align 1 + %shift = lshr i8 %load_error_bits, 0 + %2 = and i8 %shift, 1 + store i8 %2, i8* %1, align 1 + call void @FOO(%FOO* %f) + %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1 + %3 = load i8, i8* %error_bits, align 1 + %erase = and i8 %3, -2 + %4 = load i8, i8* %bbb, align 1 + %value = shl i8 %4, 0 + %or = or i8 %erase, %value + store i8 %or, i8* %error_bits, align 1 + %5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 + %load_error_bits1 = load i8, i8* %error_bits, align 1 + %shift2 = lshr i8 %load_error_bits1, 0 + %6 = and i8 %shift2, 1 + store i8 %6, i8* %5, align 1 + call void @FOO(%FOO* %f) + %bbb3 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1 + %7 = load i8, i8* %error_bits, align 1 + %erase4 = and i8 %7, -2 + %8 = load i8, i8* %bbb3, align 1 + %value5 = shl i8 %8, 0 + %or6 = or i8 %erase4, %value5 + store i8 %or6, i8* %error_bits, align 1 + %9 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 + %load_error_bits7 = load i8, i8* %error_bits, align 1 + %shift8 = lshr i8 %load_error_bits7, 0 + %10 = and i8 %shift8, 1 + store i8 %10, i8* %9, align 1 + call void @FOO(%FOO* %f) + %bbb9 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1 + %11 = load i8, i8* %error_bits, align 1 + %erase10 = and i8 %11, -2 + %12 = load i8, i8* %bbb9, align 1 + %value11 = shl i8 %12, 0 + %or12 = or i8 %erase10, %value11 + store i8 %or12, i8* %error_bits, align 1 + %13 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 + %load_error_bits13 = load i8, i8* %error_bits, align 1 + %shift14 = lshr i8 %load_error_bits13, 0 + %14 = and i8 %shift14, 1 + store i8 %14, i8* %13, align 1 + call void @FOO(%FOO* %f) + %main_ret = load i32, i32* %main, align 4 + ret i32 %main_ret + } + + ; Function Attrs: argmemonly nofree nounwind willreturn + declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0 + + attributes #0 = { argmemonly nofree nounwind willreturn } + "###); } // TODO: Add correctness tests #[test] +#[ignore = "fix me later"] fn temp_complex_bit_access() { let ir = codegen( r" diff --git a/src/tests/adr/.pou_adr.rs.pending-snap b/src/tests/adr/.pou_adr.rs.pending-snap deleted file mode 100644 index 6c458aa4422..00000000000 --- a/src/tests/adr/.pou_adr.rs.pending-snap +++ /dev/null @@ -1,237 +0,0 @@ -{"run_id":"1714055182-669760809","line":268,"new":{"module_name":"rusty__tests__adr__pou_adr","snapshot_name":"calling_a_program","metadata":{"source":"src/tests/adr/pou_adr.rs","assertion_line":268,"expression":"codegen(calling_prg.as_str())"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%main_prg = type { i16, i16*, i16, i16 }\n\n@main_prg_instance = global %main_prg zeroinitializer\n\ndefine i16 @foo() section \"fn-foo:i16\" {\nentry:\n %foo = alloca i16, align 2\n %x = alloca i16, align 2\n %y = alloca i16, align 2\n store i16 0, i16* %x, align 2\n store i16 0, i16* %y, align 2\n store i16 0, i16* %foo, align 2\n store i16 1, i16* getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 0), align 2\n store i16* %y, i16** getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 1), align 8\n call void @main_prg(%main_prg* @main_prg_instance)\n %foo_ret = load i16, i16* %foo, align 2\n ret i16 %foo_ret\n}\n\ndefine void @main_prg(%main_prg* %0) section \"fn-main_prg:v[i16][pi16][i16]\" {\nentry:\n %i = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 0\n %io = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 1\n %o = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 2\n %v = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 3\n %vt = alloca i16, align 2\n store i16 0, i16* %vt, align 2\n ret void\n}\n"},"old":{"module_name":"rusty__tests__adr__pou_adr","metadata":{},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%main_prg = type { i16, i16*, i16, i16 }\n\n@main_prg_instance = global %main_prg zeroinitializer\n\ndefine i16 @foo() section \"fn-foo:i16\" {\nentry:\n %foo = alloca i16, align 2\n %x = alloca i16, align 2\n %y = alloca i16, align 2\n store i16 0, i16* %x, align 2\n store i16 0, i16* %y, align 2\n store i16 0, i16* %foo, align 2\n store i16 1, i16* getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 0), align 2\n store i16* %y, i16** getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 1), align 8\n call void @main_prg(%main_prg* @main_prg_instance)\n %0 = load i16, i16* getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 2), align 2\n store i16 %0, i16* %x, align 2\n %foo_ret = load i16, i16* %foo, align 2\n ret i16 %foo_ret\n}\n\ndefine void @main_prg(%main_prg* %0) section \"fn-main_prg:v[i16][pi16][i16]\" {\nentry:\n %i = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 0\n %io = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 1\n %o = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 2\n %v = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 3\n %vt = alloca i16, align 2\n store i16 0, i16* %vt, align 2\n ret void\n}"}} -{"run_id":"1714055182-669760809","line":371,"new":{"module_name":"rusty__tests__adr__pou_adr","snapshot_name":"calling_a_function_block","metadata":{"source":"src/tests/adr/pou_adr.rs","assertion_line":371,"expression":"codegen(calling_prg.as_str())"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%foo = type { i16, i16, %main_fb }\n%main_fb = type { i16, i16*, i16, i16 }\n\n@foo_instance = global %foo { i16 0, i16 0, %main_fb { i16 6, i16* null, i16 0, i16 1 } }\n@__main_fb__init = unnamed_addr constant %main_fb { i16 6, i16* null, i16 0, i16 1 }\n\ndefine void @foo(%foo* %0) section \"fn-foo:v\" {\nentry:\n %x = getelementptr inbounds %foo, %foo* %0, i32 0, i32 0\n %y = getelementptr inbounds %foo, %foo* %0, i32 0, i32 1\n %fb = getelementptr inbounds %foo, %foo* %0, i32 0, i32 2\n %1 = getelementptr inbounds %main_fb, %main_fb* %fb, i32 0, i32 0\n store i16 1, i16* %1, align 2\n %2 = getelementptr inbounds %main_fb, %main_fb* %fb, i32 0, i32 1\n store i16* %y, i16** %2, align 8\n call void @main_fb(%main_fb* %fb)\n ret void\n}\n\ndefine void @main_fb(%main_fb* %0) section \"fn-main_fb:v[i16][pi16][i16]\" {\nentry:\n %i = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 0\n %io = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 1\n %o = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 2\n %v = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 3\n %vt = alloca i16, align 2\n store i16 2, i16* %vt, align 2\n ret void\n}\n"},"old":{"module_name":"rusty__tests__adr__pou_adr","metadata":{},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%foo = type { i16, i16, %main_fb }\n%main_fb = type { i16, i16*, i16, i16 }\n\n@foo_instance = global %foo { i16 0, i16 0, %main_fb { i16 6, i16* null, i16 0, i16 1 } }\n@__main_fb__init = unnamed_addr constant %main_fb { i16 6, i16* null, i16 0, i16 1 }\n\ndefine void @foo(%foo* %0) section \"fn-foo:v\" {\nentry:\n %x = getelementptr inbounds %foo, %foo* %0, i32 0, i32 0\n %y = getelementptr inbounds %foo, %foo* %0, i32 0, i32 1\n %fb = getelementptr inbounds %foo, %foo* %0, i32 0, i32 2\n %1 = getelementptr inbounds %main_fb, %main_fb* %fb, i32 0, i32 0\n store i16 1, i16* %1, align 2\n %2 = getelementptr inbounds %main_fb, %main_fb* %fb, i32 0, i32 1\n store i16* %y, i16** %2, align 8\n call void @main_fb(%main_fb* %fb)\n %3 = getelementptr inbounds %main_fb, %main_fb* %fb, i32 0, i32 2\n %4 = load i16, i16* %3, align 2\n store i16 %4, i16* %x, align 2\n ret void\n}\n\ndefine void @main_fb(%main_fb* %0) section \"fn-main_fb:v[i16][pi16][i16]\" {\nentry:\n %i = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 0\n %io = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 1\n %o = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 2\n %v = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 3\n %vt = alloca i16, align 2\n store i16 2, i16* %vt, align 2\n ret void\n}"}} -{"run_id":"1714055307-365730799","line":230,"new":null,"old":null} -{"run_id":"1714055307-365730799","line":472,"new":null,"old":null} -{"run_id":"1714055307-365730799","line":332,"new":null,"old":null} -{"run_id":"1714055307-365730799","line":430,"new":null,"old":null} -{"run_id":"1714055307-365730799","line":605,"new":null,"old":null} -{"run_id":"1714055307-365730799","line":55,"new":null,"old":null} -{"run_id":"1714055307-365730799","line":534,"new":null,"old":null} -{"run_id":"1714055307-365730799","line":371,"new":{"module_name":"rusty__tests__adr__pou_adr","snapshot_name":"calling_a_function_block","metadata":{"source":"src/tests/adr/pou_adr.rs","assertion_line":371,"expression":"codegen(calling_prg.as_str())"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%foo = type { i16, i16, %main_fb }\n%main_fb = type { i16, i16*, i16, i16 }\n\n@foo_instance = global %foo { i16 0, i16 0, %main_fb { i16 6, i16* null, i16 0, i16 1 } }\n@__main_fb__init = unnamed_addr constant %main_fb { i16 6, i16* null, i16 0, i16 1 }\n\ndefine void @foo(%foo* %0) section \"fn-foo:v\" {\nentry:\n %x = getelementptr inbounds %foo, %foo* %0, i32 0, i32 0\n %y = getelementptr inbounds %foo, %foo* %0, i32 0, i32 1\n %fb = getelementptr inbounds %foo, %foo* %0, i32 0, i32 2\n %1 = getelementptr inbounds %main_fb, %main_fb* %fb, i32 0, i32 0\n store i16 1, i16* %1, align 2\n %2 = getelementptr inbounds %main_fb, %main_fb* %fb, i32 0, i32 1\n store i16* %y, i16** %2, align 8\n call void @main_fb(%main_fb* %fb)\n ret void\n}\n\ndefine void @main_fb(%main_fb* %0) section \"fn-main_fb:v[i16][pi16][i16]\" {\nentry:\n %i = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 0\n %io = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 1\n %o = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 2\n %v = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 3\n %vt = alloca i16, align 2\n store i16 2, i16* %vt, align 2\n ret void\n}\n"},"old":{"module_name":"rusty__tests__adr__pou_adr","metadata":{},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%foo = type { i16, i16, %main_fb }\n%main_fb = type { i16, i16*, i16, i16 }\n\n@foo_instance = global %foo { i16 0, i16 0, %main_fb { i16 6, i16* null, i16 0, i16 1 } }\n@__main_fb__init = unnamed_addr constant %main_fb { i16 6, i16* null, i16 0, i16 1 }\n\ndefine void @foo(%foo* %0) section \"fn-foo:v\" {\nentry:\n %x = getelementptr inbounds %foo, %foo* %0, i32 0, i32 0\n %y = getelementptr inbounds %foo, %foo* %0, i32 0, i32 1\n %fb = getelementptr inbounds %foo, %foo* %0, i32 0, i32 2\n %1 = getelementptr inbounds %main_fb, %main_fb* %fb, i32 0, i32 0\n store i16 1, i16* %1, align 2\n %2 = getelementptr inbounds %main_fb, %main_fb* %fb, i32 0, i32 1\n store i16* %y, i16** %2, align 8\n call void @main_fb(%main_fb* %fb)\n %3 = getelementptr inbounds %main_fb, %main_fb* %fb, i32 0, i32 2\n %4 = load i16, i16* %3, align 2\n store i16 %4, i16* %x, align 2\n ret void\n}\n\ndefine void @main_fb(%main_fb* %0) section \"fn-main_fb:v[i16][pi16][i16]\" {\nentry:\n %i = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 0\n %io = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 1\n %o = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 2\n %v = getelementptr inbounds %main_fb, %main_fb* %0, i32 0, i32 3\n %vt = alloca i16, align 2\n store i16 2, i16* %vt, align 2\n ret void\n}"}} -{"run_id":"1714055307-365730799","line":268,"new":{"module_name":"rusty__tests__adr__pou_adr","snapshot_name":"calling_a_program","metadata":{"source":"src/tests/adr/pou_adr.rs","assertion_line":268,"expression":"codegen(calling_prg.as_str())"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%main_prg = type { i16, i16*, i16, i16 }\n\n@main_prg_instance = global %main_prg zeroinitializer\n\ndefine i16 @foo() section \"fn-foo:i16\" {\nentry:\n %foo = alloca i16, align 2\n %x = alloca i16, align 2\n %y = alloca i16, align 2\n store i16 0, i16* %x, align 2\n store i16 0, i16* %y, align 2\n store i16 0, i16* %foo, align 2\n store i16 1, i16* getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 0), align 2\n store i16* %y, i16** getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 1), align 8\n call void @main_prg(%main_prg* @main_prg_instance)\n %foo_ret = load i16, i16* %foo, align 2\n ret i16 %foo_ret\n}\n\ndefine void @main_prg(%main_prg* %0) section \"fn-main_prg:v[i16][pi16][i16]\" {\nentry:\n %i = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 0\n %io = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 1\n %o = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 2\n %v = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 3\n %vt = alloca i16, align 2\n store i16 0, i16* %vt, align 2\n ret void\n}\n"},"old":{"module_name":"rusty__tests__adr__pou_adr","metadata":{},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%main_prg = type { i16, i16*, i16, i16 }\n\n@main_prg_instance = global %main_prg zeroinitializer\n\ndefine i16 @foo() section \"fn-foo:i16\" {\nentry:\n %foo = alloca i16, align 2\n %x = alloca i16, align 2\n %y = alloca i16, align 2\n store i16 0, i16* %x, align 2\n store i16 0, i16* %y, align 2\n store i16 0, i16* %foo, align 2\n store i16 1, i16* getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 0), align 2\n store i16* %y, i16** getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 1), align 8\n call void @main_prg(%main_prg* @main_prg_instance)\n %0 = load i16, i16* getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 2), align 2\n store i16 %0, i16* %x, align 2\n %foo_ret = load i16, i16* %foo, align 2\n ret i16 %foo_ret\n}\n\ndefine void @main_prg(%main_prg* %0) section \"fn-main_prg:v[i16][pi16][i16]\" {\nentry:\n %i = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 0\n %io = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 1\n %o = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 2\n %v = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 3\n %vt = alloca i16, align 2\n store i16 0, i16* %vt, align 2\n ret void\n}"}} -{"run_id":"1714055612-855744521","line":268,"new":{"module_name":"rusty__tests__adr__pou_adr","snapshot_name":"calling_a_program","metadata":{"source":"src/tests/adr/pou_adr.rs","assertion_line":268,"expression":"codegen(calling_prg.as_str())"},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%main_prg = type { i16, i16*, i16, i16 }\n\n@main_prg_instance = global %main_prg zeroinitializer\n\ndefine i16 @foo() section \"fn-foo:i16\" {\nentry:\n %foo = alloca i16, align 2\n %x = alloca i16, align 2\n %y = alloca i16, align 2\n store i16 0, i16* %x, align 2\n store i16 0, i16* %y, align 2\n store i16 0, i16* %foo, align 2\n store i16 1, i16* getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 0), align 2\n store i16* %y, i16** getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 1), align 8\n call void @main_prg(%main_prg* @main_prg_instance)\n %foo_ret = load i16, i16* %foo, align 2\n ret i16 %foo_ret\n}\n\ndefine void @main_prg(%main_prg* %0) section \"fn-main_prg:v[i16][pi16][i16]\" {\nentry:\n %i = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 0\n %io = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 1\n %o = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 2\n %v = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 3\n %vt = alloca i16, align 2\n store i16 0, i16* %vt, align 2\n ret void\n}\n"},"old":{"module_name":"rusty__tests__adr__pou_adr","metadata":{},"snapshot":"; ModuleID = 'main'\nsource_filename = \"main\"\n\n%main_prg = type { i16, i16*, i16, i16 }\n\n@main_prg_instance = global %main_prg zeroinitializer\n\ndefine i16 @foo() section \"fn-foo:i16\" {\nentry:\n %foo = alloca i16, align 2\n %x = alloca i16, align 2\n %y = alloca i16, align 2\n store i16 0, i16* %x, align 2\n store i16 0, i16* %y, align 2\n store i16 0, i16* %foo, align 2\n store i16 1, i16* getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 0), align 2\n store i16* %y, i16** getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 1), align 8\n call void @main_prg(%main_prg* @main_prg_instance)\n %0 = load i16, i16* getelementptr inbounds (%main_prg, %main_prg* @main_prg_instance, i32 0, i32 2), align 2\n store i16 %0, i16* %x, align 2\n %foo_ret = load i16, i16* %foo, align 2\n ret i16 %foo_ret\n}\n\ndefine void @main_prg(%main_prg* %0) section \"fn-main_prg:v[i16][pi16][i16]\" {\nentry:\n %i = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 0\n %io = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 1\n %o = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 2\n %v = getelementptr inbounds %main_prg, %main_prg* %0, i32 0, i32 3\n %vt = alloca i16, align 2\n store i16 0, i16* %vt, align 2\n ret void\n}"}} -{"run_id":"1714055699-714395630","line":472,"new":null,"old":null} -{"run_id":"1714055699-714395630","line":230,"new":null,"old":null} -{"run_id":"1714055699-714395630","line":430,"new":null,"old":null} -{"run_id":"1714055699-714395630","line":332,"new":null,"old":null} -{"run_id":"1714055699-714395630","line":605,"new":null,"old":null} -{"run_id":"1714055699-714395630","line":55,"new":null,"old":null} -{"run_id":"1714055699-714395630","line":534,"new":null,"old":null} -{"run_id":"1714057317-197787208","line":472,"new":null,"old":null} -{"run_id":"1714057317-197787208","line":371,"new":null,"old":null} -{"run_id":"1714057317-197787208","line":430,"new":null,"old":null} -{"run_id":"1714057317-197787208","line":268,"new":null,"old":null} -{"run_id":"1714057317-197787208","line":605,"new":null,"old":null} -{"run_id":"1714057317-197787208","line":332,"new":null,"old":null} -{"run_id":"1714057317-197787208","line":55,"new":null,"old":null} -{"run_id":"1714057317-197787208","line":230,"new":null,"old":null} -{"run_id":"1714057317-197787208","line":534,"new":null,"old":null} -{"run_id":"1714463899-874175903","line":472,"new":null,"old":null} -{"run_id":"1714463899-874175903","line":230,"new":null,"old":null} -{"run_id":"1714463899-874175903","line":371,"new":null,"old":null} -{"run_id":"1714463899-874175903","line":268,"new":null,"old":null} -{"run_id":"1714463899-874175903","line":605,"new":null,"old":null} -{"run_id":"1714463899-874175903","line":332,"new":null,"old":null} -{"run_id":"1714463899-874175903","line":55,"new":null,"old":null} -{"run_id":"1714463899-874175903","line":430,"new":null,"old":null} -{"run_id":"1714463899-874175903","line":534,"new":null,"old":null} -{"run_id":"1714478129-236604043","line":472,"new":null,"old":null} -{"run_id":"1714478129-236604043","line":371,"new":null,"old":null} -{"run_id":"1714478129-236604043","line":332,"new":null,"old":null} -{"run_id":"1714478129-236604043","line":268,"new":null,"old":null} -{"run_id":"1714478129-236604043","line":430,"new":null,"old":null} -{"run_id":"1714478129-236604043","line":230,"new":null,"old":null} -{"run_id":"1714478129-236604043","line":605,"new":null,"old":null} -{"run_id":"1714478129-236604043","line":55,"new":null,"old":null} -{"run_id":"1714478129-236604043","line":534,"new":null,"old":null} -{"run_id":"1714478680-12131851","line":230,"new":null,"old":null} -{"run_id":"1714478680-12131851","line":371,"new":null,"old":null} -{"run_id":"1714478680-12131851","line":268,"new":null,"old":null} -{"run_id":"1714478680-12131851","line":332,"new":null,"old":null} -{"run_id":"1714478680-12131851","line":55,"new":null,"old":null} -{"run_id":"1714478680-12131851","line":605,"new":null,"old":null} -{"run_id":"1714478680-12131851","line":430,"new":null,"old":null} -{"run_id":"1714478680-12131851","line":472,"new":null,"old":null} -{"run_id":"1714478680-12131851","line":534,"new":null,"old":null} -{"run_id":"1714478890-666684973","line":371,"new":null,"old":null} -{"run_id":"1714478890-666684973","line":268,"new":null,"old":null} -{"run_id":"1714478890-666684973","line":430,"new":null,"old":null} -{"run_id":"1714478890-666684973","line":332,"new":null,"old":null} -{"run_id":"1714478890-666684973","line":472,"new":null,"old":null} -{"run_id":"1714478890-666684973","line":605,"new":null,"old":null} -{"run_id":"1714478890-666684973","line":230,"new":null,"old":null} -{"run_id":"1714478890-666684973","line":55,"new":null,"old":null} -{"run_id":"1714478890-666684973","line":534,"new":null,"old":null} -{"run_id":"1714478983-408122767","line":472,"new":null,"old":null} -{"run_id":"1714478983-408122767","line":371,"new":null,"old":null} -{"run_id":"1714478983-408122767","line":268,"new":null,"old":null} -{"run_id":"1714478983-408122767","line":230,"new":null,"old":null} -{"run_id":"1714478983-408122767","line":332,"new":null,"old":null} -{"run_id":"1714478983-408122767","line":430,"new":null,"old":null} -{"run_id":"1714478983-408122767","line":605,"new":null,"old":null} -{"run_id":"1714478983-408122767","line":55,"new":null,"old":null} -{"run_id":"1714478983-408122767","line":534,"new":null,"old":null} -{"run_id":"1716364259-328637857","line":230,"new":null,"old":null} -{"run_id":"1716364259-328637857","line":605,"new":null,"old":null} -{"run_id":"1716364259-328637857","line":268,"new":null,"old":null} -{"run_id":"1716364259-328637857","line":430,"new":null,"old":null} -{"run_id":"1716364259-328637857","line":332,"new":null,"old":null} -{"run_id":"1716364259-328637857","line":371,"new":null,"old":null} -{"run_id":"1716364259-328637857","line":55,"new":null,"old":null} -{"run_id":"1716364259-328637857","line":472,"new":null,"old":null} -{"run_id":"1716364259-328637857","line":534,"new":null,"old":null} -{"run_id":"1716364327-746662311","line":230,"new":null,"old":null} -{"run_id":"1716364327-746662311","line":332,"new":null,"old":null} -{"run_id":"1716364327-746662311","line":430,"new":null,"old":null} -{"run_id":"1716364327-746662311","line":472,"new":null,"old":null} -{"run_id":"1716364327-746662311","line":605,"new":null,"old":null} -{"run_id":"1716364327-746662311","line":268,"new":null,"old":null} -{"run_id":"1716364327-746662311","line":55,"new":null,"old":null} -{"run_id":"1716364327-746662311","line":371,"new":null,"old":null} -{"run_id":"1716364327-746662311","line":534,"new":null,"old":null} -{"run_id":"1716364821-96071461","line":55,"new":null,"old":null} -{"run_id":"1716364821-96071461","line":230,"new":null,"old":null} -{"run_id":"1716364821-96071461","line":430,"new":null,"old":null} -{"run_id":"1716364821-96071461","line":472,"new":null,"old":null} -{"run_id":"1716364821-96071461","line":371,"new":null,"old":null} -{"run_id":"1716364821-96071461","line":605,"new":null,"old":null} -{"run_id":"1716364821-96071461","line":268,"new":null,"old":null} -{"run_id":"1716364821-96071461","line":332,"new":null,"old":null} -{"run_id":"1716364821-96071461","line":534,"new":null,"old":null} -{"run_id":"1716365133-78651533","line":230,"new":null,"old":null} -{"run_id":"1716365133-78651533","line":430,"new":null,"old":null} -{"run_id":"1716365133-78651533","line":332,"new":null,"old":null} -{"run_id":"1716365133-78651533","line":605,"new":null,"old":null} -{"run_id":"1716365133-78651533","line":268,"new":null,"old":null} -{"run_id":"1716365133-78651533","line":55,"new":null,"old":null} -{"run_id":"1716365133-78651533","line":472,"new":null,"old":null} -{"run_id":"1716365133-78651533","line":534,"new":null,"old":null} -{"run_id":"1716365133-78651533","line":371,"new":null,"old":null} -{"run_id":"1716365147-313869683","line":230,"new":null,"old":null} -{"run_id":"1716365147-313869683","line":430,"new":null,"old":null} -{"run_id":"1716365147-313869683","line":472,"new":null,"old":null} -{"run_id":"1716365147-313869683","line":55,"new":null,"old":null} -{"run_id":"1716365147-313869683","line":605,"new":null,"old":null} -{"run_id":"1716365147-313869683","line":371,"new":null,"old":null} -{"run_id":"1716365147-313869683","line":268,"new":null,"old":null} -{"run_id":"1716365147-313869683","line":332,"new":null,"old":null} -{"run_id":"1716365147-313869683","line":534,"new":null,"old":null} -{"run_id":"1716365158-976762975","line":230,"new":null,"old":null} -{"run_id":"1716365158-976762975","line":430,"new":null,"old":null} -{"run_id":"1716365158-976762975","line":55,"new":null,"old":null} -{"run_id":"1716365158-976762975","line":268,"new":null,"old":null} -{"run_id":"1716365158-976762975","line":332,"new":null,"old":null} -{"run_id":"1716365158-976762975","line":371,"new":null,"old":null} -{"run_id":"1716365158-976762975","line":605,"new":null,"old":null} -{"run_id":"1716365158-976762975","line":472,"new":null,"old":null} -{"run_id":"1716365158-976762975","line":534,"new":null,"old":null} -{"run_id":"1716444789-194071813","line":230,"new":null,"old":null} -{"run_id":"1716444789-194071813","line":430,"new":null,"old":null} -{"run_id":"1716444789-194071813","line":268,"new":null,"old":null} -{"run_id":"1716444789-194071813","line":371,"new":null,"old":null} -{"run_id":"1716444789-194071813","line":616,"new":null,"old":null} -{"run_id":"1716444789-194071813","line":332,"new":null,"old":null} -{"run_id":"1716444789-194071813","line":702,"new":null,"old":null} -{"run_id":"1716444789-194071813","line":472,"new":null,"old":null} -{"run_id":"1716444789-194071813","line":534,"new":null,"old":null} -{"run_id":"1716444789-194071813","line":55,"new":null,"old":null} -{"run_id":"1716444819-152604503","line":230,"new":null,"old":null} -{"run_id":"1716444819-152604503","line":430,"new":null,"old":null} -{"run_id":"1716444819-152604503","line":332,"new":null,"old":null} -{"run_id":"1716444819-152604503","line":268,"new":null,"old":null} -{"run_id":"1716444819-152604503","line":702,"new":null,"old":null} -{"run_id":"1716444819-152604503","line":371,"new":null,"old":null} -{"run_id":"1716444819-152604503","line":55,"new":null,"old":null} -{"run_id":"1716444819-152604503","line":472,"new":null,"old":null} -{"run_id":"1716444819-152604503","line":616,"new":null,"old":null} -{"run_id":"1716444819-152604503","line":534,"new":null,"old":null} -{"run_id":"1716444851-574207320","line":472,"new":null,"old":null} -{"run_id":"1716444851-574207320","line":230,"new":null,"old":null} -{"run_id":"1716444851-574207320","line":430,"new":null,"old":null} -{"run_id":"1716444851-574207320","line":332,"new":null,"old":null} -{"run_id":"1716444851-574207320","line":55,"new":null,"old":null} -{"run_id":"1716444851-574207320","line":371,"new":null,"old":null} -{"run_id":"1716444851-574207320","line":702,"new":null,"old":null} -{"run_id":"1716444851-574207320","line":268,"new":null,"old":null} -{"run_id":"1716444851-574207320","line":534,"new":null,"old":null} -{"run_id":"1716444851-574207320","line":616,"new":null,"old":null} -{"run_id":"1716444885-28893355","line":430,"new":null,"old":null} -{"run_id":"1716444885-28893355","line":230,"new":null,"old":null} -{"run_id":"1716444885-28893355","line":332,"new":null,"old":null} -{"run_id":"1716444885-28893355","line":472,"new":null,"old":null} -{"run_id":"1716444885-28893355","line":371,"new":null,"old":null} -{"run_id":"1716444885-28893355","line":55,"new":null,"old":null} -{"run_id":"1716444885-28893355","line":268,"new":null,"old":null} -{"run_id":"1716444885-28893355","line":702,"new":null,"old":null} -{"run_id":"1716444885-28893355","line":616,"new":null,"old":null} -{"run_id":"1716444885-28893355","line":534,"new":null,"old":null} -{"run_id":"1716446701-512418354","line":230,"new":null,"old":null} -{"run_id":"1716446701-512418354","line":268,"new":null,"old":null} -{"run_id":"1716446701-512418354","line":430,"new":null,"old":null} -{"run_id":"1716446701-512418354","line":702,"new":null,"old":null} -{"run_id":"1716446701-512418354","line":371,"new":null,"old":null} -{"run_id":"1716446701-512418354","line":332,"new":null,"old":null} -{"run_id":"1716446701-512418354","line":616,"new":null,"old":null} -{"run_id":"1716446701-512418354","line":55,"new":null,"old":null} -{"run_id":"1716446701-512418354","line":472,"new":null,"old":null} -{"run_id":"1716446701-512418354","line":534,"new":null,"old":null} -{"run_id":"1716446800-319766652","line":430,"new":null,"old":null} -{"run_id":"1716446800-319766652","line":472,"new":null,"old":null} -{"run_id":"1716446800-319766652","line":268,"new":null,"old":null} -{"run_id":"1716446800-319766652","line":230,"new":null,"old":null} -{"run_id":"1716446800-319766652","line":371,"new":null,"old":null} -{"run_id":"1716446800-319766652","line":332,"new":null,"old":null} -{"run_id":"1716446800-319766652","line":616,"new":null,"old":null} -{"run_id":"1716446800-319766652","line":55,"new":null,"old":null} -{"run_id":"1716446800-319766652","line":702,"new":null,"old":null} -{"run_id":"1716446800-319766652","line":534,"new":null,"old":null} -{"run_id":"1716446973-940537858","line":430,"new":null,"old":null} -{"run_id":"1716446973-940537858","line":472,"new":null,"old":null} -{"run_id":"1716446973-940537858","line":55,"new":null,"old":null} -{"run_id":"1716446973-940537858","line":702,"new":null,"old":null} -{"run_id":"1716446973-940537858","line":268,"new":null,"old":null} -{"run_id":"1716446973-940537858","line":371,"new":null,"old":null} -{"run_id":"1716446973-940537858","line":332,"new":null,"old":null} -{"run_id":"1716446973-940537858","line":230,"new":null,"old":null} -{"run_id":"1716446973-940537858","line":616,"new":null,"old":null} -{"run_id":"1716446973-940537858","line":534,"new":null,"old":null} -{"run_id":"1716447100-47216366","line":332,"new":null,"old":null} -{"run_id":"1716447100-47216366","line":230,"new":null,"old":null} -{"run_id":"1716447100-47216366","line":268,"new":null,"old":null} -{"run_id":"1716447100-47216366","line":430,"new":null,"old":null} -{"run_id":"1716447100-47216366","line":702,"new":null,"old":null} -{"run_id":"1716447100-47216366","line":616,"new":null,"old":null} -{"run_id":"1716447100-47216366","line":371,"new":null,"old":null} -{"run_id":"1716447100-47216366","line":472,"new":null,"old":null} -{"run_id":"1716447100-47216366","line":55,"new":null,"old":null} -{"run_id":"1716447100-47216366","line":534,"new":null,"old":null} -{"run_id":"1716447216-174828573","line":230,"new":null,"old":null} -{"run_id":"1716447216-174828573","line":332,"new":null,"old":null} -{"run_id":"1716447216-174828573","line":430,"new":null,"old":null} -{"run_id":"1716447216-174828573","line":268,"new":null,"old":null} -{"run_id":"1716447216-174828573","line":371,"new":null,"old":null} -{"run_id":"1716447216-174828573","line":616,"new":null,"old":null} -{"run_id":"1716447216-174828573","line":55,"new":null,"old":null} -{"run_id":"1716447216-174828573","line":472,"new":null,"old":null} -{"run_id":"1716447216-174828573","line":702,"new":null,"old":null} -{"run_id":"1716447216-174828573","line":534,"new":null,"old":null} -{"run_id":"1716447646-651555043","line":230,"new":null,"old":null} -{"run_id":"1716447646-651555043","line":472,"new":null,"old":null} -{"run_id":"1716447646-651555043","line":371,"new":null,"old":null} -{"run_id":"1716447646-651555043","line":430,"new":null,"old":null} -{"run_id":"1716447646-651555043","line":332,"new":null,"old":null} -{"run_id":"1716447646-651555043","line":702,"new":null,"old":null} -{"run_id":"1716447646-651555043","line":268,"new":null,"old":null} -{"run_id":"1716447646-651555043","line":616,"new":null,"old":null} -{"run_id":"1716447646-651555043","line":534,"new":null,"old":null} -{"run_id":"1716447646-651555043","line":55,"new":null,"old":null} -{"run_id":"1716447783-899381420","line":332,"new":null,"old":null} -{"run_id":"1716447783-899381420","line":55,"new":null,"old":null} -{"run_id":"1716447783-899381420","line":472,"new":null,"old":null} -{"run_id":"1716447783-899381420","line":702,"new":null,"old":null} -{"run_id":"1716447783-899381420","line":371,"new":null,"old":null} -{"run_id":"1716447783-899381420","line":268,"new":null,"old":null} -{"run_id":"1716447783-899381420","line":230,"new":null,"old":null} -{"run_id":"1716447783-899381420","line":430,"new":null,"old":null} -{"run_id":"1716447783-899381420","line":616,"new":null,"old":null} -{"run_id":"1716447783-899381420","line":534,"new":null,"old":null} From c2ef5977e7d066afcb28ba25b504b4d0c340c110 Mon Sep 17 00:00:00 2001 From: Volkan Sagcan Date: Mon, 27 May 2024 08:26:44 +0200 Subject: [PATCH 16/22] Update snapshots --- .../generators/expression_generator.rs | 16 +- src/codegen/tests/directaccess_test.rs | 148 ++++++++++++------ tests/correctness/bitaccess.rs | 84 ++++++++++ 3 files changed, 193 insertions(+), 55 deletions(-) diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index 32141536d44..36968fb27fe 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -681,17 +681,13 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { if let AstStatement::DirectAccess(_) = member.as_ref().get_stmt() { let (Some(base), _) = (base, ..) else { panic!() }; - // Step 1 - let var = self.annotations.get_qualified_name(base).unwrap(); - let error_bits_lvalue = - self.llvm_index.find_loaded_associated_variable_value(var).unwrap(); + // Given `foo.bar.baz.%W1.%B1.%X3`, we want to grab the lvalue of `foo.bar.baz` + let (base, _) = collect_base_and_direct_access_for_assignment(base).unwrap(); - // Step 2 - let q_lvalue = self.llvm.builder.build_struct_gep(parameter_struct, index, "").unwrap(); + let lhs = self.generate_expression_value(base)?.get_basic_value_enum(); + let rhs = self.llvm.builder.build_struct_gep(parameter_struct, index, "").unwrap(); // TODO(volsa): Is a `impl From<...>` possible for inkwell results? - // lhs = lvalue - // rhs = astnode - self.generate_bit_access(error_bits_lvalue, q_lvalue, &assignment, &dt)?; + self.generate_bit_access(lhs.into_pointer_value(), rhs, assignment, dt)?; }; } @@ -2815,7 +2811,7 @@ fn int_value_multiply_accumulate<'ink>( } /// Returns false if any argument in the given list is an (output-)assignment and true otherwise -fn is_implicit_function_call(arguments: &Vec<&AstNode>) -> bool { +fn is_implicit_function_call(arguments: &[&AstNode]) -> bool { !arguments.iter().any(|argument| argument.is_assignment() || argument.is_output_assignment()) } diff --git a/src/codegen/tests/directaccess_test.rs b/src/codegen/tests/directaccess_test.rs index cf5fe3132f4..fd651e682b2 100644 --- a/src/codegen/tests/directaccess_test.rs +++ b/src/codegen/tests/directaccess_test.rs @@ -171,44 +171,44 @@ fn temp_output_and_normal_assignments() { %2 = and i8 %shift, 1 store i8 %2, i8* %1, align 1 call void @FOO(%FOO* %f) - %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1 - %3 = load i8, i8* %error_bits, align 1 - %erase = and i8 %3, -2 - %4 = load i8, i8* %bbb, align 1 - %value = shl i8 %4, 0 + %3 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1 + %4 = load i8, i8* %error_bits, align 1 + %erase = and i8 %4, -2 + %5 = load i8, i8* %3, align 1 + %value = shl i8 %5, 0 %or = or i8 %erase, %value store i8 %or, i8* %error_bits, align 1 - %5 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 + %6 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 %load_error_bits1 = load i8, i8* %error_bits, align 1 %shift2 = lshr i8 %load_error_bits1, 0 - %6 = and i8 %shift2, 1 - store i8 %6, i8* %5, align 1 + %7 = and i8 %shift2, 1 + store i8 %7, i8* %6, align 1 call void @FOO(%FOO* %f) - %bbb3 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1 - %7 = load i8, i8* %error_bits, align 1 - %erase4 = and i8 %7, -2 - %8 = load i8, i8* %bbb3, align 1 - %value5 = shl i8 %8, 0 - %or6 = or i8 %erase4, %value5 - store i8 %or6, i8* %error_bits, align 1 - %9 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 - %load_error_bits7 = load i8, i8* %error_bits, align 1 - %shift8 = lshr i8 %load_error_bits7, 0 - %10 = and i8 %shift8, 1 - store i8 %10, i8* %9, align 1 + %8 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1 + %9 = load i8, i8* %error_bits, align 1 + %erase3 = and i8 %9, -2 + %10 = load i8, i8* %8, align 1 + %value4 = shl i8 %10, 0 + %or5 = or i8 %erase3, %value4 + store i8 %or5, i8* %error_bits, align 1 + %11 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 + %load_error_bits6 = load i8, i8* %error_bits, align 1 + %shift7 = lshr i8 %load_error_bits6, 0 + %12 = and i8 %shift7, 1 + store i8 %12, i8* %11, align 1 call void @FOO(%FOO* %f) - %bbb9 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1 - %11 = load i8, i8* %error_bits, align 1 - %erase10 = and i8 %11, -2 - %12 = load i8, i8* %bbb9, align 1 - %value11 = shl i8 %12, 0 - %or12 = or i8 %erase10, %value11 - store i8 %or12, i8* %error_bits, align 1 - %13 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 - %load_error_bits13 = load i8, i8* %error_bits, align 1 - %shift14 = lshr i8 %load_error_bits13, 0 - %14 = and i8 %shift14, 1 - store i8 %14, i8* %13, align 1 + %13 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1 + %14 = load i8, i8* %error_bits, align 1 + %erase8 = and i8 %14, -2 + %15 = load i8, i8* %13, align 1 + %value9 = shl i8 %15, 0 + %or10 = or i8 %erase8, %value9 + store i8 %or10, i8* %error_bits, align 1 + %16 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 + %load_error_bits11 = load i8, i8* %error_bits, align 1 + %shift12 = lshr i8 %load_error_bits11, 0 + %17 = and i8 %shift12, 1 + store i8 %17, i8* %16, align 1 call void @FOO(%FOO* %f) %main_ret = load i32, i32* %main, align 4 ret i32 %main_ret @@ -223,7 +223,6 @@ fn temp_output_and_normal_assignments() { // TODO: Add correctness tests #[test] -#[ignore = "fix me later"] fn temp_complex_bit_access() { let ir = codegen( r" @@ -247,12 +246,71 @@ fn temp_complex_bit_access() { f : QUUX; END_VAR - f(Q => foo.bar.baz.%W3.%X2); + f(Q => foo.bar.baz.%W3); + f(Q => foo.bar.baz.%W3.%B0.%X2); END_FUNCTION ", ); - assert_snapshot!(ir, @r""); + assert_snapshot!(ir, @r###" + ; ModuleID = 'main' + source_filename = "main" + + %QUUX = type { i8 } + %foo_struct = type { %bar_struct } + %bar_struct = type { i64 } + + @__QUUX__init = unnamed_addr constant %QUUX zeroinitializer + @__foo_struct__init = unnamed_addr constant %foo_struct zeroinitializer + @__bar_struct__init = unnamed_addr constant %bar_struct zeroinitializer + + define void @QUUX(%QUUX* %0) section "fn-QUUX:v[u8]" { + entry: + %Q = getelementptr inbounds %QUUX, %QUUX* %0, i32 0, i32 0 + ret void + } + + define i32 @main() section "fn-main:i32" { + entry: + %main = alloca i32, align 4 + %foo = alloca %foo_struct, align 8 + %f = alloca %QUUX, align 8 + %0 = bitcast %foo_struct* %foo to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 bitcast (%foo_struct* @__foo_struct__init to i8*), i64 ptrtoint (%foo_struct* getelementptr (%foo_struct, %foo_struct* null, i32 1) to i64), i1 false) + %1 = bitcast %QUUX* %f to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %1, i8* align 1 getelementptr inbounds (%QUUX, %QUUX* @__QUUX__init, i32 0, i32 0), i64 ptrtoint (%QUUX* getelementptr (%QUUX, %QUUX* null, i32 1) to i64), i1 false) + store i32 0, i32* %main, align 4 + call void @QUUX(%QUUX* %f) + %bar = getelementptr inbounds %foo_struct, %foo_struct* %foo, i32 0, i32 0 + %baz = getelementptr inbounds %bar_struct, %bar_struct* %bar, i32 0, i32 0 + %2 = getelementptr inbounds %QUUX, %QUUX* %f, i32 0, i32 0 + %3 = load i64, i64* %baz, align 4 + %erase = and i64 %3, -281474976710657 + %4 = load i8, i8* %2, align 1 + %5 = zext i8 %4 to i64 + %value = shl i64 %5, 48 + %or = or i64 %erase, %value + store i64 %or, i64* %baz, align 4 + call void @QUUX(%QUUX* %f) + %bar1 = getelementptr inbounds %foo_struct, %foo_struct* %foo, i32 0, i32 0 + %baz2 = getelementptr inbounds %bar_struct, %bar_struct* %bar1, i32 0, i32 0 + %6 = getelementptr inbounds %QUUX, %QUUX* %f, i32 0, i32 0 + %7 = load i64, i64* %baz2, align 4 + %erase3 = and i64 %7, -1125899906842625 + %8 = load i8, i8* %6, align 1 + %9 = zext i8 %8 to i64 + %value4 = shl i64 %9, 50 + %or5 = or i64 %erase3, %value4 + store i64 %or5, i64* %baz2, align 4 + %main_ret = load i32, i32* %main, align 4 + ret i32 %main_ret + } + + ; Function Attrs: argmemonly nofree nounwind willreturn + declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0 + + attributes #0 = { argmemonly nofree nounwind willreturn } + "###); } #[test] @@ -300,11 +358,11 @@ fn temp_explicity() { call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false) store i32 0, i32* %main, align 4 call void @FOO(%FOO* %f) - %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 - %1 = load i8, i8* %error_bits, align 1 - %erase = and i8 %1, -17 - %2 = load i8, i8* %bbb, align 1 - %value = shl i8 %2, 4 + %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 + %2 = load i8, i8* %error_bits, align 1 + %erase = and i8 %2, -17 + %3 = load i8, i8* %1, align 1 + %value = shl i8 %3, 4 %or = or i8 %erase, %value store i8 %or, i8* %error_bits, align 1 %main_ret = load i32, i32* %main, align 4 @@ -363,11 +421,11 @@ fn temp_implicit() { call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false) store i32 0, i32* %main, align 4 call void @FOO(%FOO* %f) - %bbb = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 - %1 = load i8, i8* %error_bits, align 1 - %erase = and i8 %1, -17 - %2 = load i8, i8* %bbb, align 1 - %value = shl i8 %2, 4 + %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 + %2 = load i8, i8* %error_bits, align 1 + %erase = and i8 %2, -17 + %3 = load i8, i8* %1, align 1 + %value = shl i8 %3, 4 %or = or i8 %erase, %value store i8 %or, i8* %error_bits, align 1 %main_ret = load i32, i32* %main, align 4 diff --git a/tests/correctness/bitaccess.rs b/tests/correctness/bitaccess.rs index 06d6e6728fc..384f13896a1 100644 --- a/tests/correctness/bitaccess.rs +++ b/tests/correctness/bitaccess.rs @@ -1,5 +1,7 @@ // Copyright (c) 2020 Ghaith Hachem and Mathias Rieder +// TODO: Update tests, variable initialization into program body + use crate::*; use pretty_assertions::assert_eq; @@ -214,3 +216,85 @@ fn byteaccess_assignment_should_not_override_current_values() { let res: i32 = compile_and_run(prog, &mut crate::MainType::default); assert_eq!(res, 0b0000_0000_1100_0011_1010_1010_0101_0101); } + +// TODO: Add more tests, see [`directaccess_test.rs`] for inspo +#[test] +fn bitaccess_in_output_assignments_simple() { + let prog = " + FUNCTION_BLOCK foo + VAR_OUTPUT + OUT_FALSE : BOOL; + OUT_TRUE : BOOL; + END_VAR + + OUT_TRUE := TRUE; + OUT_FALSE := FALSE; + END_FUNCTION_BLOCK + + FUNCTION main : DINT + VAR + a : BYTE; + END_VAR + + VAR_TEMP + foo_instance : foo; + END_VAR + + a := 2#1010_1010; + + // Invert these ~~bitc-~~bits + foo_instance(OUT_TRUE => a.0); + foo_instance(OUT_TRUE => a.2); + foo_instance(OUT_TRUE => a.4); + foo_instance(OUT_TRUE => a.6); + + foo_instance(OUT_FALSE => a.1); + foo_instance(OUT_FALSE => a.3); + foo_instance(OUT_FALSE => a.5); + foo_instance(OUT_FALSE => a.7); + + main := a; + END_FUNCTION"; + + let res: i32 = compile_and_run(prog, &mut crate::MainType::default()); + assert_eq!(res, 0b0101_0101); +} + +#[test] +fn bitaccess_in_output_assignments_complex() { + let prog = " + TYPE foo_struct : STRUCT + bar : bar_struct; + END_STRUCT END_TYPE + + TYPE bar_struct : STRUCT + baz : DINT; // 0000_0000_0000_0000_0000_0000_0000_0000 + END_STRUCT END_TYPE + + FUNCTION_BLOCK QUUX + VAR_OUTPUT + Q : BOOL; + END_VAR + + Q := TRUE; + END_FUNCTION_BLOCK + + FUNCTION main : DINT + VAR + foo : foo_struct; + f : QUUX; + END_VAR + + foo.bar.baz := 0; // ...just to be sure + + + // foo.bar.baz: 0000_0000_0000_0000_0000_0000_0000_0000 + f(Q => foo.bar.baz.%W1.%B1.%X3); // 0000_1000_0000_0000_0000_0000_0000_0000 + f(Q => foo.bar.baz.%W1.%B1.%X1); // 0000_1010_0000_0000_0000_0000_0000_0000 + main := foo.bar.baz; + END_FUNCTION + "; + + let res: i32 = compile_and_run(prog, &mut crate::MainType::default()); + assert_eq!(res, 0b0000_1010_0000_0000_0000_0000_0000_0000); +} From 6cdf797dafba6d78aa8863e3023d2553bc4f09f4 Mon Sep 17 00:00:00 2001 From: Volkan Sagcan Date: Wed, 29 May 2024 13:45:52 +0200 Subject: [PATCH 17/22] refactor: Merge duplicate bit-access logic code --- .../generators/expression_generator.rs | 163 +++++++++++------- src/codegen/generators/statement_generator.rs | 102 ++--------- src/codegen/tests/directaccess_test.rs | 14 +- tests/correctness/bitaccess.rs | 41 +++++ 4 files changed, 164 insertions(+), 156 deletions(-) diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index 36968fb27fe..f308eb822e8 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -529,11 +529,14 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { parameters: Vec<&AstNode>, ) -> Result<(), Diagnostic> { let pou_info = self.index.get_declared_parameters(function_name); - let implicit = is_implicit_function_call(¶meters); + let implicit = arguments_are_implicit(¶meters); for (index, assignment_statement) in parameters.into_iter().enumerate() { let is_output = pou_info.get(index).is_some_and(|param| param.get_variable_type().is_output()); + // Assume we have the following ST function `fn foo(param1: Input, param2: Output, param3: Input)` + // Calls like fn(arg2_out, arg1_in, arg3_in) should not generate an output assignment for `arg1_in` + // (but really, the call is just invalid at this point?) if assignment_statement.is_output_assignment() || (implicit && is_output) { self.assign_output_value(&CallParameterAssignment { assignment: assignment_statement, @@ -559,35 +562,48 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { } } - fn generate_bit_access( + pub fn generate_assignment_with_direct_access( &self, - lvalue_lhs: PointerValue, - lvalue_rhs: PointerValue, - statement_lhs: &AstNode, - type_rhs: &DataType, + left_statement: &AstNode, + left_value: IntValue, + left_pointer: PointerValue, + right_type: &DataType, + right_expr: BasicValueEnum, // IDK? ) -> Result<(), Diagnostic> { - let Some((target, access_sequence)) = collect_base_and_direct_access_for_assignment(statement_lhs) + let Some((target, access_sequence)) = collect_base_and_direct_access_for_assignment(left_statement) else { - unreachable!("Invalid direct-access expression: {statement_lhs:#?}") + unreachable!("Invalid direct-access expression: {left_statement:#?}") }; let type_left = self.get_type_hint_for(target)?; - - //special case if we deal with a single bit, then we need to switch to a faked u1 type let type_right = if let DataTypeInformation::Integer { semantic_size: Some(typesystem::U1_SIZE), .. } = - *type_rhs.get_type_information() + *right_type.get_type_information() { + // we need to switch to a faked u1 type, when dealing with a single bit self.index.get_type_or_panic(typesystem::U1_TYPE) } else { - type_rhs + right_type }; - let value_lhs = self.llvm.builder.build_load(lvalue_lhs, "").into_int_value(); + let Some((element, direct_access)) = access_sequence.split_first() else { unreachable!("") }; - //Build index - if let Some((element, direct_access)) = access_sequence.split_first() { - let mut index = if let AstStatement::DirectAccess(data, ..) = element.get_stmt() { + // Build index + let mut index = if let AstStatement::DirectAccess(data, ..) = element.get_stmt() { + self.generate_direct_access_index( + &data.access, + &data.index, + type_right.get_type_information(), + type_left, + ) + } else { + //TODO: using the global context we could get a slice here + Err(Diagnostic::new(format!("{element:?} not a direct access")) + .with_error_code("E055") + .with_location(element.get_location())) + }?; + for element in direct_access { + let rhs_next = if let AstStatement::DirectAccess(data, ..) = element.get_stmt() { self.generate_direct_access_index( &data.access, &data.index, @@ -596,54 +612,58 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { ) } else { //TODO: using the global context we could get a slice here - Err(Diagnostic::new(format!("{element:?} not a direct access")) + Err(Diagnostic::new(&format!("{element:?} not a direct access")) .with_error_code("E055") .with_location(element.get_location())) }?; - for element in direct_access { - let rhs_next = if let AstStatement::DirectAccess(data, ..) = element.get_stmt() { - self.generate_direct_access_index( - &data.access, - &data.index, - type_right.get_type_information(), - type_left, - ) - } else { - //TODO: using the global context we could get a slice here - Err(Diagnostic::new(&format!("{element:?} not a direct access")) - .with_error_code("E055") - .with_location(element.get_location())) - }?; - index = self.llvm.builder.build_int_add(index, rhs_next, ""); - } - //Build mask for the index - //Get the target bit type as all ones - let rhs_type = self.llvm_index.get_associated_type(type_right.get_name())?.into_int_type(); - 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, value_lhs.get_type(), "ext"); - //Position the ones in their correct locations - let shifted_mask = self.llvm.builder.build_left_shift(extended_mask, index, "shift"); - //Invert the mask - let mask = self.llvm.builder.build_not(shifted_mask, "invert"); - //And the result with the mask to erase the set bits at the target location - let and_value = self.llvm.builder.build_and(value_lhs, mask, "erase"); - - //Generate an expression for the right size - let right = self.llvm.builder.build_load(lvalue_rhs, ""); - //Cast the right side to the left side type - let lhs = cast_if_needed!(self, type_left, type_right, right, None).into_int_value(); - //Shift left by the direct access - let value = self.llvm.builder.build_left_shift(lhs, index, "value"); - - //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(lvalue_lhs, or_value); - } else { - unreachable!() + index = self.llvm.builder.build_int_add(index, rhs_next, ""); } + //Build mask for the index + //Get the target bit type as all ones + let rhs_type = self.llvm_index.get_associated_type(type_right.get_name())?.into_int_type(); + 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"); + //Position the ones in their correct locations + let shifted_mask = self.llvm.builder.build_left_shift(extended_mask, index, "shift"); + //Invert the mask + let mask = self.llvm.builder.build_not(shifted_mask, "invert"); + //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"); + + //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(); + //Shift left by the direct access + let value = self.llvm.builder.build_left_shift(lhs, index, "value"); + + //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); + + Ok(()) + } + + fn generate_output_assignment_with_direct_access( + &self, + left_pointer: PointerValue, + lvalue_rhs: PointerValue, + statement_lhs: &AstNode, + type_rhs: &DataType, + ) -> Result<(), Diagnostic> { + let left_value = self.llvm.builder.build_load(left_pointer, "").into_int_value(); + + //Generate an expression for the right size + let right = self.llvm.builder.build_load(lvalue_rhs, ""); + self.generate_assignment_with_direct_access( + statement_lhs, + left_value, + left_pointer, + type_rhs, + right, + )?; + Ok(()) } @@ -665,11 +685,15 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { // FOO(x => y.0) match assignment.get_stmt() { AstStatement::ReferenceExpr(_) if assignment.has_direct_access() => { - let _pou = self.index.find_pou(function_name).unwrap(); - let _struct = &_pou.find_instance_struct_type(self.index).unwrap().information; - let DataTypeInformation::Struct { members, .. } = _struct else { panic!() }; - let param = &members[index as usize]; // TODO: Create a test for this; this fucks up if populating the members is not in order - let dt = self.index.find_effective_type_by_name(¶m.data_type_name).unwrap(); + // TODO: Can we this be simplified? + let dt = { + let pou = self.index.find_pou(function_name).unwrap(); + let pou_struct = &pou.find_instance_struct_type(self.index).unwrap().information; + let DataTypeInformation::Struct { members, .. } = pou_struct else { panic!() }; + let param = &members[index as usize]; // TODO: Create a test for this; this fucks up if populating the members is not in order + + self.index.find_effective_type_by_name(¶m.data_type_name).unwrap() + }; let AstStatement::ReferenceExpr(ReferenceExpr { access: ReferenceAccess::Member(member), @@ -687,7 +711,12 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let lhs = self.generate_expression_value(base)?.get_basic_value_enum(); let rhs = self.llvm.builder.build_struct_gep(parameter_struct, index, "").unwrap(); // TODO(volsa): Is a `impl From<...>` possible for inkwell results? - self.generate_bit_access(lhs.into_pointer_value(), rhs, assignment, dt)?; + self.generate_output_assignment_with_direct_access( + lhs.into_pointer_value(), + rhs, + assignment, + dt, + )?; }; } @@ -2811,7 +2840,7 @@ fn int_value_multiply_accumulate<'ink>( } /// Returns false if any argument in the given list is an (output-)assignment and true otherwise -fn is_implicit_function_call(arguments: &[&AstNode]) -> bool { +fn arguments_are_implicit(arguments: &[&AstNode]) -> bool { !arguments.iter().any(|argument| argument.is_assignment() || argument.is_output_assignment()) } @@ -2823,6 +2852,7 @@ fn collect_base_and_direct_access_for_assignment( ) -> Option<(&AstNode, Vec<&AstNode>)> { let mut current = Some(left_statement); let mut access_sequence = Vec::new(); + while let Some(AstStatement::ReferenceExpr(ReferenceExpr { access: ReferenceAccess::Member(m), base })) = current.map(|it| it.get_stmt()) { @@ -2833,5 +2863,6 @@ fn collect_base_and_direct_access_for_assignment( break; } } + current.zip(Some(access_sequence)) } diff --git a/src/codegen/generators/statement_generator.rs b/src/codegen/generators/statement_generator.rs index 40b36c193f5..8e98af057de 100644 --- a/src/codegen/generators/statement_generator.rs +++ b/src/codegen/generators/statement_generator.rs @@ -4,11 +4,11 @@ use super::{ llvm::Llvm, }; use crate::{ - codegen::{debug::Debug, llvm_typesystem::cast_if_needed}, + codegen::debug::Debug, codegen::{debug::DebugBuilderEnum, LlvmTypedIndex}, index::{ImplementationIndexEntry, Index}, resolver::{AnnotationMap, AstAnnotations, StatementAnnotation}, - typesystem::{self, DataTypeInformation}, + typesystem::DataTypeInformation, }; use inkwell::{ basic_block::BasicBlock, @@ -244,7 +244,7 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { self.register_debug_location(left_statement); //TODO: Looks hacky, the strings will be similar so we should look into making the assignment a bit nicer. if left_statement.has_direct_access() { - return self.generate_direct_access_assignment(left_statement, right_statement); + return self.generate_assignment_statement_direct_access(left_statement, right_statement); } //TODO: Also hacky but for now we cannot generate assignments for hardware access if matches!(left_statement.get_stmt(), AstStatement::HardwareAccess { .. }) { @@ -279,96 +279,32 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { self.debug.set_debug_location(self.llvm, &self.function_context.function, line, column); } - fn generate_direct_access_assignment( + fn generate_assignment_statement_direct_access( &self, left_statement: &AstNode, right_statement: &AstNode, ) -> Result<(), Diagnostic> { - //TODO : Validation let exp_gen = self.create_expr_generator(); - // given a complex direct-access assignemnt: a.b.c.%W3,%X1 - // we want to deconstruct the targe-part (a.b.c) and the direct-access sequence (%W3.%X1) - let Some((target, access_sequence)) = collect_base_and_direct_access_for_assignment(left_statement) - else { + // Left pointer + let Some((base, _)) = collect_base_and_direct_access_for_assignment(left_statement) else { 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_pointer = left_expr_value.get_basic_value_enum().into_pointer_value(); - let left_type = exp_gen.get_type_hint_for(target)?; + // Generate an expression for the right size let right_type = exp_gen.get_type_hint_for(right_statement)?; - - //special case if we deal with a single bit, then we need to switch to a faked u1 type - let right_type = - if let DataTypeInformation::Integer { semantic_size: Some(typesystem::U1_SIZE), .. } = - *right_type.get_type_information() - { - self.index.get_type_or_panic(typesystem::U1_TYPE) - } else { - right_type - }; - - //Left pointer - let left_expression_value = exp_gen.generate_expression_value(target)?; - let left_value = left_expression_value.as_r_value(self.llvm, None).into_int_value(); - let left = left_expression_value.get_basic_value_enum().into_pointer_value(); - //Build index - if let Some((element, direct_access)) = access_sequence.split_first() { - let mut rhs = if let AstStatement::DirectAccess(data, ..) = element.get_stmt() { - exp_gen.generate_direct_access_index( - &data.access, - &data.index, - right_type.get_type_information(), - left_type, - ) - } else { - //TODO: using the global context we could get a slice here - Err(Diagnostic::new(format!("{element:?} not a direct access")) - .with_error_code("E055") - .with_location(element.get_location())) - }?; - for element in direct_access { - let rhs_next = if let AstStatement::DirectAccess(data, ..) = element.get_stmt() { - exp_gen.generate_direct_access_index( - &data.access, - &data.index, - right_type.get_type_information(), - left_type, - ) - } else { - //TODO: using the global context we could get a slice here - Err(Diagnostic::new(&format!("{element:?} not a direct access")) - .with_error_code("E055") - .with_location(element.get_location())) - }?; - rhs = self.llvm.builder.build_int_add(rhs, rhs_next, ""); - } - //Build mask for the index - //Get the target bit type as all ones - let rhs_type = self.llvm_index.get_associated_type(right_type.get_name())?.into_int_type(); - 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"); - //Position the ones in their correct locations - let shifted_mask = self.llvm.builder.build_left_shift(extended_mask, rhs, "shift"); - //Invert the mask - let mask = self.llvm.builder.build_not(shifted_mask, "invert"); - //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"); - - //Generate an expression for the right size - let right = exp_gen.generate_expression(right_statement)?; - //Cast the right side to the left side type - let lhs = cast_if_needed!(self, left_type, right_type, right, None).into_int_value(); - //Shift left by the direct access - let value = self.llvm.builder.build_left_shift(lhs, rhs, "value"); - - //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, or_value); - } else { - unreachable!(); - } - Ok(()) + let right_expr = exp_gen.generate_expression(right_statement)?; + + exp_gen.generate_assignment_with_direct_access( + left_statement, + left_value, + left_pointer, + right_type, + right_expr, + ) } /// generates a for-loop statement diff --git a/src/codegen/tests/directaccess_test.rs b/src/codegen/tests/directaccess_test.rs index fd651e682b2..97a6a1d8344 100644 --- a/src/codegen/tests/directaccess_test.rs +++ b/src/codegen/tests/directaccess_test.rs @@ -173,8 +173,8 @@ fn temp_output_and_normal_assignments() { call void @FOO(%FOO* %f) %3 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1 %4 = load i8, i8* %error_bits, align 1 - %erase = and i8 %4, -2 %5 = load i8, i8* %3, align 1 + %erase = and i8 %4, -2 %value = shl i8 %5, 0 %or = or i8 %erase, %value store i8 %or, i8* %error_bits, align 1 @@ -186,8 +186,8 @@ fn temp_output_and_normal_assignments() { call void @FOO(%FOO* %f) %8 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1 %9 = load i8, i8* %error_bits, align 1 - %erase3 = and i8 %9, -2 %10 = load i8, i8* %8, align 1 + %erase3 = and i8 %9, -2 %value4 = shl i8 %10, 0 %or5 = or i8 %erase3, %value4 store i8 %or5, i8* %error_bits, align 1 @@ -199,8 +199,8 @@ fn temp_output_and_normal_assignments() { call void @FOO(%FOO* %f) %13 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 1 %14 = load i8, i8* %error_bits, align 1 - %erase8 = and i8 %14, -2 %15 = load i8, i8* %13, align 1 + %erase8 = and i8 %14, -2 %value9 = shl i8 %15, 0 %or10 = or i8 %erase8, %value9 store i8 %or10, i8* %error_bits, align 1 @@ -285,8 +285,8 @@ fn temp_complex_bit_access() { %baz = getelementptr inbounds %bar_struct, %bar_struct* %bar, i32 0, i32 0 %2 = getelementptr inbounds %QUUX, %QUUX* %f, i32 0, i32 0 %3 = load i64, i64* %baz, align 4 - %erase = and i64 %3, -281474976710657 %4 = load i8, i8* %2, align 1 + %erase = and i64 %3, -281474976710657 %5 = zext i8 %4 to i64 %value = shl i64 %5, 48 %or = or i64 %erase, %value @@ -296,8 +296,8 @@ fn temp_complex_bit_access() { %baz2 = getelementptr inbounds %bar_struct, %bar_struct* %bar1, i32 0, i32 0 %6 = getelementptr inbounds %QUUX, %QUUX* %f, i32 0, i32 0 %7 = load i64, i64* %baz2, align 4 - %erase3 = and i64 %7, -1125899906842625 %8 = load i8, i8* %6, align 1 + %erase3 = and i64 %7, -1125899906842625 %9 = zext i8 %8 to i64 %value4 = shl i64 %9, 50 %or5 = or i64 %erase3, %value4 @@ -360,8 +360,8 @@ fn temp_explicity() { call void @FOO(%FOO* %f) %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 %2 = load i8, i8* %error_bits, align 1 - %erase = and i8 %2, -17 %3 = load i8, i8* %1, align 1 + %erase = and i8 %2, -17 %value = shl i8 %3, 4 %or = or i8 %erase, %value store i8 %or, i8* %error_bits, align 1 @@ -423,8 +423,8 @@ fn temp_implicit() { call void @FOO(%FOO* %f) %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 %2 = load i8, i8* %error_bits, align 1 - %erase = and i8 %2, -17 %3 = load i8, i8* %1, align 1 + %erase = and i8 %2, -17 %value = shl i8 %3, 4 %or = or i8 %erase, %value store i8 %or, i8* %error_bits, align 1 diff --git a/tests/correctness/bitaccess.rs b/tests/correctness/bitaccess.rs index 384f13896a1..da92e13a7d2 100644 --- a/tests/correctness/bitaccess.rs +++ b/tests/correctness/bitaccess.rs @@ -298,3 +298,44 @@ fn bitaccess_in_output_assignments_complex() { let res: i32 = compile_and_run(prog, &mut crate::MainType::default()); assert_eq!(res, 0b0000_1010_0000_0000_0000_0000_0000_0000); } + +#[test] +fn bitaccess_in_output_assignments_complex_implicit() { + let prog = " + TYPE foo_struct : STRUCT + bar : bar_struct; + END_STRUCT END_TYPE + + TYPE bar_struct : STRUCT + baz : DINT; // 0000_0000_0000_0000_0000_0000_0000_0000 + END_STRUCT END_TYPE + + FUNCTION_BLOCK QUUX + VAR_INPUT + x : DINT; + END_VAR + VAR_OUTPUT + Q : BOOL; + END_VAR + + Q := TRUE; + END_FUNCTION_BLOCK + + FUNCTION main : DINT + VAR + foo : foo_struct; + f : QUUX; + END_VAR + + foo.bar.baz := 0; // ...just to be sure + + // foo.bar.baz: 0000_0000_0000_0000_0000_0000_0000_0000 + f(x := 0, Q => foo.bar.baz.%W1.%B1.%X3); // 0000_1000_0000_0000_0000_0000_0000_0000 + f(0, foo.bar.baz.%W1.%B1.%X1); // 0000_1010_0000_0000_0000_0000_0000_0000 + main := foo.bar.baz; + END_FUNCTION + "; + + let res: i32 = compile_and_run(prog, &mut crate::MainType::default()); + assert_eq!(res, 0b0000_1010_0000_0000_0000_0000_0000_0000); +} From e3a16860c77eca1d7dd30899e3393e195ec6bbfe Mon Sep 17 00:00:00 2001 From: Volkan Sagcan Date: Wed, 29 May 2024 13:53:24 +0200 Subject: [PATCH 18/22] Update tests --- src/codegen/tests/directaccess_test.rs | 159 ++++++++++++------------- tests/correctness/bitaccess.rs | 7 +- 2 files changed, 82 insertions(+), 84 deletions(-) diff --git a/src/codegen/tests/directaccess_test.rs b/src/codegen/tests/directaccess_test.rs index 97a6a1d8344..2bf6b031b9e 100644 --- a/src/codegen/tests/directaccess_test.rs +++ b/src/codegen/tests/directaccess_test.rs @@ -115,7 +115,7 @@ fn qualified_reference_assignment() { } #[test] -fn temp_output_and_normal_assignments() { +fn direct_acess_in_output_assignment_implicit_explicit_and_mixed() { let ir = codegen( r" FUNCTION_BLOCK FOO @@ -221,33 +221,23 @@ fn temp_output_and_normal_assignments() { "###); } -// TODO: Add correctness tests #[test] -fn temp_complex_bit_access() { +fn direct_acess_in_output_assignment_with_simple_expression() { let ir = codegen( r" - TYPE foo_struct : STRUCT - bar : bar_struct; - END_STRUCT END_TYPE - - TYPE bar_struct : STRUCT - baz : LWORD; - END_STRUCT END_TYPE - - FUNCTION_BLOCK QUUX + FUNCTION_BLOCK FOO VAR_OUTPUT - Q : BOOL; + Q : BOOL := TRUE; END_VAR END_FUNCTION_BLOCK FUNCTION main : DINT VAR - foo : foo_struct; - f : QUUX; + error_bits : BYTE := 2#1110_1111; + f : FOO; END_VAR - - f(Q => foo.bar.baz.%W3); - f(Q => foo.bar.baz.%W3.%B0.%X2); + + f(Q => error_bits.4); END_FUNCTION ", ); @@ -256,52 +246,33 @@ fn temp_complex_bit_access() { ; ModuleID = 'main' source_filename = "main" - %QUUX = type { i8 } - %foo_struct = type { %bar_struct } - %bar_struct = type { i64 } + %FOO = type { i8 } - @__QUUX__init = unnamed_addr constant %QUUX zeroinitializer - @__foo_struct__init = unnamed_addr constant %foo_struct zeroinitializer - @__bar_struct__init = unnamed_addr constant %bar_struct zeroinitializer + @__FOO__init = unnamed_addr constant %FOO { i8 1 } - define void @QUUX(%QUUX* %0) section "fn-QUUX:v[u8]" { + define void @FOO(%FOO* %0) section "fn-FOO:v[u8]" { entry: - %Q = getelementptr inbounds %QUUX, %QUUX* %0, i32 0, i32 0 + %Q = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0 ret void } define i32 @main() section "fn-main:i32" { entry: %main = alloca i32, align 4 - %foo = alloca %foo_struct, align 8 - %f = alloca %QUUX, align 8 - %0 = bitcast %foo_struct* %foo to i8* - call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 bitcast (%foo_struct* @__foo_struct__init to i8*), i64 ptrtoint (%foo_struct* getelementptr (%foo_struct, %foo_struct* null, i32 1) to i64), i1 false) - %1 = bitcast %QUUX* %f to i8* - call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %1, i8* align 1 getelementptr inbounds (%QUUX, %QUUX* @__QUUX__init, i32 0, i32 0), i64 ptrtoint (%QUUX* getelementptr (%QUUX, %QUUX* null, i32 1) to i64), i1 false) + %error_bits = alloca i8, align 1 + %f = alloca %FOO, align 8 + store i8 -17, i8* %error_bits, align 1 + %0 = bitcast %FOO* %f to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false) store i32 0, i32* %main, align 4 - call void @QUUX(%QUUX* %f) - %bar = getelementptr inbounds %foo_struct, %foo_struct* %foo, i32 0, i32 0 - %baz = getelementptr inbounds %bar_struct, %bar_struct* %bar, i32 0, i32 0 - %2 = getelementptr inbounds %QUUX, %QUUX* %f, i32 0, i32 0 - %3 = load i64, i64* %baz, align 4 - %4 = load i8, i8* %2, align 1 - %erase = and i64 %3, -281474976710657 - %5 = zext i8 %4 to i64 - %value = shl i64 %5, 48 - %or = or i64 %erase, %value - store i64 %or, i64* %baz, align 4 - call void @QUUX(%QUUX* %f) - %bar1 = getelementptr inbounds %foo_struct, %foo_struct* %foo, i32 0, i32 0 - %baz2 = getelementptr inbounds %bar_struct, %bar_struct* %bar1, i32 0, i32 0 - %6 = getelementptr inbounds %QUUX, %QUUX* %f, i32 0, i32 0 - %7 = load i64, i64* %baz2, align 4 - %8 = load i8, i8* %6, align 1 - %erase3 = and i64 %7, -1125899906842625 - %9 = zext i8 %8 to i64 - %value4 = shl i64 %9, 50 - %or5 = or i64 %erase3, %value4 - store i64 %or5, i64* %baz2, align 4 + call void @FOO(%FOO* %f) + %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 + %2 = load i8, i8* %error_bits, align 1 + %3 = load i8, i8* %1, align 1 + %erase = and i8 %2, -17 + %value = shl i8 %3, 4 + %or = or i8 %erase, %value + store i8 %or, i8* %error_bits, align 1 %main_ret = load i32, i32* %main, align 4 ret i32 %main_ret } @@ -314,7 +285,7 @@ fn temp_complex_bit_access() { } #[test] -fn temp_explicity() { +fn direct_acess_in_output_assignment_with_simple_expression_implicit() { let ir = codegen( r" FUNCTION_BLOCK FOO @@ -329,7 +300,7 @@ fn temp_explicity() { f : FOO; END_VAR - f(Q => error_bits.4); + f(error_bits.4); END_FUNCTION ", ); @@ -377,22 +348,31 @@ fn temp_explicity() { } #[test] -fn temp_implicit() { +fn direct_acess_in_output_assignment_with_complexe_expression() { let ir = codegen( r" - FUNCTION_BLOCK FOO + TYPE foo_struct : STRUCT + bar : bar_struct; + END_STRUCT END_TYPE + + TYPE bar_struct : STRUCT + baz : LWORD; + END_STRUCT END_TYPE + + FUNCTION_BLOCK QUUX VAR_OUTPUT - Q : BOOL := TRUE; + Q : BOOL; END_VAR END_FUNCTION_BLOCK FUNCTION main : DINT VAR - error_bits : BYTE := 2#1110_1111; - f : FOO; + foo : foo_struct; + f : QUUX; END_VAR - - f(error_bits.4); + + f(Q => foo.bar.baz.%W3); + f(Q => foo.bar.baz.%W3.%B0.%X2); END_FUNCTION ", ); @@ -401,33 +381,52 @@ fn temp_implicit() { ; ModuleID = 'main' source_filename = "main" - %FOO = type { i8 } + %QUUX = type { i8 } + %foo_struct = type { %bar_struct } + %bar_struct = type { i64 } - @__FOO__init = unnamed_addr constant %FOO { i8 1 } + @__QUUX__init = unnamed_addr constant %QUUX zeroinitializer + @__foo_struct__init = unnamed_addr constant %foo_struct zeroinitializer + @__bar_struct__init = unnamed_addr constant %bar_struct zeroinitializer - define void @FOO(%FOO* %0) section "fn-FOO:v[u8]" { + define void @QUUX(%QUUX* %0) section "fn-QUUX:v[u8]" { entry: - %Q = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0 + %Q = getelementptr inbounds %QUUX, %QUUX* %0, i32 0, i32 0 ret void } define i32 @main() section "fn-main:i32" { entry: %main = alloca i32, align 4 - %error_bits = alloca i8, align 1 - %f = alloca %FOO, align 8 - store i8 -17, i8* %error_bits, align 1 - %0 = bitcast %FOO* %f to i8* - call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%FOO, %FOO* @__FOO__init, i32 0, i32 0), i64 ptrtoint (%FOO* getelementptr (%FOO, %FOO* null, i32 1) to i64), i1 false) + %foo = alloca %foo_struct, align 8 + %f = alloca %QUUX, align 8 + %0 = bitcast %foo_struct* %foo to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 bitcast (%foo_struct* @__foo_struct__init to i8*), i64 ptrtoint (%foo_struct* getelementptr (%foo_struct, %foo_struct* null, i32 1) to i64), i1 false) + %1 = bitcast %QUUX* %f to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %1, i8* align 1 getelementptr inbounds (%QUUX, %QUUX* @__QUUX__init, i32 0, i32 0), i64 ptrtoint (%QUUX* getelementptr (%QUUX, %QUUX* null, i32 1) to i64), i1 false) store i32 0, i32* %main, align 4 - call void @FOO(%FOO* %f) - %1 = getelementptr inbounds %FOO, %FOO* %f, i32 0, i32 0 - %2 = load i8, i8* %error_bits, align 1 - %3 = load i8, i8* %1, align 1 - %erase = and i8 %2, -17 - %value = shl i8 %3, 4 - %or = or i8 %erase, %value - store i8 %or, i8* %error_bits, align 1 + call void @QUUX(%QUUX* %f) + %bar = getelementptr inbounds %foo_struct, %foo_struct* %foo, i32 0, i32 0 + %baz = getelementptr inbounds %bar_struct, %bar_struct* %bar, i32 0, i32 0 + %2 = getelementptr inbounds %QUUX, %QUUX* %f, i32 0, i32 0 + %3 = load i64, i64* %baz, align 4 + %4 = load i8, i8* %2, align 1 + %erase = and i64 %3, -281474976710657 + %5 = zext i8 %4 to i64 + %value = shl i64 %5, 48 + %or = or i64 %erase, %value + store i64 %or, i64* %baz, align 4 + call void @QUUX(%QUUX* %f) + %bar1 = getelementptr inbounds %foo_struct, %foo_struct* %foo, i32 0, i32 0 + %baz2 = getelementptr inbounds %bar_struct, %bar_struct* %bar1, i32 0, i32 0 + %6 = getelementptr inbounds %QUUX, %QUUX* %f, i32 0, i32 0 + %7 = load i64, i64* %baz2, align 4 + %8 = load i8, i8* %6, align 1 + %erase3 = and i64 %7, -1125899906842625 + %9 = zext i8 %8 to i64 + %value4 = shl i64 %9, 50 + %or5 = or i64 %erase3, %value4 + store i64 %or5, i64* %baz2, align 4 %main_ret = load i32, i32* %main, align 4 ret i32 %main_ret } diff --git a/tests/correctness/bitaccess.rs b/tests/correctness/bitaccess.rs index da92e13a7d2..faf18bd2f0c 100644 --- a/tests/correctness/bitaccess.rs +++ b/tests/correctness/bitaccess.rs @@ -217,9 +217,8 @@ fn byteaccess_assignment_should_not_override_current_values() { assert_eq!(res, 0b0000_0000_1100_0011_1010_1010_0101_0101); } -// TODO: Add more tests, see [`directaccess_test.rs`] for inspo #[test] -fn bitaccess_in_output_assignments_simple() { +fn bitaccess_in_output_assignments_with_simple_expression() { let prog = " FUNCTION_BLOCK foo VAR_OUTPUT @@ -261,7 +260,7 @@ fn bitaccess_in_output_assignments_simple() { } #[test] -fn bitaccess_in_output_assignments_complex() { +fn bitaccess_in_output_assignment_with_complexish_expression() { let prog = " TYPE foo_struct : STRUCT bar : bar_struct; @@ -300,7 +299,7 @@ fn bitaccess_in_output_assignments_complex() { } #[test] -fn bitaccess_in_output_assignments_complex_implicit() { +fn bitaccess_in_output_assignment_with_complexish_expression_implicit() { let prog = " TYPE foo_struct : STRUCT bar : bar_struct; From e8094306a74b7f75e315e2d0deb686f806701072 Mon Sep 17 00:00:00 2001 From: Volkan Sagcan Date: Wed, 29 May 2024 14:26:48 +0200 Subject: [PATCH 19/22] cleanup --- .../generators/expression_generator.rs | 68 ++++++++----------- src/codegen/generators/statement_generator.rs | 5 +- tests/correctness/bitaccess.rs | 4 +- 3 files changed, 34 insertions(+), 43 deletions(-) diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index f308eb822e8..e466621d9b6 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -534,9 +534,6 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { for (index, assignment_statement) in parameters.into_iter().enumerate() { let is_output = pou_info.get(index).is_some_and(|param| param.get_variable_type().is_output()); - // Assume we have the following ST function `fn foo(param1: Input, param2: Output, param3: Input)` - // Calls like fn(arg2_out, arg1_in, arg3_in) should not generate an output assignment for `arg1_in` - // (but really, the call is just invalid at this point?) if assignment_statement.is_output_assignment() || (implicit && is_output) { self.assign_output_value(&CallParameterAssignment { assignment: assignment_statement, @@ -568,7 +565,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { left_value: IntValue, left_pointer: PointerValue, right_type: &DataType, - right_expr: BasicValueEnum, // IDK? + right_expr: BasicValueEnum, ) -> Result<(), Diagnostic> { let Some((target, access_sequence)) = collect_base_and_direct_access_for_assignment(left_statement) else { @@ -597,7 +594,8 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { type_left, ) } else { - //TODO: using the global context we could get a slice here + // TODO: using the global context we could get a slice here; currently not possible because the + // global context isn't passed into codegen Err(Diagnostic::new(format!("{element:?} not a direct access")) .with_error_code("E055") .with_location(element.get_location())) @@ -611,7 +609,8 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { type_left, ) } else { - //TODO: using the global context we could get a slice here + // TODO: using the global context we could get a slice here; currently not possible because the + // global context isn't passed into codegen Err(Diagnostic::new(&format!("{element:?} not a direct access")) .with_error_code("E055") .with_location(element.get_location())) @@ -647,20 +646,20 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { fn generate_output_assignment_with_direct_access( &self, + left_statement: &AstNode, left_pointer: PointerValue, - lvalue_rhs: PointerValue, - statement_lhs: &AstNode, - type_rhs: &DataType, + right_pointer: PointerValue, + right_type: &DataType, ) -> Result<(), Diagnostic> { let left_value = self.llvm.builder.build_load(left_pointer, "").into_int_value(); //Generate an expression for the right size - let right = self.llvm.builder.build_load(lvalue_rhs, ""); + let right = self.llvm.builder.build_load(right_pointer, ""); self.generate_assignment_with_direct_access( - statement_lhs, + left_statement, left_value, left_pointer, - type_rhs, + right_type, right, )?; @@ -668,63 +667,56 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { } fn generate_output_assignment(&self, context: &CallParameterAssignment) -> Result<(), Diagnostic> { - let &CallParameterAssignment { assignment, function_name, index, parameter_struct } = context; + let &CallParameterAssignment { assignment: expr, function_name, index, parameter_struct } = context; let builder = &self.llvm.builder; - let Some(parameter) = self.index.get_declared_parameter(function_name, index) else { - panic!("or return?"); - }; - assert!(parameter.get_variable_type().is_output()); - - // Don't generate code if right-hand side of an assignment is an empty statement (e.g. `foo(out => )`) - if assignment.is_empty_statement() { + // We don't want to generate any code if the right side of an assignment is empty, e.g. `foo(out =>)` + if expr.is_empty_statement() { return Ok(()); } - // FOO(x => y) - // FOO(x => y.0) - match assignment.get_stmt() { - AstStatement::ReferenceExpr(_) if assignment.has_direct_access() => { + let parameter = self.index.get_declared_parameter(function_name, index).expect("must exist"); + + match expr.get_stmt() { + AstStatement::ReferenceExpr(_) if expr.has_direct_access() => { // TODO: Can we this be simplified? - let dt = { + let rhs_type = { let pou = self.index.find_pou(function_name).unwrap(); let pou_struct = &pou.find_instance_struct_type(self.index).unwrap().information; let DataTypeInformation::Struct { members, .. } = pou_struct else { panic!() }; - let param = &members[index as usize]; // TODO: Create a test for this; this fucks up if populating the members is not in order - self.index.find_effective_type_by_name(¶m.data_type_name).unwrap() + self.index.find_effective_type_by_name(&members[index as usize].data_type_name).unwrap() }; let AstStatement::ReferenceExpr(ReferenceExpr { access: ReferenceAccess::Member(member), base, - }) = &assignment.get_stmt() + }) = &expr.get_stmt() else { unreachable!("must be a bitaccess, will return early for all other cases") }; if let AstStatement::DirectAccess(_) = member.as_ref().get_stmt() { + // Given `foo.bar.baz.%W1.%B1.%X3`, we want to grab the base i.e. `foo.bar.baz` let (Some(base), _) = (base, ..) else { panic!() }; - // Given `foo.bar.baz.%W1.%B1.%X3`, we want to grab the lvalue of `foo.bar.baz` let (base, _) = collect_base_and_direct_access_for_assignment(base).unwrap(); let lhs = self.generate_expression_value(base)?.get_basic_value_enum(); - let rhs = self.llvm.builder.build_struct_gep(parameter_struct, index, "").unwrap(); // TODO(volsa): Is a `impl From<...>` possible for inkwell results? + let rhs = self.llvm.builder.build_struct_gep(parameter_struct, index, "").unwrap(); self.generate_output_assignment_with_direct_access( + expr, lhs.into_pointer_value(), rhs, - assignment, - dt, + rhs_type, )?; }; } _ => { - let assigned_output = self.generate_lvalue(assignment)?; - + let assigned_output = self.generate_lvalue(expr)?; let assigned_output_type = - self.annotations.get_type_or_void(assignment, self.index).get_type_information(); + self.annotations.get_type_or_void(expr, self.index).get_type_information(); let output = builder.build_struct_gep(parameter_struct, index, "").map_err(|_| { Diagnostic::codegen_error( @@ -735,7 +727,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { let output_value_type = self.index.get_type_information_or_void(parameter.get_type_name()); - //Special string handling + // Special string handling if (assigned_output_type.is_string() && output_value_type.is_string()) || (assigned_output_type.is_struct() && output_value_type.is_struct()) || (assigned_output_type.is_array() && output_value_type.is_array()) @@ -743,7 +735,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { self.generate_string_store( assigned_output, assigned_output_type, - assignment.get_location(), + expr.get_location(), output, output_value_type, parameter.source_location.clone(), @@ -758,8 +750,6 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { Ok(()) } - /// Given an output assignment such as `foo => bar`, the right-hand side of the assignment (i.e. `bar`) - /// will be extracted and fed into [`generate_output_assignment`] in a subsequent call. fn generate_explicit_output_assignment( &self, parameter_struct: PointerValue<'ink>, diff --git a/src/codegen/generators/statement_generator.rs b/src/codegen/generators/statement_generator.rs index 8e98af057de..30d125f57f6 100644 --- a/src/codegen/generators/statement_generator.rs +++ b/src/codegen/generators/statement_generator.rs @@ -778,9 +778,8 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { } } -/// when generating an assignment to a direct-access (e.g. a.b.c.%W3.%X2 := 2;) -/// we want to deconstruct the sequence into the base-statement (a.b.c) and the sequence -/// of direct-access commands (vec![%W3, %X2]) +/// Deconstructs assignments such as `a.b.c.%W3.%X2 := 2` into a base statement and its direct-access sequences. +/// For the given example this function would return `(Node(a.b.c), vec![Node(%W3), Node(%X2)])` fn collect_base_and_direct_access_for_assignment( left_statement: &AstNode, ) -> Option<(&AstNode, Vec<&AstNode>)> { diff --git a/tests/correctness/bitaccess.rs b/tests/correctness/bitaccess.rs index faf18bd2f0c..a412bf4f6a9 100644 --- a/tests/correctness/bitaccess.rs +++ b/tests/correctness/bitaccess.rs @@ -1,6 +1,8 @@ // Copyright (c) 2020 Ghaith Hachem and Mathias Rieder -// TODO: Update tests, variable initialization into program body +// TODO: Some of these tests are incorrect, because a `default()` call will override the values defined in the +// VAR block. Thus any tests relying on data initialized in the VAR block needs to be updated such that +// the initialization happens in the POU body. However, this won't be any issue once we convert to LIT. use crate::*; use pretty_assertions::assert_eq; From b3d51d2688cc853f71c928037ff71d9d629e0e20 Mon Sep 17 00:00:00 2001 From: Volkan Sagcan Date: Wed, 5 Jun 2024 11:07:21 +0200 Subject: [PATCH 20/22] format --- src/codegen/generators/expression_generator.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index e466621d9b6..08f0382aff2 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -421,15 +421,16 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { // find the pou we're calling let pou = self.annotations.get_call_name(operator).zip(self.annotations.get_qualified_name(operator)) .and_then(|(call_name, qualified_name)| self.index.find_pou(call_name) - // for some functions (builtins) the call name does not exist in the index, we try to call with the originally defined generic functions - .or_else(|| self.index.find_pou(qualified_name))) + // for some functions (builtins) the call name does not exist in the index, we try to call with the originally defined generic functions + .or_else(|| self.index.find_pou(qualified_name))) .or_else(|| // some rare situations have a callstatement that's not properly annotated (e.g. checkRange-call of ranged datatypes) if let Some(name) = operator.get_flat_reference_name() { self.index.find_pou(name) } else { None - }) + } + ) .ok_or_else(|| Diagnostic::cannot_generate_call_statement(operator))?; // find corresponding implementation From ffd2179885e2f17a3a2adda01e26e661cad67fc4 Mon Sep 17 00:00:00 2001 From: Volkan Sagcan Date: Fri, 7 Jun 2024 11:58:43 +0200 Subject: [PATCH 21/22] feedback --- src/codegen/generators/expression_generator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index 6900c74aa11..054e78f596d 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -680,11 +680,10 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { match expr.get_stmt() { AstStatement::ReferenceExpr(_) if expr.has_direct_access() => { - // TODO: Can we this be simplified? let rhs_type = { let pou = self.index.find_pou(function_name).unwrap(); let pou_struct = &pou.find_instance_struct_type(self.index).unwrap().information; - let DataTypeInformation::Struct { members, .. } = pou_struct else { panic!() }; + let DataTypeInformation::Struct { members, .. } = pou_struct else { unreachable!() }; self.index.find_effective_type_by_name(&members[index as usize].data_type_name).unwrap() }; @@ -2807,6 +2806,7 @@ fn int_value_multiply_accumulate<'ink>( llvm.builder.build_load(accum, "accessor").into_int_value() } +// XXX: Could be problematic with https://github.com/PLC-lang/rusty/issues/668 /// Returns false if any argument in the given list is an (output-)assignment and true otherwise fn arguments_are_implicit(arguments: &[&AstNode]) -> bool { !arguments.iter().any(|argument| argument.is_assignment() || argument.is_output_assignment()) From f00ec7334e71540e08889d8da47fcb7ccb48facc Mon Sep 17 00:00:00 2001 From: Volkan Sagcan Date: Wed, 19 Jun 2024 15:10:39 +0200 Subject: [PATCH 22/22] Update snapshots --- src/codegen/tests/directaccess_test.rs | 28 +++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/codegen/tests/directaccess_test.rs b/src/codegen/tests/directaccess_test.rs index 2bf6b031b9e..26e2604ff32 100644 --- a/src/codegen/tests/directaccess_test.rs +++ b/src/codegen/tests/directaccess_test.rs @@ -147,16 +147,16 @@ fn direct_acess_in_output_assignment_implicit_explicit_and_mixed() { %FOO = type { i8, i8 } - @__FOO__init = unnamed_addr constant %FOO zeroinitializer + @__FOO__init = unnamed_addr constant %FOO zeroinitializer, section "var-$RUSTY$__FOO__init:r2u8u8" - define void @FOO(%FOO* %0) section "fn-FOO:v[u8][u8]" { + define void @FOO(%FOO* %0) section "fn-$RUSTY$FOO:v[u8][u8]" { entry: %X = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0 %Y = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 1 ret void } - define i32 @main() section "fn-main:i32" { + define i32 @main() section "fn-$RUSTY$main:i32" { entry: %main = alloca i32, align 4 %error_bits = alloca i8, align 1 @@ -248,15 +248,15 @@ fn direct_acess_in_output_assignment_with_simple_expression() { %FOO = type { i8 } - @__FOO__init = unnamed_addr constant %FOO { i8 1 } + @__FOO__init = unnamed_addr constant %FOO { i8 1 }, section "var-$RUSTY$__FOO__init:r1u8" - define void @FOO(%FOO* %0) section "fn-FOO:v[u8]" { + define void @FOO(%FOO* %0) section "fn-$RUSTY$FOO:v[u8]" { entry: %Q = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0 ret void } - define i32 @main() section "fn-main:i32" { + define i32 @main() section "fn-$RUSTY$main:i32" { entry: %main = alloca i32, align 4 %error_bits = alloca i8, align 1 @@ -311,15 +311,15 @@ fn direct_acess_in_output_assignment_with_simple_expression_implicit() { %FOO = type { i8 } - @__FOO__init = unnamed_addr constant %FOO { i8 1 } + @__FOO__init = unnamed_addr constant %FOO { i8 1 }, section "var-$RUSTY$__FOO__init:r1u8" - define void @FOO(%FOO* %0) section "fn-FOO:v[u8]" { + define void @FOO(%FOO* %0) section "fn-$RUSTY$FOO:v[u8]" { entry: %Q = getelementptr inbounds %FOO, %FOO* %0, i32 0, i32 0 ret void } - define i32 @main() section "fn-main:i32" { + define i32 @main() section "fn-$RUSTY$main:i32" { entry: %main = alloca i32, align 4 %error_bits = alloca i8, align 1 @@ -385,17 +385,17 @@ fn direct_acess_in_output_assignment_with_complexe_expression() { %foo_struct = type { %bar_struct } %bar_struct = type { i64 } - @__QUUX__init = unnamed_addr constant %QUUX zeroinitializer - @__foo_struct__init = unnamed_addr constant %foo_struct zeroinitializer - @__bar_struct__init = unnamed_addr constant %bar_struct zeroinitializer + @__QUUX__init = unnamed_addr constant %QUUX zeroinitializer, section "var-$RUSTY$__QUUX__init:r1u8" + @__foo_struct__init = unnamed_addr constant %foo_struct zeroinitializer, section "var-$RUSTY$__foo_struct__init:r1r1u64" + @__bar_struct__init = unnamed_addr constant %bar_struct zeroinitializer, section "var-$RUSTY$__bar_struct__init:r1u64" - define void @QUUX(%QUUX* %0) section "fn-QUUX:v[u8]" { + define void @QUUX(%QUUX* %0) section "fn-$RUSTY$QUUX:v[u8]" { entry: %Q = getelementptr inbounds %QUUX, %QUUX* %0, i32 0, i32 0 ret void } - define i32 @main() section "fn-main:i32" { + define i32 @main() section "fn-$RUSTY$main:i32" { entry: %main = alloca i32, align 4 %foo = alloca %foo_struct, align 8