@@ -15,7 +15,7 @@ use crate::{
15
15
} ,
16
16
index:: { self , ImplementationType } ,
17
17
resolver:: { AstAnnotations , Dependency } ,
18
- typesystem:: { self , DataType , VarArgs } ,
18
+ typesystem:: { DataType , DataTypeInformation , VarArgs , DINT_TYPE } ,
19
19
} ;
20
20
use std:: collections:: HashMap ;
21
21
@@ -24,9 +24,10 @@ use std::collections::HashMap;
24
24
/// - generates a struct-datatype for the POU's members
25
25
/// - generates a function for the pou
26
26
/// - declares a global instance if the POU is a PROGRAM
27
- use crate :: index:: { ImplementationIndexEntry , VariableIndexEntry } ;
27
+ use crate :: index:: { ArgumentType , ImplementationIndexEntry , VariableIndexEntry } ;
28
28
29
29
use crate :: index:: Index ;
30
+ use index:: VariableType ;
30
31
use indexmap:: { IndexMap , IndexSet } ;
31
32
use inkwell:: {
32
33
module:: Module ,
@@ -190,32 +191,59 @@ impl<'ink, 'cg> PouGenerator<'ink, 'cg> {
190
191
new_llvm_index : & mut LlvmTypedIndex < ' ink > ,
191
192
) -> Result < FunctionValue < ' ink > , Diagnostic > {
192
193
let declared_parameters = self . index . get_declared_parameters ( implementation. get_call_name ( ) ) ;
193
-
194
194
let parameters = self
195
195
. collect_parameters_for_implementation ( implementation) ?
196
196
. iter ( )
197
197
. enumerate ( )
198
- . map ( |( i, p) | match declared_parameters. get ( i) {
199
- Some ( v)
200
- if v. is_in_parameter_by_ref ( ) &&
201
- // parameters by ref will always be a pointer
202
- p. into_pointer_type ( ) . get_element_type ( ) . is_array_type ( ) =>
203
- {
204
- // for array types we will generate a pointer to the arrays element type
205
- // not a pointer to array
206
- let ty = p
207
- . into_pointer_type ( )
208
- . get_element_type ( )
209
- . into_array_type ( )
210
- . get_element_type ( )
211
- . ptr_type ( AddressSpace :: from ( ADDRESS_SPACE_GENERIC ) ) ;
212
-
213
- // set the new type for further codegen
214
- let _ = new_llvm_index. associate_type ( v. get_type_name ( ) , ty. into ( ) ) ;
215
-
216
- ty. into ( )
198
+ . map ( |( i, p) | {
199
+ let param = declared_parameters. get ( i) ;
200
+ let dti = param. map ( |it| self . index . get_type_information_or_void ( it. get_type_name ( ) ) ) ;
201
+ match param {
202
+ Some ( v)
203
+ if v. is_in_parameter_by_ref ( ) &&
204
+ // parameters by ref will always be a pointer
205
+ p. into_pointer_type ( ) . get_element_type ( ) . is_array_type ( ) =>
206
+ {
207
+ // for by-ref array types we will generate a pointer to the arrays element type
208
+ // not a pointer to array
209
+ let ty = p
210
+ . into_pointer_type ( )
211
+ . get_element_type ( )
212
+ . into_array_type ( )
213
+ . get_element_type ( )
214
+ . ptr_type ( AddressSpace :: from ( ADDRESS_SPACE_GENERIC ) ) ;
215
+
216
+ // set the new type for further codegen
217
+ let _ = new_llvm_index. associate_type ( v. get_type_name ( ) , ty. into ( ) ) ;
218
+
219
+ ty. into ( )
220
+ }
221
+ _ => {
222
+ dti. map ( |it| {
223
+ if !matches ! (
224
+ implementation. get_implementation_type( ) ,
225
+ ImplementationType :: Function
226
+ ) {
227
+ return * p;
228
+ }
229
+ // for aggregate function parameters we will generate a pointer instead of the value type.
230
+ // it will then later be memcopied into a locally allocated variable
231
+ match it {
232
+ DataTypeInformation :: Struct { .. } => p
233
+ . into_struct_type ( )
234
+ . ptr_type ( AddressSpace :: from ( ADDRESS_SPACE_GENERIC ) )
235
+ . into ( ) ,
236
+ DataTypeInformation :: Array { .. } | DataTypeInformation :: String { .. } => p
237
+ . into_array_type ( )
238
+ . get_element_type ( )
239
+ . ptr_type ( AddressSpace :: from ( ADDRESS_SPACE_GENERIC ) )
240
+ . into ( ) ,
241
+ _ => * p,
242
+ }
243
+ } )
244
+ . unwrap_or ( * p)
245
+ }
217
246
}
218
- _ => * p,
219
247
} )
220
248
. collect :: < Vec < BasicMetadataTypeEnum > > ( ) ;
221
249
@@ -521,11 +549,10 @@ impl<'ink, 'cg> PouGenerator<'ink, 'cg> {
521
549
let ptr_value = params_iter
522
550
. next ( )
523
551
. ok_or_else ( || Diagnostic :: missing_function ( m. source_location . clone ( ) ) ) ?;
524
-
525
- let ptr = self
526
- . llvm
527
- . create_local_variable ( m. get_name ( ) , & index. get_associated_type ( m. get_type_name ( ) ) ?) ;
528
-
552
+ let member_type_name = m. get_type_name ( ) ;
553
+ let type_info = self . index . get_type_information_or_void ( member_type_name) ;
554
+ let ty = index. get_associated_type ( member_type_name) ?;
555
+ let ptr = self . llvm . create_local_variable ( m. get_name ( ) , & ty) ;
529
556
if let Some ( block) = self . llvm . builder . get_insert_block ( ) {
530
557
debug. add_variable_declaration (
531
558
m. get_qualified_name ( ) ,
@@ -536,7 +563,57 @@ impl<'ink, 'cg> PouGenerator<'ink, 'cg> {
536
563
m. source_location . get_column ( ) ,
537
564
) ;
538
565
}
539
- self . llvm . builder . build_store ( ptr, ptr_value) ;
566
+
567
+ if matches ! ( m. argument_type, ArgumentType :: ByVal ( VariableType :: Input ) )
568
+ && type_info. is_aggregate ( )
569
+ {
570
+ // a by-value aggregate type => we need to memcpy the data into the local variable
571
+ let ty = if ty. is_array_type ( ) {
572
+ ty. into_array_type ( )
573
+ . get_element_type ( )
574
+ . ptr_type ( AddressSpace :: from ( ADDRESS_SPACE_GENERIC ) )
575
+ } else {
576
+ ty. into_struct_type ( ) . ptr_type ( AddressSpace :: from ( ADDRESS_SPACE_GENERIC ) )
577
+ } ;
578
+ let bitcast = self . llvm . builder . build_bitcast ( ptr, ty, "bitcast" ) . into_pointer_value ( ) ;
579
+ let ( size, alignment) = if let DataTypeInformation :: String { size, encoding } = type_info
580
+ {
581
+ // since passed string args might be larger than the local acceptor, we need to first memset the local variable to 0
582
+ let size = size. as_int_value ( self . index ) . map_err ( |err| {
583
+ Diagnostic :: codegen_error ( err. as_str ( ) , m. source_location . clone ( ) )
584
+ } ) ? as u64 ;
585
+ let char_width = encoding. get_bytes_per_char ( ) ;
586
+ self . llvm
587
+ . builder
588
+ . build_memset (
589
+ bitcast,
590
+ char_width,
591
+ self . llvm . context . i8_type ( ) . const_zero ( ) ,
592
+ self . llvm . context . i64_type ( ) . const_int ( size * char_width as u64 , true ) ,
593
+ )
594
+ . map_err ( |e| Diagnostic :: codegen_error ( e, m. source_location . clone ( ) ) ) ?;
595
+ (
596
+ // we then reduce the amount of bytes to be memcopied by the equivalent of one grapheme in bytes to preserve the null-terminator
597
+ self . llvm . context . i64_type ( ) . const_int ( ( size - 1 ) * char_width as u64 , true ) ,
598
+ char_width,
599
+ )
600
+ } else {
601
+ let Some ( size) = index. get_associated_type ( member_type_name) ?. size_of ( ) else {
602
+ // XXX: can this still fail at this point? might be `unreachable`
603
+ return Err ( Diagnostic :: codegen_error (
604
+ "Unable to determine type size" ,
605
+ m. source_location . clone ( ) ,
606
+ ) ) ;
607
+ } ;
608
+ ( size, 1 )
609
+ } ;
610
+ self . llvm
611
+ . builder
612
+ . build_memcpy ( bitcast, alignment, ptr_value. into_pointer_value ( ) , alignment, size)
613
+ . map_err ( |e| Diagnostic :: codegen_error ( e, m. source_location . clone ( ) ) ) ?;
614
+ } else {
615
+ self . llvm . builder . build_store ( ptr, ptr_value) ;
616
+ } ;
540
617
541
618
( parameter_name, ptr)
542
619
} else {
@@ -753,7 +830,7 @@ impl<'ink, 'cg> PouGenerator<'ink, 'cg> {
753
830
( variadic, variadic. and_then ( VariableIndexEntry :: get_varargs) )
754
831
{
755
832
//Create a size parameter of type i32 (DINT)
756
- let size = self . llvm_index . find_associated_type ( typesystem :: DINT_TYPE ) . map ( Into :: into) ?;
833
+ let size = self . llvm_index . find_associated_type ( DINT_TYPE ) . map ( Into :: into) ?;
757
834
758
835
let ty = self
759
836
. llvm_index
0 commit comments