Return std :: pair compared to passing by non-constant link

Why is returning std::pairor boost::tupleso less effective than returning by reference? In real codes that I tested, setting data with a non-constant link, and not std::pairin the internal core, can speed up the code by 20%.

As an experiment, I examined three scenarios with the simplest case, including adding two (predefined) integers to two integers:

  • Use the internal built-in function to change integers by reference

  • Use two internal, built-in functions to return ints by value

  • Use the internal, built-in function to return the std :: pair that are copied to the result.

Compiling with g++ -c $x -Wall -Wextra -O2 -Sleads to the same assembler for passing by reference and returning ints by value:

__Z7getPairiRiS_:
LFB19:
    pushq   %rbp
LCFI0:
    leal    1023(%rdi), %eax
    addl    $31, %edi
    movl    %eax, (%rsi)
    movq    %rsp, %rbp
LCFI1:
    movl    %edi, (%rdx)
    leave
    ret

(Pass by reference code:

#include <utility>

inline void myGetPair(const int inp, int& a, int& b) {
    a = 1023 + inp;
    b = 31 + inp;
}

void getPair(const int inp, int& a, int& b) {
    myGetPair(inp, a, b);
}

Using individual r values:

#include <utility>

inline int myGetPair1(int inp) {
    return 1023 + inp;
}

inline int myGetPair2(int inp) {
    return 31 + inp;
}

void getPair(const int inp, int& a, int& b) {
    a = myGetPair1(inp);
    b = myGetPair2(inp);
}

)

Using std :: pair, however, adds five additional build commands:

__Z7getPairiRiS_:
LFB18:
    leal    31(%rdi), %eax
    addl    $1023, %edi
    pushq   %rbp
LCFI0:
    salq    $32, %rax
    movq    %rsp, %rbp
LCFI1:
    orq %rdi, %rax
    movq    %rax, %rcx
    movl    %eax, (%rsi)
    shrq    $32, %rcx
    movl    %ecx, (%rdx)
    leave
    ret

The code for this is almost as simple as in the previous examples:

#include <utility>

inline std::pair<int,int> myGetPair(int inp) {
    return std::make_pair(1023 + inp, 31 + inp);
}

void getPair(const int inp, int& a, int& b) {
    std::pair<int,int> result = myGetPair(inp);

    a = result.first;
    b = result.second;
}

Can anyone who knows the internal workings of compilers help with this issue? The boost tuple page refers to a performance penalty for tuples against passing by reference, but none of the related documents answer the question.

, , std:: pair , , , , .

+3
6

V++ 2008, cl.exe /c /O2 /FAs foo.cpp ( " ", " " " " ). getLine() , .

"byref" :

PUBLIC  ?getPair@@YAXHAAH0@Z                ; getPair
; Function compile flags: /Ogtpy
;   COMDAT ?getPair@@YAXHAAH0@Z
_TEXT   SEGMENT
_inp$ = 8                       ; size = 4
_a$ = 12                        ; size = 4
_b$ = 16                        ; size = 4
?getPair@@YAXHAAH0@Z PROC               ; getPair, COMDAT

; 9    :     myGetPair(inp, a, b);

    mov eax, DWORD PTR _inp$[esp-4]
    mov edx, DWORD PTR _a$[esp-4]
    lea ecx, DWORD PTR [eax+1023]
    mov DWORD PTR [edx], ecx
    mov ecx, DWORD PTR _b$[esp-4]
    add eax, 31                 ; 0000001fH
    mov DWORD PTR [ecx], eax

; 10   : }

    ret 0
?getPair@@YAXHAAH0@Z ENDP               ; getPair

"byval" std::pair - :

PUBLIC  ?getPair@@YAXHAAH0@Z                ; getPair
; Function compile flags: /Ogtpy
;   COMDAT ?getPair@@YAXHAAH0@Z
_TEXT   SEGMENT
_inp$ = 8                       ; size = 4
_a$ = 12                        ; size = 4
_b$ = 16                        ; size = 4
?getPair@@YAXHAAH0@Z PROC               ; getPair, COMDAT

; 8    :     std::pair<int,int> result = myGetPair(inp);

    mov eax, DWORD PTR _inp$[esp-4]

; 9    : 
; 10   :     a = result.first;

    mov edx, DWORD PTR _a$[esp-4]
    lea ecx, DWORD PTR [eax+1023]
    mov DWORD PTR [edx], ecx

; 11   :     b = result.second;

    mov ecx, DWORD PTR _b$[esp-4]
    add eax, 31                 ; 0000001fH
    mov DWORD PTR [ecx], eax

; 12   : }

    ret 0
?getPair@@YAXHAAH0@Z ENDP               ; getPair

, ; .

+5

. , -.

+5

? gcc 4.4.2 ( ) pass-by-reference return-pairs-by-value. :

mov 0x4(%esp),%eax
mov 0x8(%esp),%edx
lea 0x3ff(%eax),%ecx
add $0x1f,%eax
mov %ecx,(%edx)
mov 0xc(%esp),%edx
mov %eax,(%edx)
ret
lea 0x0(%esi),%esi

-O2 -fomit-frame-pointer. , . , : P

+4

.

+3

C++ "". , , .

+3

, , , std::pair, , pair . -POD, .

POD- ++ 0x, , , .

+3

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


All Articles