1 // Member pointer to virtual function. 2 3 // RUN: %clang_cc1 %s -triple=aarch64-unknown-fuchsia -O3 -S -o - -emit-llvm | FileCheck %s 4 5 // CHECK: define{{.*}} void @_Z4funcP1AMS_FvvE(%class.A* noundef %a, [2 x i64] %fn.coerce) local_unnamed_addr 6 // CHECK-NEXT: entry: 7 // CHECK-NEXT: [[fn_ptr:%.+]] = extractvalue [2 x i64] %fn.coerce, 0 8 // CHECK-NEXT: [[adjust:%.+]] = extractvalue [2 x i64] %fn.coerce, 1 9 // CHECK-NEXT: [[this:%.+]] = bitcast %class.A* %a to i8* 10 // CHECK-NEXT: [[this_adj:%.+]] = getelementptr inbounds i8, i8* [[this]], i64 [[adjust]] 11 // CHECK-NEXT: [[virtbit:%.+]] = and i64 [[fn_ptr]], 1 12 // CHECK-NEXT: [[isvirt:%.+]] = icmp eq i64 [[virtbit]], 0 13 // CHECK-NEXT: br i1 [[isvirt]], label %[[nonvirt:.+]], label %[[virt:.+]] 14 // CHECK: [[virt]]: 15 16 // The loading of the virtual function here should be replaced with a llvm.load.relative() call. 17 // CHECK-NEXT: [[this:%.+]] = bitcast i8* [[this_adj]] to i8** 18 // CHECK-NEXT: [[vtable:%.+]] = load i8*, i8** [[this]], align 8 19 // CHECK-NEXT: [[offset:%.+]] = add i64 [[fn_ptr]], -1 20 // CHECK-NEXT: [[ptr:%.+]] = tail call i8* @llvm.load.relative.i64(i8* [[vtable]], i64 [[offset]]) 21 // CHECK-NEXT: [[method:%.+]] = bitcast i8* [[ptr]] to void (%class.A*)* 22 // CHECK-NEXT: br label %[[memptr_end:.+]] 23 // CHECK: [[nonvirt]]: 24 // CHECK-NEXT: [[method2:%.+]] = inttoptr i64 [[fn_ptr]] to void (%class.A*)* 25 // CHECK-NEXT: br label %[[memptr_end]] 26 // CHECK: [[memptr_end]]: 27 // CHECK-NEXT: [[method3:%.+]] = phi void (%class.A*)* [ [[method]], %[[virt]] ], [ [[method2]], %[[nonvirt]] ] 28 // CHECK-NEXT: [[a:%.+]] = bitcast i8* [[this_adj]] to %class.A* 29 // CHECK-NEXT: tail call void [[method3]](%class.A* {{[^,]*}} [[a]]) 30 // CHECK-NEXT: ret void 31 // CHECK-NEXT: } 32 33 class A { 34 public: 35 virtual void foo(); 36 }; 37 38 class B : public A { 39 public: 40 void foo() override; 41 }; 42 43 typedef void (A::*A_foo)(); 44 45 void func(A *a, A_foo fn) { 46 (a->*fn)(); 47 } 48