@@ -375,3 +375,218 @@ fn void_pointer_casting() {
375375 attributes #0 = { argmemonly nofree nounwind willreturn }
376376 "# ) ;
377377}
378+
379+ #[ test]
380+ fn user_defined_virtual_table_calls ( ) {
381+ let result = codegen (
382+ r"
383+ // Virtual Table Definitions
384+ TYPE UserVT_FbA:
385+ STRUCT
386+ printNumber: POINTER TO FbA.printNumber := ADR(FbA.printNumber);
387+ END_STRUCT
388+ END_TYPE
389+
390+ TYPE UserVT_FbB:
391+ STRUCT
392+ // No override, hence the ADR(FbA.<...>)
393+ printNumber: POINTER TO FbA.printNumber := ADR(FbA.printNumber);
394+ END_STRUCT
395+ END_TYPE
396+
397+ TYPE UserVT_FbC:
398+ STRUCT
399+ // override, hence the ADR(FbC.<...>)
400+ printNumber: POINTER TO FbA.printNumber := ADR(FbC.printNumber);
401+ END_STRUCT
402+ END_TYPE
403+
404+ // Virtual Table Instances
405+ VAR_GLOBAL
406+ UserVT_FbA_instance: UserVT_FbA;
407+ UserVT_FbB_instance: UserVT_FbB;
408+ UserVT_FbC_instance: UserVT_FbC;
409+ END_VAR
410+
411+ FUNCTION_BLOCK FbA
412+ VAR
413+ vt: POINTER TO __VOID;
414+ localStateA: DINT := 5;
415+ END_VAR
416+
417+ METHOD printNumber
418+ VAR_INPUT
419+ in: DINT;
420+ END_VAR
421+ END_METHOD
422+ END_FUNCTION_BLOCK
423+
424+ FUNCTION_BLOCK FbB EXTENDS FbA
425+ VAR
426+ localStateB: DINT := 10;
427+ END_VAR
428+ END_FUNCTION_BLOCK
429+
430+ FUNCTION_BLOCK FbC EXTENDS FbA
431+ VAR
432+ localStateC: DINT := 15;
433+ END_VAR
434+
435+ METHOD printNumber
436+ VAR_INPUT
437+ in: DINT;
438+ END_VAR
439+ END_METHOD
440+ END_FUNCTION_BLOCK
441+
442+ FUNCTION main
443+ VAR
444+ instanceFbA: FbA;
445+ instanceFbB: FbB;
446+ instanceFbC: FbC;
447+ refInstanceFbA: POINTER TO FbA;
448+ END_VAR
449+
450+ // Virtual Table Initialization
451+ instanceFbA.vt := ADR(UserVT_FbA_instance);
452+ instanceFbB.vt := ADR(UserVT_FbB_instance);
453+ instanceFbC.vt := ADR(UserVT_FbC_instance);
454+
455+ refInstanceFbA := ADR(instanceFbA);
456+ UserVT_FbA#(refInstanceFbA^.vt^).printNumber^(refInstanceFbA^, 5);
457+
458+ refInstanceFbA := ADR(instanceFbB);
459+ UserVT_FbA#(refInstanceFbA^.vt^).printNumber^(refInstanceFbA^, 10);
460+
461+ refInstanceFbA := ADR(instanceFbC);
462+ UserVT_FbA#(refInstanceFbA^.vt^).printNumber^(refInstanceFbA^, 15);
463+ END_FUNCTION
464+ " ) ;
465+
466+ // Lots of yada yada, the interesting part happens in the `main` function
467+ filtered_assert_snapshot ! ( result, @r#"
468+ ; ModuleID = '<internal>'
469+ source_filename = "<internal>"
470+ target datalayout = "[filtered]"
471+ target triple = "[filtered]"
472+
473+ %UserVT_FbA = type { void (%FbA*, i32)* }
474+ %FbA = type { i32*, i32 }
475+ %UserVT_FbB = type { void (%FbA*, i32)* }
476+ %UserVT_FbC = type { void (%FbA*, i32)* }
477+ %FbB = type { i32 }
478+ %FbC = type { i32 }
479+
480+ @UserVT_FbA_instance = global %UserVT_FbA zeroinitializer
481+ @__UserVT_FbA__init = unnamed_addr constant %UserVT_FbA zeroinitializer
482+ @__FbA__init = unnamed_addr constant %FbA { i32* null, i32 5 }
483+ @UserVT_FbB_instance = global %UserVT_FbB zeroinitializer
484+ @__UserVT_FbB__init = unnamed_addr constant %UserVT_FbB zeroinitializer
485+ @UserVT_FbC_instance = global %UserVT_FbC zeroinitializer
486+ @__UserVT_FbC__init = unnamed_addr constant %UserVT_FbC zeroinitializer
487+ @__FbB__init = unnamed_addr constant %FbB { i32 10 }
488+ @__FbC__init = unnamed_addr constant %FbC { i32 15 }
489+
490+ define void @FbA__printNumber(%FbA* %0, i32 %1) {
491+ entry:
492+ %this = alloca %FbA*, align 8
493+ store %FbA* %0, %FbA** %this, align 8
494+ %vt = getelementptr inbounds %FbA, %FbA* %0, i32 0, i32 0
495+ %localStateA = getelementptr inbounds %FbA, %FbA* %0, i32 0, i32 1
496+ %in = alloca i32, align 4
497+ store i32 %1, i32* %in, align 4
498+ ret void
499+ }
500+
501+ define void @FbA(%FbA* %0) {
502+ entry:
503+ %this = alloca %FbA*, align 8
504+ store %FbA* %0, %FbA** %this, align 8
505+ %vt = getelementptr inbounds %FbA, %FbA* %0, i32 0, i32 0
506+ %localStateA = getelementptr inbounds %FbA, %FbA* %0, i32 0, i32 1
507+ ret void
508+ }
509+
510+ define void @FbB(%FbB* %0) {
511+ entry:
512+ %this = alloca %FbB*, align 8
513+ store %FbB* %0, %FbB** %this, align 8
514+ %localStateB = getelementptr inbounds %FbB, %FbB* %0, i32 0, i32 0
515+ ret void
516+ }
517+
518+ define void @FbC(%FbC* %0) {
519+ entry:
520+ %this = alloca %FbC*, align 8
521+ store %FbC* %0, %FbC** %this, align 8
522+ %localStateC = getelementptr inbounds %FbC, %FbC* %0, i32 0, i32 0
523+ ret void
524+ }
525+
526+ define void @FbC__printNumber(%FbC* %0, i32 %1) {
527+ entry:
528+ %this = alloca %FbC*, align 8
529+ store %FbC* %0, %FbC** %this, align 8
530+ %localStateC = getelementptr inbounds %FbC, %FbC* %0, i32 0, i32 0
531+ %in = alloca i32, align 4
532+ store i32 %1, i32* %in, align 4
533+ ret void
534+ }
535+
536+ define void @main() {
537+ entry:
538+ %instanceFbA = alloca %FbA, align 8
539+ %instanceFbB = alloca %FbB, align 8
540+ %instanceFbC = alloca %FbC, align 8
541+ %refInstanceFbA = alloca %FbA*, align 8
542+ %0 = bitcast %FbA* %instanceFbA to i8*
543+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 bitcast (%FbA* @__FbA__init to i8*), i64 ptrtoint (%FbA* getelementptr (%FbA, %FbA* null, i32 1) to i64), i1 false)
544+ %1 = bitcast %FbB* %instanceFbB to i8*
545+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %1, i8* align 1 bitcast (%FbB* @__FbB__init to i8*), i64 ptrtoint (%FbB* getelementptr (%FbB, %FbB* null, i32 1) to i64), i1 false)
546+ %2 = bitcast %FbC* %instanceFbC to i8*
547+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %2, i8* align 1 bitcast (%FbC* @__FbC__init to i8*), i64 ptrtoint (%FbC* getelementptr (%FbC, %FbC* null, i32 1) to i64), i1 false)
548+ store %FbA* null, %FbA** %refInstanceFbA, align 8
549+ %vt = getelementptr inbounds %FbA, %FbA* %instanceFbA, i32 0, i32 0
550+ store i32* bitcast (%UserVT_FbA* @UserVT_FbA_instance to i32*), i32** %vt, align 8
551+ %vt1 = getelementptr inbounds %FbB, %FbB* %instanceFbB, i32 0, i32 0
552+ store i32* bitcast (%UserVT_FbB* @UserVT_FbB_instance to i32*), i32* %vt1, align 8
553+ %vt2 = getelementptr inbounds %FbC, %FbC* %instanceFbC, i32 0, i32 0
554+ store i32* bitcast (%UserVT_FbC* @UserVT_FbC_instance to i32*), i32* %vt2, align 8
555+ store %FbA* %instanceFbA, %FbA** %refInstanceFbA, align 8
556+ %deref = load %FbA*, %FbA** %refInstanceFbA, align 8
557+ %vt3 = getelementptr inbounds %FbA, %FbA* %deref, i32 0, i32 0
558+ %deref4 = load i32*, i32** %vt3, align 8
559+ %cast = bitcast i32* %deref4 to %UserVT_FbA*
560+ %printNumber = getelementptr inbounds %UserVT_FbA, %UserVT_FbA* %cast, i32 0, i32 0
561+ %3 = load void (%FbA*, i32)*, void (%FbA*, i32)** %printNumber, align 8
562+ %deref5 = load %FbA*, %FbA** %refInstanceFbA, align 8
563+ call void %3(%FbA* %deref5, i32 5)
564+ %4 = bitcast %FbB* %instanceFbB to %FbA*
565+ store %FbA* %4, %FbA** %refInstanceFbA, align 8
566+ %deref6 = load %FbA*, %FbA** %refInstanceFbA, align 8
567+ %vt7 = getelementptr inbounds %FbA, %FbA* %deref6, i32 0, i32 0
568+ %deref8 = load i32*, i32** %vt7, align 8
569+ %cast9 = bitcast i32* %deref8 to %UserVT_FbA*
570+ %printNumber10 = getelementptr inbounds %UserVT_FbA, %UserVT_FbA* %cast9, i32 0, i32 0
571+ %5 = load void (%FbA*, i32)*, void (%FbA*, i32)** %printNumber10, align 8
572+ %deref11 = load %FbA*, %FbA** %refInstanceFbA, align 8
573+ call void %5(%FbA* %deref11, i32 10)
574+ %6 = bitcast %FbC* %instanceFbC to %FbA*
575+ store %FbA* %6, %FbA** %refInstanceFbA, align 8
576+ %deref12 = load %FbA*, %FbA** %refInstanceFbA, align 8
577+ %vt13 = getelementptr inbounds %FbA, %FbA* %deref12, i32 0, i32 0
578+ %deref14 = load i32*, i32** %vt13, align 8
579+ %cast15 = bitcast i32* %deref14 to %UserVT_FbA*
580+ %printNumber16 = getelementptr inbounds %UserVT_FbA, %UserVT_FbA* %cast15, i32 0, i32 0
581+ %7 = load void (%FbA*, i32)*, void (%FbA*, i32)** %printNumber16, align 8
582+ %deref17 = load %FbA*, %FbA** %refInstanceFbA, align 8
583+ call void %7(%FbA* %deref17, i32 15)
584+ ret void
585+ }
586+
587+ ; Function Attrs: argmemonly nofree nounwind willreturn
588+ declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0
589+
590+ attributes #0 = { argmemonly nofree nounwind willreturn }
591+ "# ) ;
592+ }
0 commit comments