OSDev http://osdev.su/ |
|
Об эффективности трансляторов http://osdev.su/viewtopic.php?f=6&t=433 |
Страница 1 из 4 |
Автор: | SII [ 28 июл 2011, 14:41 ] |
Заголовок сообщения: | Об эффективности трансляторов |
Сравнил для интереса на небольшом фрагменте кода эффективность двух трансляторов под ARM (конкретнее, под ядро Cortex-M3): GCC 4.5-4.6 и KEIL 4.21 (последний, кто не в курсе, является "официальным" компилятором и средой разработки: фирму KEIL во время оно купила ARM). Исходник такой: Код: void CPU_Init(void) { RCC->CR |= RCC_CR_HSEON | RCC_CR_HSION; RCC->AHBENR = AHB_CLOCK_ENABLE; RCC->APB1ENR = APB1_CLOCK_ENABLE; RCC->APB2ENR = APB2_CLOCK_ENABLE; while ( (RCC->CR & RCC_CR_HSIRDY) == 0 ) ; RCC->CFGR = RCC_CFGR_MCO_NOCLOCK | RCC_CFGR_USBPRE_1_5 | RCC_CFGR_PLLMUL9 | RCC_CFGR_PLLXTPRE_HSE | RCC_CFGR_PLLSRC_HSE | RCC_CFGR_ADCPRE_DIV6 | RCC_CFGR_PPRE2_DIV1 | RCC_CFGR_PPRE1_DIV2 | RCC_CFGR_HPRE_DIV1 | RCC_CFGR_SW_HSI; while ( (RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI ) ; FLASH->ACR = FLASH_ACR_LATENCY_2 | FLASH_ACR_PRFTBE; while ( (RCC->CR & RCC_CR_HSERDY) == 0 ) ; RCC->CR |= RCC_CR_PLLON; while ( (RCC->CR & RCC_CR_PLLRDY) == 0 ) ; RCC->CFGR = RCC_CFGR_MCO_NOCLOCK | RCC_CFGR_USBPRE_1_5 | RCC_CFGR_PLLMUL9 | RCC_CFGR_PLLXTPRE_HSE | RCC_CFGR_PLLSRC_HSE | RCC_CFGR_ADCPRE_DIV6 | RCC_CFGR_PPRE2_DIV1 | RCC_CFGR_PPRE1_DIV2 | RCC_CFGR_HPRE_DIV1 | RCC_CFGR_SW_PLL; while ( (RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL ) ; GPIOA->CRH = GPIOA_CRH; GPIOA->CRL = GPIOA_CRL; GPIOB->CRH = GPIOB_CRH; GPIOB->CRL = GPIOB_CRL; GPIOC->CRH = GPIOC_CRH; GPIOC->CRL = GPIOC_CRL; GPIOD->CRL = GPIOD_CRL; AFIO->MAPR = AFIO_MAPR; } Все переменные -- это "неустойчивые" (volatile) структуры с фиксированными адресами, которые являются на самом деле блоками регистров микроконтроллеров семейства STM32F10xxx. Объединение регистров устройств в структуры объясняется особенностью архитектуры ARM: у неё нет непосредственной адресации памяти (чего-то типа MOV [адрес], EAX для IA-32), и любое обращение к памяти выполняется с использованием базового адреса в регистре (например, STR R1, [R5, #12] -- записать содержимое регистра 1 в память по адресу, равному сумме регистра 5 и константы 12). В обоих случаях использовалась оптимизация -O2 (означающая одно и то же: почти максимальную оптимизацию, за исключением, главным образом, инлайнов; -О3 в данном случае даёт такой же результат). KEIL выдал такой код: Код: KERNEL:00000000 KERNEL_0 ; Alternative name is 'CPU_Init' KERNEL:00000000 LDR R0, =0x40021000 KERNEL:00000002 LDR R1, [R0] KERNEL:00000004 ORR.W R1, R1, #0x10001 KERNEL:00000008 STR R1, [R0] KERNEL:0000000A MOVS R1, #0x15 KERNEL:0000000C STR R1, [R0,#0x14] KERNEL:0000000E MOVS R1, #0 KERNEL:00000010 STR R1, [R0,#0x1C] KERNEL:00000012 MOVW R1, #0x403D KERNEL:00000016 STR R1, [R0,#0x18] KERNEL:00000018 KERNEL:00000018 loc_18 ; CODE XREF: KERNEL:0000001Cj KERNEL:00000018 LDR R1, [R0] KERNEL:0000001A LSLS R1, R1, #0x1E KERNEL:0000001C BPL loc_18 KERNEL:0000001E LDR R1, =0x1D8400 KERNEL:00000020 STR R1, [R0,#4] KERNEL:00000022 KERNEL:00000022 loc_22 ; CODE XREF: KERNEL:00000028j KERNEL:00000022 LDR R1, [R0,#4] KERNEL:00000024 TST.W R1, #0xC KERNEL:00000028 BNE loc_22 KERNEL:0000002A LDR R2, =0x40022000 KERNEL:0000002C MOVS R1, #0x12 KERNEL:0000002E STR R1, [R2] KERNEL:00000030 KERNEL:00000030 loc_30 ; CODE XREF: KERNEL:00000034j KERNEL:00000030 LDR R1, [R0] KERNEL:00000032 LSLS R1, R1, #0xE KERNEL:00000034 BPL loc_30 KERNEL:00000036 LDR R1, [R0] KERNEL:00000038 ORR.W R1, R1, #0x1000000 KERNEL:0000003C STR R1, [R0] KERNEL:0000003E KERNEL:0000003E loc_3E ; CODE XREF: KERNEL:00000042j KERNEL:0000003E LDR R1, [R0] KERNEL:00000040 LSLS R1, R1, #6 KERNEL:00000042 BPL loc_3E KERNEL:00000044 LDR R1, =0x1D8400 KERNEL:00000046 ADDS R1, R1, #2 KERNEL:00000048 STR R1, [R0,#4] KERNEL:0000004A KERNEL:0000004A loc_4A ; CODE XREF: KERNEL:00000052j KERNEL:0000004A LDR R1, [R0,#4] KERNEL:0000004C UBFX.W R1, R1, #2, #2 KERNEL:00000050 CMP R1, #2 KERNEL:00000052 BNE loc_4A KERNEL:00000054 LDR R1, =0x40010804 KERNEL:00000056 LDR R0, =0x444444B4 KERNEL:00000058 STR R0, [R1] KERNEL:0000005A SUBS R1, R1, #4 KERNEL:0000005C LDR R0, =0xB4B44404 KERNEL:0000005E STR R0, [R1] KERNEL:00000060 LDR R1, =0x40010C04 KERNEL:00000062 MOV.W R0, #0x33333333 KERNEL:00000066 STR R0, [R1] KERNEL:00000068 SUBS R1, R1, #4 KERNEL:0000006A MOV.W R0, #0x44444444 KERNEL:0000006E STR R0, [R1] KERNEL:00000070 LDR R1, =0x40011000 KERNEL:00000072 STR R0, [R1,#4] KERNEL:00000074 STR R0, [R1] KERNEL:00000076 LDR R1, =0x40011400 KERNEL:00000078 STR R0, [R1] KERNEL:0000007A LDR R1, =0x40010000 KERNEL:0000007C MOV.W R0, #0x4000 KERNEL:00000080 STR R0, [R1,#4] KERNEL:00000082 BX LR KERNEL:00000084 А у GCC получилось следующее: Код: .text:00000000 cpu__cpu_init .text:00000000 PUSH {R4-R6} .text:00000002 MOV R3, 0x40021000 .text:0000000A LDR R2, [R3] .text:0000000C MOV R1, R3 .text:0000000E ORR.W R2, R2, #0x10001 .text:00000012 STR R2, [R3] .text:00000014 MOVS R2, #0x15 .text:00000016 STR R2, [R3,#0x14] .text:00000018 MOVS R2, #0 .text:0000001A STR R2, [R3,#0x1C] .text:0000001C MOVW R2, #0x403D .text:00000020 STR R2, [R3,#0x18] .text:00000022 .text:00000022 loc_22 ; CODE XREF: cpu__cpu_init+30j .text:00000022 LDR R2, [R1] .text:00000024 MOV.W R3, #0x1000 .text:00000028 TST.W R2, #2 .text:0000002C MOVT.W R3, #0x4002 .text:00000030 BEQ loc_22 .text:00000032 LDR R0, =unk_114 .text:00000034 MOV R2, R3 .text:00000036 LDR R1, [R0] .text:00000038 STR R1, [R3,#4] .text:0000003A .text:0000003A loc_3A ; CODE XREF: cpu__cpu_init+42j .text:0000003A LDR R3, [R2,#4] .text:0000003C UBFX.W R3, R3, #2, #2 .text:00000040 CMP R3, #0 .text:00000042 BNE loc_3A .text:00000044 MOVS R1, #2 .text:00000046 MOVS R2, #0 .text:00000048 BFI.W R2, R1, #0, #3 .text:0000004C BFI.W R2, R3, #3, #1 .text:00000050 ORR.W R2, R2, #0x10 .text:00000054 MOV.W R12, #0x2000 .text:00000058 BFI.W R2, R3, #5, #1 .text:0000005C MOVT.W R12, #0x4002 .text:00000060 MOV.W R1, #0x1000 .text:00000064 STR.W R2, [R12] .text:00000068 MOVT.W R1, #0x4002 .text:0000006C .text:0000006C loc_6C ; CODE XREF: cpu__cpu_init+7Aj .text:0000006C LDR R2, [R1] .text:0000006E MOV.W R3, #0x1000 .text:00000072 TST.W R2, #0x20000 .text:00000076 MOVT.W R3, #0x4002 .text:0000007A BEQ loc_6C .text:0000007C LDR R2, [R3] .text:0000007E MOV R1, R3 .text:00000080 ORR.W R2, R2, #0x1000000 .text:00000084 STR R2, [R3] .text:00000086 .text:00000086 loc_86 ; CODE XREF: cpu__cpu_init+94j .text:00000086 LDR R2, [R1] .text:00000088 MOV.W R3, #0x1000 .text:0000008C TST.W R2, #0x2000000 .text:00000090 MOVT.W R3, #0x4002 .text:00000094 BEQ loc_86 .text:00000096 LDR R1, [R0,#4] .text:00000098 MOV R2, R3 .text:0000009A STR R1, [R3,#4] .text:0000009C .text:0000009C loc_9C ; CODE XREF: cpu__cpu_init+A4j .text:0000009C LDR R3, [R2,#4] .text:0000009E UBFX.W R3, R3, #2, #2 .text:000000A2 CMP R3, #2 .text:000000A4 BNE loc_9C .text:000000A6 MOV.W R12, #0x800 .text:000000AA MOVW R6, #0x44B4 .text:000000AE MOVW R5, #0x4404 .text:000000B2 MOVT.W R12, #0x4001 .text:000000B6 MOV.W R0, #0xC00 .text:000000BA MOV.W R1, #0x1000 .text:000000BE MOV.W R4, #0x1400 .text:000000C2 MOVT.W R6, #0x4444 .text:000000C6 MOVT.W R5, #0xB4B4 .text:000000CA STR.W R6, [R12,#4] .text:000000CE MOV.W R2, #0x44444444 .text:000000D2 STR.W R5, [R12] .text:000000D6 MOVT.W R0, #0x4001 .text:000000DA MOVT.W R1, #0x4001 .text:000000DE MOVS R3, #0 .text:000000E0 MOVT.W R4, #0x4001 .text:000000E4 MOV.W R12, #0x33333333 .text:000000E8 STR.W R12, [R0,#4] .text:000000EC MOVT.W R3, #0x4001 .text:000000F0 STR R2, [R0] .text:000000F2 STR R2, [R1,#4] .text:000000F4 STR R2, [R1] .text:000000F6 STR R2, [R4] .text:000000F8 MOV.W R2, #0x4000 .text:000000FC STR R2, [R3,#4] .text:000000FE LDR R2, [R3,#4] .text:00000100 STR R2, [R3,#4] .text:00000102 POP {R4-R6} .text:00000104 BX LR .text:00000106 Налицо очень большая разница в длине кода: 130 байтов у транслятора KEIL и 262 байта у GCC. Если заняться анализом кода, то можно выделить четыре глупости, совершаемые GCC: 1) Он плохо помнит содержимое регистров процессора. Например, загрузив в самом начале базовый адрес RCC в регистр 3 (смещение 2), он почти сразу пересылает его в регистр 1 (смещение C), вместо того, чтобы продолжать пользоваться регистром 3. Аналогичным образом он поступает и дальше. Как следствие, ему не хватило рабочих регистров (R0-R3, R12), и он сохранил в стеке ещё три регистра (R4-R6). 2) Он вставляет фактически бессмысленные команды внутрь циклов (смещения 22, 6C, 86 -- MOVы, которые надо было бы вынести из циклов). 3) Иногда он зачем-то вновь загружает эти значения и сразу же опять записывает (пара LDR-STR по смещению FE-100). Помимо раздувания кода, это может привести вообще к некорректной работе программы: это же не обычные ячейки памяти, а регистры устройств. При каких условиях генерируется подобный код, пока неясно. 4) Наконец, он банально глупо грузит константы, собирая их по кусочкам с помощью MOVов (со смещения A6) вместо прямой загрузки из памяти с помощью LDR, как это делает KEIL (со смещения 54). В итоге получаем жутко раздутый код (в 2 раза длиннее, чем надо), да к тому же потенциально некорректно выполняющийся из-за п. 3 (в данном конкретном случае к неприятным последствиям это не приведёт, но...). В общем, похоже, не зря KEIL стоит больших денег (несколько тыщ евро): код корректный, заметно более качественный, плюс в комплекте IDE (пускай и не верх совершенства, но у GCC вообще ничего нет, надо использовать сторонние вещи), всякие там заголовочные файлы под различные контроллеры... |
Автор: | SII [ 28 июл 2011, 14:56 ] |
Заголовок сообщения: | Re: Об эффективности трансляторов |
Вдогонку к предыдущему. По моей просьбе Grindars странслировал этот же код с использованием CLANG или как там его. Получилось вот что: Код: 0: f241 0000 movw r0, #4096 ; 0x1000 4: 2215 movs r2, #21 6: f2c4 0002 movt r0, #16386 ; 0x4002 a: 6801 ldr r1, [r0, #0] c: f041 1101 orr.w r1, r1, #65537 ; 0x10001 10: 6001 str r1, [r0, #0] 12: f241 0114 movw r1, #4116 ; 0x1014 16: f2c4 0102 movt r1, #16386 ; 0x4002 1a: 600a str r2, [r1, #0] 1c: f241 011c movw r1, #4124 ; 0x101c 20: 2200 movs r2, #0 22: f2c4 0102 movt r1, #16386 ; 0x4002 26: 600a str r2, [r1, #0] 28: f241 0118 movw r1, #4120 ; 0x1018 2c: f244 023d movw r2, #16445 ; 0x403d 30: f2c4 0102 movt r1, #16386 ; 0x4002 34: 600a str r2, [r1, #0] 36: 6801 ldr r1, [r0, #0] 38: f011 0f02 tst.w r1, #2 3c: d0fb beq.n 36 <CPU_Init+0x36> 3e: f241 0104 movw r1, #4100 ; 0x1004 42: f248 4200 movw r2, #33792 ; 0x8400 46: f2c4 0102 movt r1, #16386 ; 0x4002 4a: f2c0 021d movt r2, #29 4e: 600a str r2, [r1, #0] 50: 680a ldr r2, [r1, #0] 52: f012 0f0c tst.w r2, #12 56: d1fb bne.n 50 <CPU_Init+0x50> 58: f242 0200 movw r2, #8192 ; 0x2000 5c: 2312 movs r3, #18 5e: f2c4 0202 movt r2, #16386 ; 0x4002 62: 6013 str r3, [r2, #0] 64: 6802 ldr r2, [r0, #0] 66: f412 3f00 tst.w r2, #131072 ; 0x20000 6a: d0fb beq.n 64 <CPU_Init+0x64> 6c: 6802 ldr r2, [r0, #0] 6e: f042 7280 orr.w r2, r2, #16777216 ; 0x1000000 72: 6002 str r2, [r0, #0] 74: 6802 ldr r2, [r0, #0] 76: f012 7f00 tst.w r2, #33554432 ; 0x2000000 7a: d0fb beq.n 74 <CPU_Init+0x74> 7c: f248 4002 movw r0, #33794 ; 0x8402 80: f2c0 001d movt r0, #29 84: 6008 str r0, [r1, #0] 86: 6808 ldr r0, [r1, #0] 88: f000 000c and.w r0, r0, #12 8c: 2808 cmp r0, #8 8e: d1fa bne.n 86 <CPU_Init+0x86> 90: f640 0004 movw r0, #2052 ; 0x804 94: f244 41b4 movw r1, #17588 ; 0x44b4 98: f2c4 0001 movt r0, #16385 ; 0x4001 9c: f2c4 4144 movt r1, #17476 ; 0x4444 a0: 6001 str r1, [r0, #0] a2: f640 0000 movw r0, #2048 ; 0x800 a6: f244 4104 movw r1, #17412 ; 0x4404 aa: f2c4 0001 movt r0, #16385 ; 0x4001 ae: f2cb 41b4 movt r1, #46260 ; 0xb4b4 b2: 6001 str r1, [r0, #0] b4: f640 4004 movw r0, #3076 ; 0xc04 b8: f04f 3133 mov.w r1, #858993459 ; 0x33333333 bc: f2c4 0001 movt r0, #16385 ; 0x4001 c0: 6001 str r1, [r0, #0] c2: f640 4100 movw r1, #3072 ; 0xc00 c6: f04f 3044 mov.w r0, #1145324612 ; 0x44444444 ca: f2c4 0101 movt r1, #16385 ; 0x4001 ce: 6008 str r0, [r1, #0] d0: f241 0104 movw r1, #4100 ; 0x1004 d4: f2c4 0101 movt r1, #16385 ; 0x4001 d8: 6008 str r0, [r1, #0] da: f241 0100 movw r1, #4096 ; 0x1000 de: f2c4 0101 movt r1, #16385 ; 0x4001 e2: 6008 str r0, [r1, #0] e4: f241 4100 movw r1, #5120 ; 0x1400 e8: f2c4 0101 movt r1, #16385 ; 0x4001 ec: 6008 str r0, [r1, #0] ee: 2004 movs r0, #4 f0: f44f 4180 mov.w r1, #16384 ; 0x4000 f4: f2c4 0001 movt r0, #16385 ; 0x4001 f8: 6001 str r1, [r0, #0] fa: 4770 bx lr Код вроде корректный и короче GCCшного, хотя и существенно больше KEILовского. |
Автор: | SII [ 28 июл 2011, 16:14 ] |
Заголовок сообщения: | Re: Об эффективности трансляторов |
Поэкскрементировал тут и получил следующие результаты... 1) Неверный код (загрузка только что записанного значения и его повторная запись) генерируется при любой оптимизации, кроме -O0, т.е. вызван какой-то ошибкой в оптимизаторе. Обойти эту генерацию можно, если нужную константу сначала присвоить промежуточной переменной, а потом выполнить присваивание этой переменной "неустойчивому" полю, т.е. вместо Код: Volatile_Reg = const; писать примерно такое: Код: temp = const; Volatile_Reg = temp; 2) Наиболее компактный (176 байт) и одновременно быстрый код генерируется при оптимизации -Os, т.е. по размеру. Кстати говоря, алгоритмически одинаковый код на Си и Аде даёт одинаковый машинный код, но это как раз вполне ожидаемо: оптимизатор и кодогенератор же у них общий, различаются только фронт-энды. |
Автор: | Yoda [ 28 июл 2011, 22:46 ] |
Заголовок сообщения: | Re: Об эффективности трансляторов |
SII писал(а): Налицо очень большая разница в длине кода: 130 байтов у транслятора KEIL и 262 байта у GCC. Если заняться анализом кода, то можно выделить четыре глупости, совершаемые GCC... В общем, похоже, не зря KEIL стоит больших денег (несколько тыщ евро): код корректный, заметно более качественный... А я всегда говорил, — не всё то благо, что GNUсно распространяемое. Самые качественные продукты обычно платные. |
Автор: | SII [ 28 июл 2011, 22:50 ] |
Заголовок сообщения: | Re: Об эффективности трансляторов |
Yoda писал(а): А я всегда говорил, — не всё то благо, что GNUсно распространяемое. Самые качественные продукты обычно платные. Вот-вот. По крайней мере, если речь идёт о действительно крупных и сложных продуктах. |
Автор: | SII [ 29 июл 2011, 02:12 ] |
Заголовок сообщения: | Re: Об эффективности трансляторов |
А теперь наткнулся на настолько неверную кодогенерацию, что трансляция вообще не проходит: валится ассемблер: C:\TEMP\ccldORbK.s: Assembler messages: C:\TEMP\ccldORbK.s:64: Error: immediate value out of range -- `movteq r7,-4096' C:\TEMP\ccldORbK.s:66: Error: incorrect condition in IT block -- `bfcne r6,#16,#16' C:\TEMP\ccldORbK.s:68: Error: instruction not allowed in IT block -- `and r2,r2,#8192' C:\TEMP\ccvXA4Sd.s: Assembler messages: C:\TEMP\ccvXA4Sd.s:62: Error: immediate value out of range -- `movteq r5,-4096' C:\TEMP\ccvXA4Sd.s:64: Error: incorrect condition in IT block -- `bfcne r4,#16,#16' C:\TEMP\ccvXA4Sd.s:66: Error: IT falling in the range of a previous IT block -- `ite eq' C:\TEMP\ccvXA4Sd.s:67: Error: thumb conditional instruction should be in IT block -- `streq r5,[r3,#16]' C:\TEMP\ccvXA4Sd.s:69: Error: thumb conditional instruction should be in IT block -- `strne r4,[r3,#16]' В общем, качество GCC как транслятора, мягко говоря, очень и очень невысокое со всех точек зрения. Одно слово: опенсорц. Жаль, под АРМ коммерческие компиляторы -- исключительно Си/Си++, Паскаля/Модулы/Оберона/Ады нет... |
Автор: | SII [ 31 июл 2011, 01:53 ] |
Заголовок сообщения: | Re: Об эффективности трансляторов |
Вручную закодировал ту же процедурку на ассемблере. Вместе с константами в памяти заняла 154 байта, у Кейла -- 160 (размер выше, равный 130 байтам, был дан без учёта констант). Выигрыш, как видим, есть, но незначительный. Правда, и сам код тупо прямолинейный; в более сложных случаях ручное программирование даёт больше выгоды (естественно, ценой затрат большего времени). |
Автор: | Himik [ 31 июл 2011, 09:57 ] |
Заголовок сообщения: | Re: Об эффективности трансляторов |
GCC под x86 оптимизирует гораздо лучше. Может быть проблема в кросскомпиляции - не может один оптимизатор идеально подходить под все процессоры. Софтина, заточенная под конкретную архитектуру всегда лучше. |
Автор: | pavia [ 31 июл 2011, 11:57 ] |
Заголовок сообщения: | Re: Об эффективности трансляторов |
По моему я где-то читал. Что официально GCC под arm не оптимизирует. |
Автор: | SII [ 31 июл 2011, 14:29 ] |
Заголовок сообщения: | Re: Об эффективности трансляторов |
pavia писал(а): По моему я где-то читал. Что официально GCC под arm не оптимизирует. Если на то пошло, оптимизация делится на два вида: машинно-независимую и машинно-зависимую. Даже если вторая напрочь отсутствует, первая должна работать в любом случае. Ну и, кроме того, никакое отсутствие оптимизации не может порождать неверный код. Я же убедился, что без оптимизации (ключ -O0) GCC выдаёт корректный, хотя и очень неэффективный код, а вот при включении любой оптимизации код становится некорректным для некоторых случаев (если обращение идёт к регистрам устройств, а не к обычной памяти), причём мне удалось-таки подобрать способ, как обойти эту неверную генерацию. В общем, дело не в этом. Himik писал(а): GCC под x86 оптимизирует гораздо лучше. Может быть проблема в кросскомпиляции - не может один оптимизатор идеально подходить под все процессоры. Софтина, заточенная под конкретную архитектуру всегда лучше. Абсолютно согласен. Просто данный пример развеивает сразу два мифа, бытующих у поклонников свободного ПО: 1) основное инструментальное средство "борцов за свободу", коим является GCC, -- эффективное решение на любой платформе (как видим, оно откровенно неэффективно даже на одной из самых популярных и распространённых платформ); 2) Линух -- эффективная ОС (поскольку она компилируется с помощью GCC, то, даже без учёта "личных качеств" самой системы "в вакууме", она будет неэффективной на любой платформе, для которой GCC порождает плохой код). Ну а как итог: я лишний раз убедился, что инструментальное ПО должно затачиваться под конкретную платформу. Хотя нельзя сказать, что подход GCC абсолютно неверен, однако его реализация, как обычно, далека даже от "тройки". Действительно, можно разделить фронт-энд (транслятор с исходного языка в промежуточное представление), машинно-независимый оптимизатор (работающий только с этим промежуточным представлением) и бэк-энд (машинно-зависимый оптимизатор и генератор объектного/ассемблерного кода), получив при этом хорошие результаты (поскольку эффективные трансляторы, по сути, так и работают, только "линия раздела" находится внутри них), но делать это надо аккуратно, уделяя большое внимание деталям, а также тщательно документируя всё и вся. В случае с GCC этого нет: его исходники просто ужасны, документация крайне неполна и т.д. Неудивительно, что на выходе имеем столь низкое качество. Ну а его разработчики, вместо того, чтобы доводить его до ума, всё впихивают и впихивают новые прибамбасы (зачем, например, какая-то оптимизация циклов graphite, если у них оптимизатор впихивает в циклы лишние команды, которые однозначно должны находиться вне цикла? лучше б доделали простые виды оптимизации, чем выдумывать сложные). Кроме того, похоже, GCC никто толком не тестирует ни на чём хоть малость нестандартном... |
Страница 1 из 4 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group http://www.phpbb.com/ |