Praxeolitic
Praxeolitic

Reputation: 24089

Why do compilers generate different code for const int& vs const int arguments?

Consider these two functions.

int foo(const int& a) {
    return a + 5;
}

int bar(const int a) {
    return a + 5;
}

Given these functions, g++-4.9 generates the following code at full optimization.

g++-4.9 -std=c++11 -Ofast -march=native -DNDEBUG -fno-exceptions -Wall -S -o test17.S test17.cpp
# foo
movl    (%rdi), %eax
addl    $5, %eax
ret

# bar
leal    5(%rdi), %eax
ret

The machine is an x86-64 Mac.

Why is the compiler so "literal minded" here?

My understanding is that references in C++ are usually implemented as pointers but that this is not mandated by the standard. They are best understood as an alias for a variable. The details are left to the implementation.

Given that references need not actually be pointers, it seems like an obvious optimization to generate the same code for both functions. Would it have been illegal to generate the const int code for both of these functions? Is there an observable difference between the two functions?

Upvotes: 1

Views: 135

Answers (1)

AnT stands with Russia
AnT stands with Russia

Reputation: 320631

You declared your functions with external linkage. A compiler that does not (or cannot) perform global program optimizations cannot change interface specification of a function with external linkage for obvious reasons - that function can be called from some other translation unit, which has no knowledge of whether the function's interface specification was "transformed" or not.

If you declare these functions with internal linkage, then the compiler will have much more freedom in transforming these functions.

When I declared your functions static and compiled them with gcc -O3 -fno-inline-functions -fno-inline-functions-called-once -fno-inline-small-functions (in a desperate no-holds-barred attempt to kill any possibility of inlining), they produced identical code

_ZL3bari:
.LFB1:
    .seh_endprologue
    leal    5(%rcx), %eax
    ret

_ZL3fooRKi.isra.0:
.LFB3:
    .seh_endprologue
    leal    5(%rcx), %eax
    ret

Note that these considerations apply to "trivial" functions only (which is probably what you meant in the first place) with "obvious" (to the compiler) semantics. A "non-trivial" function might cast away the constness of the reference and modify the referee, which is perfectly legal provided the referee itself is modifiable. For this reason in general case it is not possible to replace a const reference parameter with a value parameter.

Upvotes: 9

Related Questions