https://godbolt.org/z/W8b3TG5f6
struct A { int __attribute__((noinline)) call(int a) { return (this->*mfuncP)(a); } int __attribute__((noinline)) returnArg(int a) { return a; } int (A::*mfuncP)(int) = &A::returnArg;};int test(int a) { return A().call(a);}
yields
A::returnArg(int): mov eax, esi retA::call(int): mov rax, QWORD PTR [rdi] add rdi, QWORD PTR [rdi+8] test al, 1 je .L4 mov rdx, QWORD PTR [rdi] mov rax, QWORD PTR [rdx-1+rax].L4: jmp raxtest(int): sub rsp, 24 mov esi, edi mov rdi, rsp mov QWORD PTR [rsp], OFFSET FLAT:A::returnArg(int) mov QWORD PTR [rsp+8], 0 call A::call(int) add rsp, 24 ret
If I understand correctly, the assembly, in this case, is such that if the function address has the LSB set to 1, it is interpreted as referring to a virtual method (https://itanium-cxx-abi.github.io/cxx-abi/abi.html#member-function-pointers) hence the need for the branch. However, class A has no virtual functions, so it is unclear why this handling is done.