В том случае это не просто было сворачивание константных подвыражений. Это было сворачивание параметра функции до константы, раз он передавался только константой. Согласитесь, это несколько другое.
В том случае это не просто было сворачивание константных подвыражений. Это было сворачивание параметра функции до константы, раз он передавался только константой. Согласитесь, это несколько другое.
Категорически не соглашусь. Аргумент функции в C -- ровно такое же выражение, как и любое другое. С точки зрения компилятора, между этими двумя вызовами функции нет никакой разницы:
Точнее, разница только в том, что значение переменной a может потребоваться сохранить.Код:int a = 5 + 8; func(a) ... func(5+8)
- - - Добавлено - - -
Или речь о том, что он сворачивает вызов чистых функций с константными аргументами в предвычисленную константу? Так это тоже оптимизация константных подвыражений. Чистые функции по определению всегда возвращают одно и то же при тех же аргументах.
Имеется в виду вот что:
Насколько говорит мой опыт, компиляторы Си (особенно набортные или для ретро-таргетов) эту оптимизацию не делают.Код:void func (int a, int b, int с) { ... a ; // вот здесь компилятор прямо вставляет константу вместо a, // ибо он проверил, что все вызовы func идут с этой константой }
А, понял. На самом деле, такая частичная параметризация возможна не всегда. Если мы экспортируем функцию, то компилятор не имеет права так делать, поскольку мало ли кто её с какими параметрами будет вызывать.
Что же касается GCC, то, видимо, это косвенный эффект оптимизации шаблонов с константными параметрами, типа MyTemplate<a, 5>. В STL и Boost это просто необходимо, там такого -- вагон и маленькая тележка. Страшный язык этот современный C++, вот что я скажу.
А вот в C компиляторах я действительно никогда такого не видел.
Думаю, если эту фекцию экспортировать, то ничего подобного не будет, скорее всего компилятор даже не попытается порождать специализированную версию. Лень проверять
Видимо, да. Функция не экспортирована, помечена static, потому и возможна эта оптимизация. Но GCC реально удивляет качеством кода и помимо этого случая.
жаль, что godbolt не умеет в pdp11
любопытно посмотреть, во что развернется такой код
Код:void update(unsigned char *mem, int *bitmap, int x, int y) { for (int m = x; m < x+y; m++) { unsigned char bits = *mem++; for (int i = 0; i < 8; i++) { *bitmap++ = (bits >> i) & 1; } } }
С любовью к вам, Yandex.Direct
Размещение рекламы на форуме способствует его дальнейшему развитию
GCC даёт такой код:
Код:; --------------------------------------------------------------------------- mov R2, -(SP) mov R3, -(SP) mov R4, -(SP) mov R5, -(SP) add #-12, SP mov 30(SP), R3 clr R2 mov 32(SP), R0 add R3, R0 mov 32(SP), R1 inc R1 cmp R3, R0 bgt loc_1062 cmp R0, #-100000 bne loc_1066 loc_1062: ; CODE XREF: RAM:001052↑j mov #1, R1 loc_1066: ; CODE XREF: RAM:001060↑j ; RAM:001242↓j mov #4, R0 mov R2, R3 loc_1074: ; CODE XREF: RAM:001100↓j asl R3 dec R0 bne loc_1074 add 26(SP), R3 mov R3, 10(SP) dec R1 beq loc_1122 jmp loc_1140 ; --------------------------------------------------------------------------- loc_1122: ; CODE XREF: RAM:001114↑j add #12, SP mov (SP)+, R5 mov (SP)+, R4 mov (SP)+, R3 mov (SP)+, R2 return ; --------------------------------------------------------------------------- loc_1140: ; CODE XREF: RAM:001116↑J mov 24(SP), R0 add R2, R0 movb @R0, 7(SP) clr R0 mov #10, R3 loc_1160: ; CODE XREF: RAM:001236↓j mov R0, R4 asl R4 add 10(SP), R4 mov R4, 2(SP) clr R4 bisb 7(SP), R4 mov R4, @SP mov R0, R5 ble loc_1220 loc_1210: ; CODE XREF: RAM:001214↓j asr R4 dec R5 bne loc_1210 mov R4, @SP loc_1220: ; CODE XREF: RAM:001206↑j mov @SP, R4 bic #-2, R4 mov 2(SP), R5 mov R4, @R5 inc R0 sob R3, loc_1160 inc R2 br loc_1066 ; ---------------------------------------------------------------------------
Печально. Оптимизатор не осилил.
Вот, например:
Очевидные ошибки:Код:loc_1066: ; CODE XREF: RAM:001060↑j ; RAM:001242↓j mov #4, R0 mov R2, R3 loc_1074: ; CODE XREF: RAM:001100↓j asl R3 dec R0 bne loc_1074
1) Проигнорировано существование команды SOB. Компилятор прибит гвоздями к самым младшим моделям PDP-11? Не верится, дальше-то SOB есть.
2) Правильно этот код пишется так:
На слово короче, не использует дополнительный регистр и как минимум в 3 раза быстрее.Код:mov R2, R3 asl R3 asl R3 asl R3 asl R3
3) Чудовищным образом закодирован цикл со счётом вниз до нуля. Ну это же типовая идиома, кодогенератор должен её узнавать и вставлять шаблон.
А самое главное -- это не совсем от этой функции код :P
Вот сходу в уме декомпилировал начало функции:
- - - Добавлено - - -Код:func(int a, int b, int c, int d) { int v3 = c; int v2 = c + d; int v1 = d +1 // ЧТО ЭТО ??? if (v3 > v0 || v0 == 0100000) { v3 = v2* 16; } while (--v1 > 0) { ... } }
А в этом коде ничего, случаем, не пропало? Что там происходит с x? Зачем он нужен?
- - - Добавлено - - -
Переписал вручную на ассемблере. Если x всё-таки имеет значение, то в инициализации цикла добавляется ещё несколько команд.
Аргументы в регистрах r1..r4
- - - Добавлено - - -Код:;void update(unsigned char *mem, int *bitmap, int x, int y) { ; for (int m = x; m < x+y; m++) { ; unsigned char bits = *mem++; ; for (int i = 0; i < 8; i++) { ; *bitmap++ = (bits >> i) & 1; ; } ; } ;} update: mov r5, -(sp) mov r4, -(sp) mov r3, -(sp) mov r2, -(sp) mov r1, -(sp) cmp #0, r4 bge 0$ 1$: movb (r1)+, r0 mov #10, r5 2$: clr r3 asr r0 adc r3 mov r3, (r2)+ sob r5, 2$ sob r4, 1$ 0$: mov (sp)+, r1 mov (sp)+, r2 mov (sp)+, r3 mov (sp)+, r4 mov (sp)+, r5 ret
Таки залез на gobolt.org, и проверил, что тамошняя коллекция компялиторов думает.
Несколько родственный MSP-430
Ужас какой! Плохо у GCC с 16-битками...Код:update: PUSHM.W #1, R10 SUB.W #14, R1 MOV.W R12, 6(R1) MOV.W R13, 4(R1) MOV.W R14, 2(R1) MOV.W R15, @R1 MOV.W 2(R1), 12(R1) BR #.L2 .L5: MOV.W 6(R1), R12 MOV.W R12, R13 ADD.W #1, R13 MOV.W R13, 6(R1) MOV.B @R12, 9(R1) MOV.W #0, 10(R1) BR #.L3 .L4: MOV.W 4(R1), R10 MOV.W R10, R12 ADD.W #2, R12 MOV.W R12, 4(R1) MOV.B 9(R1), R12 MOV.W 10(R1), R13 CALL #__mspabi_srai AND.B #1, R12 MOV.W R12, @R10 ADD.W #1, 10(R1) .L3: MOV.B #7, R12 CMP.W 10(R1), R12 { JGE .L4 ADD.W #1, 12(R1) .L2: MOV.W 2(R1), R12 ADD.W @R1, R12 CMP.W R12, 12(R1) { JL .L5 NOP ADD.W #14, R1 POPM.W #1, r10 RET
Богомерзкий RISC-V:
А вот это примерно то же самое, что и я написал.Код:update(unsigned char*, int*, int, int): add a5,a2,a3 add a7,a0,a3 li a6,8 ble a5,a2,.L1 .L5: lbu a2,0(a0) mv a3,a1 addi a0,a0,1 li a5,0 .L3: sra a4,a2,a5 addi a3,a3,4 andi a4,a4,1 sw a4,-4(a3) addi a5,a5,1 bne a5,a6,.L3 addi a1,a1,32 bne a7,a0,.L5 .L1: ret
изначально этот код выглядел примерно так:
https://github.com/mamedev/mame/blob...an240.cpp#L424
Код:u32 okean240_state::screen_update_okean240(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { for (u16 y = 0; y < 256; y++) { u8 const ma = y + m_scroll; // ma must be 8-bit u16 *p = &bitmap.pix(y); for (u16 x = 0; x < 0x4000; x+=0x200) { u8 const gfx = m_p_videoram[x|ma] | m_p_videoram[x|ma|0x100]; /* Display a scanline of a character */ *p++ = BIT(gfx, 0); *p++ = BIT(gfx, 1); *p++ = BIT(gfx, 2); *p++ = BIT(gfx, 3); *p++ = BIT(gfx, 4); *p++ = BIT(gfx, 5); *p++ = BIT(gfx, 6); *p++ = BIT(gfx, 7); } } return 0; }
Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)