Given the following code:
struct Tag {};
struct X {
// Tag t; // if not commented it shouldn't be pointer-interconvertible
int k;
};
int fn(const X& x, int& p) {
int i = x.k;
p = 2;
return i + x.k;
}
The generated code is:
fn(X const&, int&):
mov eax, DWORD PTR [rdi]
mov DWORD PTR [rsi], 2
add eax, DWORD PTR [rdi]
ret
Here the compiler assumes aliasing.
If member t
is not present, the types X
and int
are pointer-interconvertible. As so, the compiler must generate code as if the references could alias.
But if member t
is present, they should no longer be pointer-interconvertible and code for the non-aliased case should be generated. But in both cases the code is identical except the relative address of member k
.
The assembler:
fn(X const&, int&):
mov eax, DWORD PTR [rdi+4]
mov DWORD PTR [rsi], 2
add eax, DWORD PTR [rdi+4]
ret
As an counter-example
template<typename T>
struct X {int k; };
int fn(X<struct A>& x, X<struct B>& p) {
int i = x.k;
p.k = 2;
return i + x.k;
}
in the above version the generated code assumes no aliasing, but the types are pointer-interconvertible.
fn(X<A>&, X<B>&):
mov eax, DWORD PTR [rdi]
mov DWORD PTR [rsi], 2
add eax, eax
ret
Can anyone explain this?