@@ -74,6 +74,8 @@ struct CallParameterAssignment<'a, 'b> {
7474 function_name : & ' b str ,
7575 /// the position of the argument in the POU's argument's list
7676 index : u32 ,
77+ depth : u32 ,
78+ arg_pou : & ' b str ,
7779 /// a pointer to the struct instance that carries the call's arguments
7880 parameter_struct : PointerValue < ' a > ,
7981}
@@ -702,14 +704,18 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
702704 let is_output = pou_info. get ( index) . is_some_and ( |param| param. get_variable_type ( ) . is_output ( ) ) ;
703705
704706 if assignment_statement. is_output_assignment ( ) || ( implicit && is_output) {
707+ let Some ( StatementAnnotation :: Argument { position, depth, pou, .. } ) =
708+ self . annotations . get_hint ( assignment_statement)
709+ else {
710+ panic ! ( )
711+ } ;
712+
705713 self . assign_output_value ( & CallParameterAssignment {
706714 assignment : assignment_statement,
707715 function_name,
708- index : self
709- . annotations
710- . get_hint ( assignment_statement)
711- . and_then ( StatementAnnotation :: get_location_in_parent)
712- . expect ( "arguments must have a type hint" ) ,
716+ index : * position as u32 ,
717+ depth : * depth as u32 ,
718+ arg_pou : pou,
713719 parameter_struct,
714720 } ) ?
715721 }
@@ -720,11 +726,9 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
720726
721727 fn assign_output_value ( & self , param_context : & CallParameterAssignment ) -> Result < ( ) , CodegenError > {
722728 match & param_context. assignment . stmt {
723- AstStatement :: OutputAssignment ( assignment) => self . generate_explicit_output_assignment (
724- param_context. parameter_struct ,
725- param_context. function_name ,
726- assignment,
727- ) ,
729+ AstStatement :: OutputAssignment ( assignment) => {
730+ self . generate_explicit_output_assignment ( param_context, assignment)
731+ }
728732
729733 _ => self . generate_output_assignment ( param_context) ,
730734 }
@@ -840,15 +844,23 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
840844 }
841845
842846 fn generate_output_assignment ( & self , context : & CallParameterAssignment ) -> Result < ( ) , CodegenError > {
843- let & CallParameterAssignment { assignment : expr, function_name, index, parameter_struct } = context;
847+ let & CallParameterAssignment {
848+ assignment : expr,
849+ function_name,
850+ index,
851+ depth : _,
852+ arg_pou,
853+ parameter_struct,
854+ } = context;
855+
844856 let builder = & self . llvm . builder ;
845857
846858 // We don't want to generate any code if the right side of an assignment is empty, e.g. `foo(out =>)`
847859 if expr. is_empty_statement ( ) {
848860 return Ok ( ( ) ) ;
849861 }
850862
851- let parameter = self . index . get_declared_parameter ( function_name , index) . expect ( "must exist" ) ;
863+ let parameter = self . index . get_declared_parameter ( arg_pou , index) . expect ( "must exist" ) ;
852864
853865 match expr. get_stmt ( ) {
854866 AstStatement :: ReferenceExpr ( _) if expr. has_direct_access ( ) => {
@@ -889,12 +901,18 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
889901 let assigned_output = self . generate_lvalue ( expr) ?;
890902 let assigned_output_type =
891903 self . annotations . get_type_or_void ( expr, self . index ) . get_type_information ( ) ;
892- let output = builder. build_struct_gep ( parameter_struct, index, "" ) . map_err ( |_| {
893- Diagnostic :: codegen_error (
894- format ! ( "Cannot build generate parameter: {parameter:#?}" ) ,
895- & parameter. source_location ,
896- )
897- } ) ?;
904+ let output = unsafe {
905+ let mut gep_index = vec ! [ 0 ; ( context. depth + 1 ) as usize ] ;
906+ gep_index. push ( context. index ) ;
907+
908+ let i32_type = self . llvm . context . i32_type ( ) ;
909+ let gep_index = gep_index
910+ . into_iter ( )
911+ . map ( |value| i32_type. const_int ( value as u64 , false ) )
912+ . collect :: < Vec < _ > > ( ) ;
913+
914+ builder. build_gep ( parameter_struct, & gep_index, "" ) . unwrap ( )
915+ } ;
898916
899917 let output_value_type = self . index . get_type_information_or_void ( parameter. get_type_name ( ) ) ;
900918
@@ -919,24 +937,21 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
919937
920938 fn generate_explicit_output_assignment (
921939 & self ,
922- parameter_struct : PointerValue < ' ink > ,
923- function_name : & str ,
940+ param_context : & CallParameterAssignment ,
924941 assignment : & Assignment ,
925942 ) -> Result < ( ) , CodegenError > {
943+ let parameter_struct = param_context. parameter_struct ;
944+ let function_name = param_context. function_name ;
926945 let Assignment { left, right } = assignment;
927946
928- if let Some ( StatementAnnotation :: Variable { qualified_name, .. } ) = self . annotations . get ( left) {
929- let parameter = self
930- . index
931- . find_fully_qualified_variable ( qualified_name)
932- . ok_or_else ( || Diagnostic :: unresolved_reference ( qualified_name, left. as_ref ( ) ) ) ?;
933- let index = parameter. get_location_in_parent ( ) ;
934-
947+ if let Some ( StatementAnnotation :: Variable { .. } ) = self . annotations . get ( left) {
935948 self . generate_output_assignment ( & CallParameterAssignment {
936949 assignment : right,
937950 function_name,
938- index,
951+ index : param_context. index ,
952+ depth : param_context. depth ,
939953 parameter_struct,
954+ arg_pou : param_context. arg_pou ,
940955 } ) ?
941956 } ;
942957
@@ -1280,14 +1295,18 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
12801295 } )
12811296 . unwrap_or_else ( || vec ! [ parameter_struct. as_basic_value_enum( ) . into( ) ] ) ;
12821297 for argument in arguments. iter ( ) {
1298+ let Some ( StatementAnnotation :: Argument { position, depth, pou, .. } ) =
1299+ self . annotations . get_hint ( argument)
1300+ else {
1301+ panic ! ( )
1302+ } ;
1303+
12831304 let parameter = self . generate_call_struct_argument_assignment ( & CallParameterAssignment {
12841305 assignment : argument,
12851306 function_name : pou_name,
1286- index : self
1287- . annotations
1288- . get_hint ( argument)
1289- . and_then ( StatementAnnotation :: get_location_in_parent)
1290- . expect ( "arguments must have a type hint" ) ,
1307+ index : * position as u32 ,
1308+ depth : * depth as u32 ,
1309+ arg_pou : pou,
12911310 parameter_struct,
12921311 } ) ?;
12931312 if let Some ( parameter) = parameter {
@@ -1378,28 +1397,35 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
13781397 param_context : & CallParameterAssignment ,
13791398 ) -> Result < Option < BasicValueEnum < ' ink > > , CodegenError > {
13801399 let builder = & self . llvm . builder ;
1381- let function_name = param_context. function_name ;
1400+ // let function_name = param_context.function_name;
13821401 let index = param_context. index ;
13831402 let parameter_struct = param_context. parameter_struct ;
13841403 let expression = param_context. assignment ;
1385- if let Some ( parameter) = self . index . get_declared_parameter ( function_name, index) {
1404+
1405+ if let Some ( parameter) = self . index . get_declared_parameter ( param_context. arg_pou , index) {
13861406 // this happens before the pou call
13871407 // before the call statement we may only consider inputs and inouts
13881408 // after the call we need to copy the output values to the correct assigned variables
13891409 if matches ! ( parameter. get_variable_type( ) , VariableType :: Output ) {
13901410 return Ok ( None ) ;
13911411 }
13921412
1393- let pointer_to_param = builder. build_struct_gep ( parameter_struct, index, "" ) . map_err ( |_| {
1394- Diagnostic :: codegen_error (
1395- format ! ( "Cannot build generate parameter: {expression:#?}" ) ,
1396- expression,
1397- )
1398- } ) ?;
1413+ let pointer_to_param = unsafe {
1414+ let mut gep_index = vec ! [ 0 ; ( param_context. depth + 1 ) as usize ] ;
1415+ gep_index. push ( param_context. index ) ;
1416+
1417+ let i32_type = self . llvm . context . i32_type ( ) ;
1418+ let gep_index = gep_index
1419+ . into_iter ( )
1420+ . map ( |value| i32_type. const_int ( value as u64 , false ) )
1421+ . collect :: < Vec < _ > > ( ) ;
1422+
1423+ builder. build_gep ( parameter_struct, & gep_index, "" ) . unwrap ( )
1424+ } ;
13991425
14001426 let parameter = self
14011427 . index
1402- . find_parameter ( function_name , index)
1428+ . find_parameter ( param_context . arg_pou , index)
14031429 . and_then ( |var| self . index . find_effective_type_by_name ( var. get_type_name ( ) ) )
14041430 . map ( |var| var. get_type_information ( ) )
14051431 . unwrap_or_else ( || self . index . get_void_type ( ) . get_type_information ( ) ) ;
@@ -1444,21 +1470,23 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
14441470 . index
14451471 . find_fully_qualified_variable ( qualified_name)
14461472 . ok_or_else ( || Diagnostic :: unresolved_reference ( qualified_name, left) ) ?;
1447- let index = parameter. get_location_in_parent ( ) ;
14481473
14491474 // don't generate param assignments for empty statements, with the exception
14501475 // of VAR_IN_OUT params - they need an address to point to
14511476 let is_auto_deref = self
14521477 . index
14531478 . find_effective_type_by_name ( parameter. get_type_name ( ) )
1454- . map ( |var| var . get_type_information ( ) )
1455- . unwrap_or ( self . index . get_void_type ( ) . get_type_information ( ) )
1479+ . map ( DataType :: get_type_information)
1480+ . unwrap_or_else ( || self . index . get_void_type ( ) . get_type_information ( ) )
14561481 . is_auto_deref ( ) ;
1482+
14571483 if !right. is_empty_statement ( ) || is_auto_deref {
14581484 self . generate_call_struct_argument_assignment ( & CallParameterAssignment {
14591485 assignment : right,
14601486 function_name,
1461- index,
1487+ index : param_context. index ,
1488+ depth : param_context. depth ,
1489+ arg_pou : param_context. arg_pou ,
14621490 parameter_struct,
14631491 } ) ?;
14641492 } ;
0 commit comments