waqur: (Евро)
[personal profile] waqur

gcc4.8.3_amd64 -std=c++11 -O3

Сначала небольшой безобидный кусочек кода в стиле C++03:
==исходный код 1==
uint32_t f( uint32_t  x )
{
    static const uint32_t  local_array[] = { 0x11112222U, 0x33334444U, 0x55556666U, 0x77778888U };
    return  local_array[x & 3U];
}

====

==машинный код 1==
.text:0000000000000000 ; f(unsigned int)
.text:0000000000000000                 public _Z1fj
.text:0000000000000000 _Z1fj           proc near
.text:0000000000000000                 and     edi, 3
.text:0000000000000003                 mov     eax, dword ptr ds:_ZZ1fjE11local_array[rdi*4] ; f(uint)::local_array
.text:000000000000000A
.text:000000000000000A locret_A:
.text:000000000000000A                 retn
.text:000000000000000A _Z1fj           endp

.rodata:0000000000000170 ; f(unsigned int)::local_array
.rodata:0000000000000170 _ZZ1fjE11local_array dd 11112222h
.rodata:0000000000000174                 dd 33334444h
.rodata:0000000000000178                 dd 55556666h
.rodata:000000000000017C                 dd 77778888h

==

Всё чинно, константная табличка в .rodata и обращение к ней из секции .text

Делаем ещё более константный массив, в стиле C++11-константнее-некуда:

==исходный код 2==
uint32_t f( uint32_t  x )
{
    constexpr uint32_t  local_array[] = { 0x11112222U, 0x33334444U, 0x55556666U, 0x77778888U };
    return  local_array[x & 3U];
}

====

В ответ это компилятор выдаёт ужасы нашего городка:

==машинный код 2==
.text:0000000000000000 ; =============== S U B R O U T I N E =======================================
.text:0000000000000000
.text:0000000000000000
.text:0000000000000000 ; f(unsigned int)
.text:0000000000000000                 public _Z1fj
.text:0000000000000000 _Z1fj           proc near
.text:0000000000000000
.text:0000000000000000 var_18          = dword ptr -18h
.text:0000000000000000 var_14          = dword ptr -14h
.text:0000000000000000 var_10          = dword ptr -10h
.text:0000000000000000 var_C           = dword ptr -0Ch
.text:0000000000000000
.text:0000000000000000                 and     edi, 3
.text:0000000000000003                 mov     [rsp+var_18], 11112222h
.text:000000000000000B                 mov     [rsp+var_14], 33334444h
.text:0000000000000013                 mov     [rsp+var_10], 55556666h
.text:000000000000001B                 mov     [rsp+var_C], 77778888h
.text:0000000000000023                 mov     eax, [rsp+rdi*4+var_18]
.text:0000000000000027
.text:0000000000000027 locret_27:
.text:0000000000000027                 retn
.text:0000000000000027 _Z1fj           endp

====

Красный террор и холокост в одном флаконе: "констатная" таблица перевычисляется при каждом вызове функции, да ещё и размещается в зарезервированной области стека для параметров, которую должна создавать вызывающая сторона по конвенции ABI.

Какой конпелятор, такое и O3. Поддержка C++11 на уровне "пришей собаке хвост".

Date: 2014-01-10 04:10 pm (UTC)
From: [identity profile] bitfield.livejournal.com
Ты не вкурил смысл constexpr (Ничего, что на ты?)
Это замена всяким извращениям вида "посчитать Фибоначчи на шаблонах".
constexpr = посчитать на этапе компиляции. что компилятор и делает.

Date: 2014-01-10 05:13 pm (UTC)
From: [identity profile] waqur.livejournal.com
про constexpr-функции я в курсе.
однако constexpr-константы это немного другое.

предположим, есть embedded-код, который в header-файле объявляет кучу констант

1) сишники использовали #define:
#define MY_COOL_CONSTANT 0x12345

2) c++ники (секта имени 2003 года) используют static const
static const uint32_t MY_COOL_CONSTANT = 0x12345;
при этом глюпый кросс-компилятор дветысячибородатого года с патчами под embedded-железку, но без последних оптимизационных фишечек тупо сваливает все эти static const в секцию данных, и оперативная память на AVRке (например) заканчивается, потому что её там всего лишь 2048 байт

3) на претензии из пункта "2" лучшие собаководы из секты имени 2003 года советуют юзать enum:
enum { MY_COOL_CONSTANT = 0x12345 };
в принципе неплохо, но теряется тип и не поддерживаются например константы типа double
так что часть народа не впечатлилась и продолжили использовать #define

"непорядок" - решил Страуструп и предложил новую фенечку - constexpr
типа как static const только ещё константнее, максимально близко к #define



всё это достаточно подробно разжёвывается в "10.4 Constant Expressions" книги "Язык программирования C++, 4-е издание" за авторством Страуструпа, суть сводится к тому что constexpr-выражение - это всегда литерал, и если его нельзя вычислить в контексте компилятора, то имеем ошибку.

однако gcc всё равно решил, что надо вычислять на каждом входе в функцию
ну OK

Date: 2014-01-10 05:18 pm (UTC)
From: [identity profile] waqur.livejournal.com
кстати, constexpr-функции, про которые Вы говорили, в 4-м издании Страуструпа рассматриваются в другой главе, "12.1.6. constexpr Functions"

Date: 2014-01-10 05:39 pm (UTC)
From: [identity profile] waqur.livejournal.com
смысл constexpr применительно к массивам и глобальным переменным лучше всего поясняет следующий пример:

int f( uint32_t  x )
{
    static const int  local_array[] = { rand(), rand(), rand(), rand() };
    return  local_array[x & 3];
}


Он компилируются. Код, который генерируется компилятором, вызывает rand() четыре раза при первом входе в функцию, а затем сохраняет результаты в глобальной переменной. При последующих вызовах используются старые значения.

Всё просто: static в этом контексте означает "вычислить не более одного раза",
а const означает "элементы массива нельзя изменять после того, как они были проинициализированы"
И ни то, ни другое не означает "вычислить массив на этапе компиляции".

Для того, чтобы выразить требование "вычислить массив на этапе компиляции" в C++11 есть ключевое слово constexpr, ну а в C++03 для выражения этого требования нет нужных ключевых слов, строго говоря.

Date: 2014-01-11 07:05 am (UTC)
From: [identity profile] cd-riper.livejournal.com
ну если это называется вычисление на этапе компиляции...

Date: 2014-01-11 07:06 am (UTC)
From: [identity profile] cd-riper.livejournal.com
зато они первые отрапортовали о полной поддержке C++11.
за такую кодогенерацию надо просто отрывать голову.

March 2024

S M T W T F S
     12
3456789
10111213141516
17181920212223
24252627282930
31      

Автор стиля

Развернуть

No cut tags
Page generated 2026-05-07 02:32 am
Powered by Dreamwidth Studios