Как заставить GCC помещать константы в память вместо их генерации?
У меня много постоянных массивов, определенных в нескольких функциях. Что-то вроде следующего:
const float values[4] = {-4312.435f, -432.44333f, 4.798, 7898.89};
После проверки выхода gcc-ассемблера я заметил, что эти константы генерируются при каждом запуске функций. Это довольно неэффективно. Я подозреваю, что это связано с тем, что спецификация C/С++ говорит, что даже если данные const
, компилятор не может предположить, что он не будет изменен (например, через const_cast). Можно ли заставить gcc думать иначе?
Я хочу, чтобы эти константы определялись внутри тел функций, потому что они довольно сложны. Сохранение констант вблизи того места, где они используются, помогает в ремонтопригодности.
ИЗМЕНИТЬ
К сожалению, даже когда константы определены static
, они обновляются на каждом прогоне. Я использую -O3, если это помогает.
EDIT2
Хорошо, извините за первое редактирование, мне нужно исследовать дальше. Кажется, что определенная настройка ранее каким-то образом не позволяла gcc инициализировать константы без их регенерации.
EDIT3
Проблема была в моей тестовой папке, где я определил два массива рядом, но один из них должен был быть сгенерирован. Затем ассемблер ввел меня в заблуждение. Извините еще раз и спасибо!
Ответы
Ответ 1
Объявите их с помощью ключевого слова static
.
Изменить: ответ на ваш комментарий, чтобы я мог показать вам код:
Это ожидаемое поведение. Вы делаете или видите что-то другое?
$ cat foo.c++
int main(void)
{
static const float foos[] = {1.234f, 5.678f, 9.012f};
return 0;
}
$ g++ -S foo.c++
$ cat foo.s
.file "foo.c++"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
.cfi_personality 0x3,__gxx_personality_v0
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
movl $0, %eax
leave
ret
.cfi_endproc
.LFE0:
.size main, .-main
.section .rodata
.align 4
.type _ZZ4mainE4foos, @object
.size _ZZ4mainE4foos, 12
_ZZ4mainE4foos:
.long 1067316150
.long 1085649453
.long 1091580199
.ident "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
.section .note.GNU-stack,"",@progbits
Ответ 2
Компилятор действительно может предположить, что значения, определенные как const
, никогда не изменятся. (Вещи, доступ к которым осуществляется через переменную const
, - это еще одна история, я говорю только о случаях, когда определение видимо и имеет const
.) Получаемая здесь информация заключается в том, что стандарт говорит, если вы вызываете свою функцию рекурсивно, адрес values
будет отличаться каждый раз.
Поэтому используйте функцию языка, которая означает, что декларация относится к одной и той же вещи при каждом вызове функции. То есть, переменная функции static
:
static const float values[4] = {-4312.435f, -432.44333f, 4.798, 7898.89};
Ответ 3
Измените определение на
static const float values[4] = {-4312.435f, -432.44333f, 4.798, 7898.89};
Статические массивы не будут помещаться в стек функции, поэтому они не будут восстановлены для каждого вызова функции.
Вы также можете попытаться перенести этот массив из функции (сделайте его глобальным массивом с некоторым префиксом, например function1_values
).
EDIT:
Если вы считаете экземпляры "flds"
или "movss"
регенерирующими - это не так. Константы будут храниться в разделе .rodata
файла elf, но для их использования компилятор должен загрузить их в регистры. Таким образом, fld
и movss
будут загружать константу из памяти, и невозможно получить значение из памяти, не загружая ее.
Пример кода:
int function4(float *a, int sz)
{
int i;
const float values[4] = {-4312.435f, -432.44333f, 4.798, 7898.89};
for(i=4;i<sz;i++);
a[i]+=a[i-1]*values[0]+a[i-2]*values[1]+a[i-3]*values[2]+a[i-4]*values[3];
return i;
}
gcc-4.5.2 -O3 a.c -fverbose-asm -mfpmath = sse -march = native -S
Ассемблер для тела цикла:
.L2:
movl -20(%ebp), %ecx # %sfp, D.2677
leal (%edx,%ecx), %ecx #, D.2677
movss .LC0, %xmm0 #, tmp192 << THIS is a constant loading
mulss (%edx,%edi), %xmm0 #* prephitmp.46, tmp192
movss .LC1, %xmm1 #, tmp179
mulss (%edx,%esi), %xmm1 #* prephitmp.46, tmp179
addss %xmm1, %xmm0 # tmp179, tmp192
movss .LC2, %xmm1 #, tmp183
mulss (%edx,%ebx), %xmm1 #* prephitmp.46, tmp183
addss %xmm1, %xmm0 # tmp183, tmp192
movss .LC3, %xmm1 #, tmp187
movl -16(%ebp), %ebx # %sfp,
И константы хранятся в .rodata
:
.section .rodata.cst4,"aM",@progbits,4
.align 4
.LC0:
.long -981023877
.align 4
.LC1:
.long -1009239873
.align 4
.LC2:
.long 1083803959
.align 4
.LC3:
.long 1173804831
Ответ 4
Поместите все свои
const float values[4] = {-4312.435f, -432.44333f, 4.798, 7898.89};
в отдельном файле .cpp.
Объявите их extern в файле, который использует эти массивы
extern const float values[4];
Хотя, как упоминалось в комментариях, профайл это (в реальном приложении, где эти массивы могут быть выброшены из кэшей l1/l2). Это может по неинтересным причинам снизить производительность.
Ответ 5
Я не понимаю, где вы видите проблему, компилятор делает разумную вещь, оптимизируя константы. Вы можете предотвратить это, требуя внешнего соединения:
extern const float values[4];