Can main stream compilers convert base types passed by reference to pass-by-copy?

Passing an object by reference is an easier, faster, and safer way to pass an address to it. But for most compilers, it's all the same: links are really pointers.

Now about basic types like int ? Passing the address to int and using it inside the function will be slower than passing it in as a copy, since the pointer must be dereferenced before use.

How is the modern compiler handled?

 int foo(const int & i) { cout << i; // Do whatever read-only with i. } 

Can I trust them to compile this into this?

 int foo(const int i) { cout << i; } 

By the way, in some cases it would be even faster to go through both i and &i , and then use i to read and *i to write.

 int foo(const int i, int * ptr_i) { cout << i; // no dereferencement, therefore faster (?) // many more read-only operations with i. *ptr_i = 123; } 
+6
source share
4 answers

Visual Studio 2010 (Express) does, in simple cases, which I tested at least. Can anyone check gcc?

I tested the following:

1. Transmission only i :

 int vars[] = {1,2,3,12,3,23,1,213,231,1,21,12,213,21321,213,123213,213123}; int ok1(const int i){ return sqrtl(vars[i]); } int ok2(const int & i){ return sqrtl(vars[i]); } void main() { int i; std::cin >> i; //i = ok1(i); i = ok2(i); std::cout << i; } 

ASM:

 i = ok1(i); 000D1014 mov ecx,dword ptr [i] 000D1017 fild dword ptr vars (0D3018h)[ecx*4] 000D101E call _CIsqrt (0D1830h) 000D1023 call _ftol2_sse (0D1840h) i = ok2(i); 013A1014 mov ecx,dword ptr [i] 013A1017 fild dword ptr vars (13A3018h)[ecx*4] 013A101E call _CIsqrt (13A1830h) 013A1023 call _ftol2_sse (13A1840h) 

Well, ASMs are identical; no doubt, optimization has been performed.

2. Transfer of i and &i :

Consider here @newacct anser.

 int vars[] = {1,2,3,12,3,23,1,213,231,1,21,12,213,21321,213,123213,213123}; int ok1(const int i, int * pi) { *pi = 2; return sqrtl(vars[i]); } int ok2(const int & i, int * pi) { *pi = 2; return sqrtl(vars[i]); } void main() { int i; int * pi = &i; std::cin >> i; i = ok1(i, pi); //i = ok2(i, pi); std::cout << i; } 

ASM:

 i = ok1(i, pi); 00891014 mov ecx,dword ptr [i] 00891017 fild dword ptr vars (893018h)[ecx*4] // access vars[i] 0089101E call _CIsqrt (891830h) 00891023 call _ftol2_sse (891840h) i = ok2(i, pi); 011B1014 fild dword ptr [vars+8 (11B3020h)] // access vars[2] 011B101A call _CIsqrt (11B1830h) 011B101F call _ftol2_sse (11B1840h) 

In ok1 I do not see him writing 2 in pi . He probably understands that the memory location will be overwritten by the result of the function in any case, so writing is useless.

With ok2 , the compiler is as smart as I expected. He understands that i and pi pointing to the same place, so he directly uses hard-coded 2 .

Notes:

  • I compiled twice for both tests, once uncommenting only ok1 , after uncommenting only ok2 . Compiling both at the same time leads to more complex optimization between the two functions, which eventually become all nested and mixed.
  • I added a search to the vars array because simple sqrtl calls were simplified into basic ADD and MUL type operations without actually calling
  • Compiled in version
  • Got the expected results, of course
0
source

Can I trust them to compile this into this? Yes, you can. [Yes here means differently, Please read the section "Edit", "Which specify"]

 int foo(const int & i) 

Tells the compiler that i is a reference to an integer integer type.
The compiler can perform optimizations, but they are allowed to perform optimizations only after the As-If rule . Thus, you can be sure that for your program the behavior of the above will be just as good (the const classifier will be observed):

 int foo(const int i) 

As-If Rule:

The C ++ standard allows the compiler to perform any optimization as long as the resulting executable shows the same observable behavior as if all the requirements of the standard were met.

For fans of Standerdese:
C ++ 03 1.9 "Program execution:

Appropriate implementations are needed to emulate (only) the observed behavior of an abstract machine.

And the Foot-Note says:

This provision is sometimes called the β€œas is” rule, because an implementation can ignore any requirement of this International Standard if the result is as if this requirement were met, as far as it can be determined from the observed behavior of the program. For example, the actual implementation should not evaluate part of the expression if it can infer that its value is not used and that no side effects affecting the observed behavior of the program are produced.

EDIT:
Since there is some confusion in the answer, let me clarify:
Optimization cannot be applied to the compiler. Since the compiler interprets this, it depends on the compiler. It is important that the observed behavior of the program does not change.

+4
source

He should not compile it into this, because this may not be true. Consider:

 int foo(const int &i, int *p) { *p = 42; cout << i; // prints 42 return 0; } int main() { int x = 5; foo(x, &x); return 0; } 

against

 int foo(const int i, int *p) { *p = 42; cout << i; // prints 5 return 0; } int main() { int x = 5; foo(x, &x); return 0; } 

How does the compiler know that this will not happen? It would have to be somehow able to analyze that it is impossible to access this variable in order to change it, for example. (1) someone has a pointer, (2) it can be a global variable, (3) from another thread. Given the insecure nature of C, with pointer arithmetic and everything, even ensuring that a function cannot get a pointer to this variable, it may not be possible.

+3
source

gcc does not seem to do this optimization with -O3 (gcc version 4.7.2). Using Gabriel's code, notice how ok2 loads the dereferenced address before indexing into vars, while ok1 does not.

ok1:

 .cfi_startproc subq $40, %rsp .cfi_def_cfa_offset 48 movslq %edi, %rdi fildl vars(,%rdi,4) fld %st(0) fsqrt fucomi %st(0), %st jp .L7 fstp %st(1) 
ok2:
 .cfi_startproc subq $40, %rsp .cfi_def_cfa_offset 48 movslq (%rdi), %rax fildl vars(,%rax,4) fld %st(0) fsqrt fucomi %st(0), %st jp .L12 fstp %st(1) 
0
source

Source: https://habr.com/ru/post/900461/


All Articles