Передача выбранных комментариев в ответ и расширение информации…
Если что-то собирается сделать, используя §6.10.9 Прагма оператор - _Pragma("unroll")
- это, вероятно, способ сделать это. Вы не можете также встраивать другие директивы предварительной обработки, такие как #if
и #endif
, в тело вызова макроса. Однако быстрый эксперимент показал, что gcc -E
по-прежнему ставит #pragma
перед расширенным l oop. Возможно, вам придется проверить, действует ли прагма, посмотрев код ассемблера. Оптимизатор может изменить этот конкретный l oop на a = 5;
, исключив в целом i
и ничего не развернув.
Кроме того, G CC L oop -Specifi * 1070 Документация * Pragmas гласит, что вам нужно использовать #pragma GCC unroll n
(с указанием, сколько раз развернуть l oop).
Вы не можете полагаться на любой #pragma
, который не задокументирован стандартом. быть переносимым на любой компилятор. Прагмы изначально определены компилятором c. Существует 3 стандартных прагмы, каждая из которых начинается с #pragma STDC
- ни одна из них не связана с развертыванием l oop. См. Также §6.10.6 Директива Pragma для стандартных прагм и документацию "все зависит от компилятора".
Делая код в l oop немного более сложным, вы можно получить l oop развернутым, если вы используете:
Не работает, если вы попытаетесь:
Пример кода:
extern double course_deviation(double x, double y);
#define K( arg ) arg
int main(void)
{
K(
int a = 0;
_Pragma("GCC unroll 5")
//#pragma GCC unroll 5
for (int i = 0; i < 5; i++)
{
a += course_deviation(i + 3.0, i - 3.0);
}
)
return a;
}
При наличии директивы #pragma
вместо оператора _Pragma
код не компилируется. Как показано, соответствующий раздел кода ассемблера, созданного G CC 9.3.0 в macOS Mojave 10.14.6:
$ gcc -O -S k37.c
$ sed '/LFE0/q' k37.s
.text
.section __TEXT,__text_startup,regular,pure_instructions
.globl _main
_main:
LFB0:
subq $24, %rsp
LCFI0:
movsd lC0(%rip), %xmm1
movsd lC1(%rip), %xmm0
call _course_deviation
movsd %xmm0, 8(%rsp)
movsd lC2(%rip), %xmm1
movsd lC3(%rip), %xmm0
call _course_deviation
movapd %xmm0, %xmm1
pxor %xmm2, %xmm2
addsd 8(%rsp), %xmm2
cvttsd2sil %xmm2, %eax
pxor %xmm0, %xmm0
cvtsi2sdl %eax, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 8(%rsp)
movsd lC5(%rip), %xmm1
movsd lC6(%rip), %xmm0
call _course_deviation
movapd %xmm0, %xmm1
cvttsd2sil 8(%rsp), %eax
pxor %xmm0, %xmm0
cvtsi2sdl %eax, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 8(%rsp)
pxor %xmm1, %xmm1
movsd lC7(%rip), %xmm0
call _course_deviation
movapd %xmm0, %xmm1
cvttsd2sil 8(%rsp), %eax
pxor %xmm0, %xmm0
cvtsi2sdl %eax, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 8(%rsp)
movsd lC8(%rip), %xmm1
movsd lC9(%rip), %xmm0
call _course_deviation
movapd %xmm0, %xmm1
cvttsd2sil 8(%rsp), %eax
pxor %xmm0, %xmm0
cvtsi2sdl %eax, %xmm0
addsd %xmm1, %xmm0
cvttsd2sil %xmm0, %eax
addq $24, %rsp
LCFI1:
ret
LFE0:
Без опции -O
(без оптимизации), соответствующий раздел Код ассемблера выглядит следующим образом - без l oop раскрутка. Похоже, что развертывание l oop является оптимизацией - без оптимизации, без развертывания l oop.
.text
.globl _main
_main:
LFB0:
pushq %rbp
LCFI0:
movq %rsp, %rbp
LCFI1:
subq $16, %rsp
movl $0, -4(%rbp)
movl $0, -8(%rbp)
jmp L2
L3:
cvtsi2sdl -8(%rbp), %xmm0
movsd lC0(%rip), %xmm1
movapd %xmm0, %xmm2
subsd %xmm1, %xmm2
cvtsi2sdl -8(%rbp), %xmm1
movsd lC0(%rip), %xmm0
addsd %xmm1, %xmm0
movapd %xmm2, %xmm1
call _course_deviation
cvtsi2sdl -4(%rbp), %xmm1
addsd %xmm1, %xmm0
cvttsd2sil %xmm0, %eax
movl %eax, -4(%rbp)
addl $1, -8(%rbp)
L2:
cmpl $4, -8(%rbp)
setle %al
testb %al, %al
jne L3
movl -4(%rbp), %eax
leave
LCFI2:
ret
LFE0:
Я пытался использовать atan2()
из <math.h>
вместо функции course_correction()
, и оптимизатор оптимизировал код до - просто возвращая 7
:
.text
.section __TEXT,__text_startup,regular,pure_instructions
.globl _main
_main:
LFB19:
movl $7, %eax
ret
LFE19:
С исходным кодом (a++;
в теле l oop, результат возвращался 5
вместо 7
.