@@ -9,6 +9,7 @@ use inkwell::{
9
9
} ,
10
10
AddressSpace , FloatPredicate , IntPredicate ,
11
11
} ;
12
+ use itertools:: Either ;
12
13
use rustc_hash:: FxHashSet ;
13
14
14
15
use plc_ast:: {
@@ -30,13 +31,12 @@ use crate::{
30
31
llvm_typesystem:: { cast_if_needed, get_llvm_int_type} ,
31
32
} ,
32
33
index:: {
33
- const_expressions:: ConstId , ArgumentType , ImplementationIndexEntry , Index , PouIndexEntry ,
34
- VariableIndexEntry , VariableType ,
34
+ const_expressions:: ConstId , ArgumentType , ImplementationIndexEntry , ImplementationType , Index ,
35
+ PouIndexEntry , VariableIndexEntry , VariableType ,
35
36
} ,
36
37
resolver:: { AnnotationMap , AstAnnotations , StatementAnnotation } ,
37
- typesystem,
38
38
typesystem:: {
39
- is_same_type_class, DataType , DataTypeInformation , DataTypeInformationProvider , Dimension ,
39
+ self , is_same_type_class, DataType , DataTypeInformation , DataTypeInformationProvider , Dimension ,
40
40
StringEncoding , VarArgs , DINT_TYPE , INT_SIZE , INT_TYPE , LINT_TYPE ,
41
41
} ,
42
42
} ;
@@ -485,60 +485,45 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
485
485
operator : & AstNode ,
486
486
parameters : Option < & AstNode > ,
487
487
) -> Result < ExpressionValue < ' ink > , Diagnostic > {
488
- // Extract the base expression from the dereference operator
489
- let base = if let AstStatement :: ReferenceExpr ( ReferenceExpr {
490
- access : ReferenceAccess :: Deref ,
491
- base : Some ( base ) ,
492
- } ) = operator . get_stmt ( )
493
- {
494
- base
495
- } else {
496
- return Err ( Diagnostic :: codegen_error (
497
- "Expected dereference expression with base for function pointer call" ,
498
- operator ,
499
- ) ) ;
488
+ // Assumptions:
489
+ // - Used internally only (during lowering for polymorphism) hence unwraps should be fine
490
+ // - Stateful function call (i.e. the instance is always part of the argument list at position 0)
491
+ // - Pointer does not point to another pointer, rather directly to the function implementation
492
+ // - The function pointer is dereferenced, e.g. `myFnPtr^(...)` rather than `myFnPtr(...)`
493
+
494
+ // fnPtr^(instanceFbA);
495
+ // ^^^^^
496
+ let AstStatement :: ReferenceExpr ( ReferenceExpr { access : ReferenceAccess :: Deref , base : Some ( base ) } ) =
497
+ & operator . stmt
498
+ else {
499
+ unreachable ! ( "internal error, invalid function invocation" )
500
500
} ;
501
501
502
- // Get the function pointer type information
503
- let function_pointer_type = self . annotations . get_type_or_void ( base, self . index ) ;
502
+ // fnPtr -> PointerType { inner_type_name: "FbA.doNothing" }
503
+ let pointer_type = self . annotations . get_type ( base, self . index ) . unwrap ( ) ; // -> PointerType, FbA.doNothing
504
504
505
- // Extract the target function type from the REF_TO pointer type
506
- let target_function_type = if let DataTypeInformation :: Pointer { inner_type_name, .. } =
507
- function_pointer_type. get_type_information ( )
508
- {
509
- self . index . find_effective_type_by_name ( inner_type_name) . ok_or_else ( || {
510
- Diagnostic :: codegen_error (
511
- format ! ( "Could not find function type: {}" , inner_type_name) . as_str ( ) ,
512
- operator,
513
- )
514
- } ) ?
515
- } else {
516
- return Err ( Diagnostic :: codegen_error ( "Expected pointer type for function pointer" , operator) ) ;
505
+ // PointerType { inner_type_name: "FbA.doNothing" } -> DataType { name: "FbA.doNothing", information: Struct { source: Pou }
506
+ let target_function_type = match pointer_type. get_type_information ( ) {
507
+ DataTypeInformation :: Pointer { inner_type_name, .. } => {
508
+ self . index . find_effective_type_by_name ( inner_type_name) . unwrap ( )
509
+ }
510
+
511
+ _ => todo ! ( ) ,
517
512
} ;
518
513
519
- // Get the function from the index to determine its signature
520
- let function_pou = self . index . find_pou ( target_function_type. get_name ( ) ) . ok_or_else ( || {
521
- Diagnostic :: codegen_error (
522
- format ! ( "Could not find function POU: {}" , target_function_type. get_name( ) ) . as_str ( ) ,
523
- operator,
524
- )
525
- } ) ?;
514
+ // "fba.doNothing" -> "Method { name: "FbA.doNothing", parent_name: "FbA", property: None, declaration_kind: Concrete, return_type: "VOID", instance_struct_name: "FbA.doNothing", linkage: Internal, location: SourceLocation { span: Range(2:19 - 2:28), file: Some("<internal>") } }"
515
+ let function_pou = self . index . find_pou ( target_function_type. get_name ( ) ) . unwrap ( ) ;
526
516
527
- // Get the function implementation
528
- let implementation = function_pou. find_implementation ( self . index ) . ok_or_else ( || {
529
- Diagnostic :: codegen_error (
530
- format ! ( "Could not find implementation for function: {}" , target_function_type. get_name( ) )
531
- . as_str ( ) ,
532
- operator,
533
- )
534
- } ) ?;
517
+ // "Method { name: FbA.doNothing, ..." -> "ImplementationIndexEntry { call_name: "FbA.doNothing"
518
+ let implementation = function_pou. find_implementation ( self . index ) . unwrap ( ) ;
535
519
536
520
// Generate the arguments list
537
521
let parameters_list = parameters. map ( flatten_expression_list) . unwrap_or_default ( ) ;
538
522
539
- // For method function pointers, we need to handle the instance parameter specially
540
523
let ( method_instance, actual_parameters) =
541
- if matches ! ( function_pou, PouIndexEntry :: Method { .. } ) && !parameters_list. is_empty ( ) {
524
+ if matches ! ( implementation. implementation_type, ImplementationType :: Method { .. } )
525
+ && !parameters_list. is_empty ( )
526
+ {
542
527
// For methods, the first parameter is the instance, the rest are method parameters
543
528
// But if there's only one parameter, it's just the instance and there are no method parameters
544
529
if parameters_list. len ( ) == 1 {
@@ -547,84 +532,26 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
547
532
( Some ( & parameters_list[ 0 ] ) , & parameters_list[ 1 ..] )
548
533
}
549
534
} else {
550
- ( None , parameters_list . as_slice ( ) )
535
+ panic ! ( "{implementation:#?}" ) ;
551
536
} ;
552
537
553
- // For function blocks, we need special handling for parameters
554
- if matches ! ( function_pou, PouIndexEntry :: FunctionBlock { .. } ) {
555
- // Get the function block instance pointer
556
- if let Ok ( fb_ptr) = self
557
- . generate_expression_value ( base)
558
- . map ( |v| v. as_r_value ( self . llvm , Some ( "deref" . to_string ( ) ) ) )
559
- {
560
- // For function blocks, parameters need to be assigned to the instance variables
561
- // before calling the function block body
562
-
563
- // Generate parameter assignments to the function block instance
564
- let fb_instance_ptr = fb_ptr. into_pointer_value ( ) ;
565
- for argument in parameters_list. iter ( ) {
566
- self . generate_call_struct_argument_assignment ( & CallParameterAssignment {
567
- assignment : argument,
568
- function_name : implementation. get_type_name ( ) ,
569
- index : self
570
- . annotations
571
- . get_hint ( argument)
572
- . and_then ( StatementAnnotation :: get_location_in_parent)
573
- . expect ( "arguments must have a type hint" ) ,
574
- parameter_struct : fb_instance_ptr,
575
- } ) ?;
576
- }
577
-
578
- // Get the function block body implementation
579
- let function_value = self
580
- . llvm_index
581
- . find_associated_implementation ( implementation. get_type_name ( ) )
582
- . ok_or_else ( || {
583
- Diagnostic :: codegen_error (
584
- format ! ( "Could not find LLVM function for: {}" , implementation. get_type_name( ) )
585
- . as_str ( ) ,
586
- operator,
587
- )
588
- } ) ?;
589
-
590
- // Generate the debug statement for the call
591
- self . register_debug_location ( operator) ;
592
-
593
- // Call the function block body with just the instance pointer
594
- let call = self . llvm . builder . build_call ( function_value, & [ fb_ptr. into ( ) ] , "call" ) ;
595
-
596
- // Handle output assignments after the call
597
- // Copy output values back to the assigned output variables
598
- self . assign_output_values ( fb_instance_ptr, implementation. get_type_name ( ) , parameters_list) ?;
599
-
600
- // Handle the return value
601
- let value = call
602
- . try_as_basic_value ( )
603
- . either ( Ok , |_| {
604
- // Return null pointer for void functions
605
- Ok ( get_llvm_int_type ( self . llvm . context , INT_SIZE , INT_TYPE )
606
- . ptr_type ( AddressSpace :: from ( ADDRESS_SPACE_CONST ) )
607
- . const_null ( )
608
- . as_basic_value_enum ( ) )
609
- } )
610
- . map ( ExpressionValue :: RValue ) ;
611
-
612
- return value;
613
- }
614
- }
615
-
616
- // Generate the function pointer value (only for non-FB cases)
538
+ // TODO: Why alloca?
539
+ // %fnPtr = alloca void (%FbA*)*, align 8
617
540
let function_pointer_value = self . generate_expression_value ( base) ?;
541
+
542
+ // %1 = load void (%FbA*)*, void (%FbA*)** %fnPtr, align 8
618
543
let function_pointer = match function_pointer_value {
619
544
ExpressionValue :: LValue ( ptr) => {
620
545
// Load the function pointer from memory
621
546
self . llvm . load_pointer ( & ptr, "" ) . into_pointer_value ( )
622
547
}
623
- ExpressionValue :: RValue ( val ) => val . into_pointer_value ( ) ,
548
+ _ => unreachable ! ( "?" ) ,
624
549
} ;
625
550
626
- // Generate function arguments for non-function block cases
551
+ // TODO: Debug & Understand
627
552
let declared_parameters = self . index . get_declared_parameters ( implementation. get_type_name ( ) ) ;
553
+
554
+ // TODO: Debug & Understand
628
555
let mut arguments_list =
629
556
self . generate_function_arguments ( function_pou, actual_parameters, declared_parameters) ?;
630
557
@@ -649,57 +576,35 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
649
576
}
650
577
}
651
578
652
- // Get the LLVM function type from the implementation
653
- let function_value = self
654
- . llvm_index
655
- . find_associated_implementation ( implementation. get_type_name ( ) )
656
- . ok_or_else ( || {
657
- Diagnostic :: codegen_error (
658
- format ! ( "Could not find LLVM function for: {}" , implementation. get_type_name( ) ) . as_str ( ) ,
659
- operator,
660
- )
661
- } ) ?;
662
- let function_type = function_value. get_type ( ) ;
663
-
664
579
// Cast the function pointer to the correct function type if needed
665
580
let callable_ptr = if function_pointer. get_type ( ) . get_element_type ( ) . is_function_type ( ) {
581
+ // -> %1 = load void (%FbA*)*, void (%FbA*)** %fnPtr, align 8
666
582
function_pointer
667
583
} else {
668
- // Cast to the correct function pointer type
669
- self . llvm
670
- . builder
671
- . build_bitcast (
672
- function_pointer,
673
- function_type. ptr_type ( AddressSpace :: from ( ADDRESS_SPACE_GENERIC ) ) ,
674
- "cast_fn_ptr" ,
675
- )
676
- . into_pointer_value ( )
584
+ unimplemented ! ( )
677
585
} ;
678
586
679
- // Convert the function pointer to a CallableValue
680
- let callable = CallableValue :: try_from ( callable_ptr) . map_err ( |_| {
681
- Diagnostic :: codegen_error ( "Could not convert function pointer to callable" , operator)
682
- } ) ?;
683
-
684
- // Generate the debug statement for the call
685
- self . register_debug_location ( operator) ;
587
+ // -> CallableValue(Right(PointerValue { ptr_value: Value { name: "", address: 0x14d00acc0, is_const: false, is_null: false, is_undef: false, llvm_value: " %1 = load void (%FbA*)*, void (%FbA*)** %fnPtr, align 8", llvm_type: "void (%FbA*)*" } }))
588
+ let callable = CallableValue :: try_from ( callable_ptr) . unwrap ( ) ;
686
589
687
590
// Generate the indirect call
591
+ // -> call void %1(%FbA* %instanceFbA)
688
592
let call = self . llvm . builder . build_call ( callable, & arguments_list, "call" ) ;
593
+ // panic!("{call:#?}");
689
594
690
595
// Handle the return value similar to regular function calls
691
- let value = call
692
- . try_as_basic_value ( )
693
- . either ( Ok , |_| {
694
- // Return null pointer for void functions
695
- Ok ( get_llvm_int_type ( self . llvm . context , INT_SIZE , INT_TYPE )
696
- . ptr_type ( AddressSpace :: from ( ADDRESS_SPACE_CONST ) )
697
- . const_null ( )
698
- . as_basic_value_enum ( ) )
699
- } )
700
- . map ( ExpressionValue :: RValue ) ;
596
+ let value = match call. try_as_basic_value ( ) {
597
+ Either :: Left ( value ) => {
598
+ // If the call returns a value, we return it as an r-value
599
+ value
600
+ }
601
+ Either :: Right ( _ ) => get_llvm_int_type ( self . llvm . context , INT_SIZE , INT_TYPE )
602
+ . ptr_type ( AddressSpace :: from ( ADDRESS_SPACE_CONST ) )
603
+ . const_null ( )
604
+ . as_basic_value_enum ( ) ,
605
+ } ;
701
606
702
- value
607
+ Ok ( ExpressionValue :: RValue ( value) )
703
608
}
704
609
705
610
/// generates the given call-statement <operator>(<parameters>)
@@ -712,8 +617,12 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
712
617
operator : & AstNode ,
713
618
parameters : Option < & AstNode > ,
714
619
) -> Result < ExpressionValue < ' ink > , Diagnostic > {
715
- // TODO(vosa): Perhaps to be 100% sure also check if the operator has a pointer annotation; for now this works though
716
- if operator. is_deref ( ) {
620
+ if operator. is_deref ( )
621
+ && self
622
+ . annotations
623
+ . get_type ( operator, self . index )
624
+ . is_some_and ( |opt| opt. is_method_pointer ( self . index ) )
625
+ {
717
626
return self . generate_function_pointer_call ( operator, parameters) ;
718
627
}
719
628
0 commit comments