Применяется ли оптимизация к однолинейным функциям? - PullRequest
0 голосов
/ 27 февраля 2019

Я не люблю повторяться в коде, но также я не хочу терять производительность простыми функциями.Предположим, что класс имеет operator+ и функцию Add с той же функциональностью (рассматривая первый как удобный способ использования класса в выражениях, а второй - как "исключенный" способ сделать это)

struct Obj {
   Obj operator+(float);
   Obj Add(float);
   /* some other state and behaviour */
};

Obj AddDetails(Obj const& a, float b) {
   return Obj(a.float_val + b, a.some_other_stuff);
}

Obj Obj::operator+(float b) {
   return AddDetails(*this, b);
}

Obj Obj::Add(float b) {
   return AddDetails(*this, b);
}

Для целейоблегчая изменения, обе функции реализованы с помощью вызова вспомогательной функцииПоэтому любой звонок оператору делает 2 звонка, что не очень приятно.

Но достаточно ли умен компилятор для устранения таких двойных вызовов?

Я тестировал с простыми классами (которые содержат встроенные типы и указатели), и оптимизатор просто не вычисляет что-то ненужное, но как он ведет себя в больших системах (особенно с горячими вызовами)?

Если именно здесь происходит RVO, то работает ли он в больших последовательностях вызовов (3-4), чтобы сложить его в 1 вызов?

PS Да, да, преждевременная оптимизация - этокорень зла, но все же я хочу получить ответ

Ответы [ 2 ]

0 голосов
/ 27 февраля 2019

Общий

Да См. Инструкции, генерируемые на https://godbolt.org/z/VB23-W Строка 21

   movsd   xmm0, qword ptr [rsp]   # xmm0 = mem[0],zero
   addsd   xmm0, qword ptr [rip + .LCPI3_0]

, он просто применяет код AddDetails прямо вместо того, чтобы даже звонить вашему оператору +.Это называется встраиванием и работает даже для этой цепочки вызовов, возвращающих значения.

Подробности

Не только оптимизация RVO может происходить с однострочными функциями, но любая другая оптимизация, включая встраивание, см. https://godbolt.org/z/miX3u1 и https://godbolt.org/z/tNaSW.

Посмотрите на это, вы можете увидеть, что gcc и clang сильно оптимизируют даже объявленный код без встроенных символов, (https://godbolt.org/z/8Wf3oR)

#include <iostream>

struct Obj {
    Obj(double val) : float_val(val) {}
    Obj operator+(float b) {
        return AddDetails(*this, b);
    }
    Obj Add(float b) {
        return AddDetails(*this, b);
    }
    double val() const {
        return float_val;
    }
private:
    double float_val{0};
    static inline Obj AddDetails(Obj const& a, float b);
};

Obj Obj::AddDetails(Obj const& a, float b) {
    return Obj(a.float_val + b);
}


int main() {
    Obj foo{32};
    Obj bar{foo + 1337};
    std::cout << bar.val() << "\n";
}

Даже без встраивания никаких дополнительных вызовов C-Tor невозможно увидеть с помощью

#include <iostream>

struct Obj {
    Obj(double val) : float_val(val) {}
    Obj operator+(float);
    Obj Add(float);
    double val() const {
        return float_val;
    }
private:
    double float_val{0};
    static Obj AddDetails(Obj const& a, float b);
};

Obj Obj::AddDetails(Obj const& a, float b) {
    return Obj(a.float_val + b);
}

Obj Obj::operator+(float b) {
    return AddDetails(*this, b);
}

Obj Obj::Add(float b) {
    return AddDetails(*this, b);
}

int main() {
    Obj foo{32};
    Obj bar{foo + 1337};
    std::cout << bar.val() << "\n";
}

Однако некоторая оптимизация выполняется из-за того, что компилятор знает, что значение не изменится, поэтому давайте изменим основной на

int main() {
    double d{};
    std::cin >> d;
    Obj foo{d};
    Obj bar{foo + 1337};
    std::cout << bar.val() << "\n";
}

Но тогда вы все равно можете увидеть оптимизацию на обоих компиляторах https://godbolt.org/z/M2jaSH и https://godbolt.org/z/OyQfJI

0 голосов
/ 27 февраля 2019

Из того, что я понимаю, современные компиляторы обязаны применять elision в ваших случаях.Согласно https://en.cppreference.com/w/cpp/language/copy_elision,, когда вы пишете return Obj(a.float_val + b, a.some_other_stuff), вызов конструктора является prvalue;его возвращение не создаст временный объект, поэтому перемещение или копирование не произойдет.

...