After taking a look at a few questions (and answers) regarding this topic, I tried the below simple code in godbolt.
#include <iostream>
class TwoInts
{
public:
TwoInts( ) = default;
const int& getAByRef( ) const;
int getAByVal( ) const;
private:
int a;
int b;
};
const int& TwoInts::getAByRef( ) const
{
return a;
}
int TwoInts::getAByVal( ) const
{
return a;
}
int main( )
{
TwoInts ti;
const int& num1 { ti.getAByRef( ) };
const int num2 { ti.getAByVal( ) };
//std::cout << num1 << ' ' << num2 << '\n';
}
Now I see different codes generated for the two member functions getAByRef
and getAByVal
:
TwoInts::getAByRef() const:
mov rax, rdi
ret
TwoInts::getAByVal() const:
mov eax, DWORD PTR [rdi]
ret
I would appreciate it if someone could explain what those two different assembly instructions are doing?
CodePudding user response:
Each member function gets this
as an implicit first argument. In ABI used by that particular compiler (Itanium ABI), the first argument is passed in the rdi
register and a value is returned (if it's trivial, and here it is) in the rax
(eax
) register.
In the first case, when you return a
by reference, you're actually returning an address of a
. a
is the first member, so its address is the same as that of the object, i.e. this
. Hence, you just set rax
to rdi
.
In the second case, when you return a
by value, you need to do actual dereferencing. That's what DWORD PTR [rdi]
is doing. DWORD PTR
means that you want to fetch 4 bytes (sizeof(int)
).
If you put some data member before a
, you'll see an additional offset added to rdi
.