GCC optimalizace, zahada

Josef Štengl ok1ced na nagano.cz
Pátek Listopad 3 22:37:23 CET 2017


 > Je mozne, ze to jinak prehodi instrukce tak, ze neni dodrzeno poradi zapisu do GPIO registru, i kdyz jsou volatile?

Možné to je, ale  tom případě se jedná se o chybu kompilátoru.

Pokud je vše v pořádku, tak mě napadá rychlost zpracování. Volatie také znamená, že je použito více instrukcí a kód je 
pomalejší. Není nutná nějaká mimimální latence mezi jednotlivými operacemi?


 >>> assembler je pri optimalizaci strasnej gulas, na prvni pohled se lisi kody pouzitim str vs str.w - jaky je v tom
 >>> rozdil? Mel jsem za to, ze jen v delce kodu instrukce, kdyz jsou operace s registry... napr.:

Pokud jsem se správně díval, tak v délce instrukce a velikosti ofssetu (#...). Laický tip, že je to kvůli zarovnání, ale 
mohu se hrubě mýlit. Guláš po optimalizaci má svou, někdy úžasnou, logiku. Pokud ne, našel jste chybu nebo možnost k 
vylepšení :-)

 >>> Tusi nekdo cim to je? GPIOx->BSRR je snad definovano jako volatile uint32_t. Reseni mam ale znervoznuje me to...

No, u STM něco předpokládat, je cesta velkého omylu, jak jsem se přesvědčil. Nepředpokládejte. Podívejte se, prosím.
Pokud nebudou, tak máte hned jasno.


A assembler by nebyl? Před a po -O3? Možná něco někdo vykouká.


Mimochodem, proč používáte instrukce dbs a isb? Nechápu důvod (i když to může vyznít arogantně, jsem pouze zvědav a dráždí 
mě má nevědomost).

Dne 3.11.2017 v 20:40 Jaroslav Buchta napsal(a):
> Tak jeste jednou, ta funkce taky nebyla OK, jedine, co pri optimalizaci asi pomuze spolehlive je
> *volatile* uint32_t AH,AL,BH,BL,CH,CL;
> Je mozne, ze to jinak prehodi instrukce tak, ze neni dodrzeno poradi zapisu do GPIO registru, i kdyz jsou volatile?
> 
> 
> Dne 03.11.2017 v 20:19 Jaroslav Buchta napsal(a):
>> Jeste koukam, ze GPIO_PIN_x je uint16_t ale tohle taky nepomuze:
>>
>> #define PREPAREDOREGS(A,B,C,v)    A =  ((v)&0x01) ? (uint32_t)TFT_D0_Pin : ((uint32_t)TFT_D0_Pin) << 16;\
>>                                 C =  ((v)&0x02) ? (uint32_t)TFT_D1_Pin : ((uint32_t)TFT_D1_Pin) << 16;\
>>                                 A |= ((v)&0x04) ? (uint32_t)TFT_D2_Pin : ((uint32_t)TFT_D2_Pin) << 16;\
>>                                 B =  ((v)&0x08) ? (uint32_t)TFT_D3_Pin : ((uint32_t)TFT_D3_Pin) << 16;\
>>                                 B |= ((v)&0x10) ? (uint32_t)TFT_D4_Pin : ((uint32_t)TFT_D4_Pin) << 16;\
>>                                 B |= ((v)&0x20) ? (uint32_t)TFT_D5_Pin : ((uint32_t)TFT_D5_Pin) << 16;\
>>                                 B |= ((v)&0x40) ? (uint32_t)TFT_D6_Pin : ((uint32_t)TFT_D6_Pin) << 16;\
>>                                 A |= ((v)&0x80) ? (uint32_t)TFT_D7_Pin : ((uint32_t)TFT_D7_Pin) << 16
>>
>> Dne 03.11.2017 v 20:08 Jaroslav Buchta napsal(a):
>>> Mam kod pro plneni displeje pripojeneho osmibitove k STM32F303, bity jsou namixovany na ruzne porty tak to neni uplne 
>>> jednoduche. Po zapnuti optimalizace mi to zacne asi vynechavat nastaveni nekterych bitu, barvy jsou spatne, nefunguje 
>>> to se zakomentovanym makrem APPLYDOREGS, tak jak to je to unguje OK. Pomuze take vypnout optimalizaci nebo AH,AL... 
>>> definovat jako volatile.
>>>
>>> assembler je pri optimalizaci strasnej gulas, na prvni pohled se lisi kody pouzitim str vs str.w - jaky je v tom 
>>> rozdil? Mel jsem za to, ze jen v delce kodu instrukce, kdyz jsou operace s registry... napr.:
>>>
>>> 08001720:   str     r5, [r3, #24]
>>> 08001722:   str     r1, [r4, #24]
>>> 08001724:   str.w   r6, [r8, #24]
>>>
>>> Tusi nekdo cim to je? GPIOx->BSRR je snad definovano jako volatile uint32_t. Reseni mam ale znervoznuje me to...
>>>
>>> #pragma GCC push_options
>>> #pragma GCC optimize ("O3")
>>>
>>>
>>> #define PREPAREDOREGS(A,B,C,v)    A =  ((v)&0x01) ? TFT_D0_Pin : TFT_D0_Pin << 16;\
>>>                                 C =  ((v)&0x02) ? TFT_D1_Pin : TFT_D1_Pin << 16;\
>>>                                 A |= ((v)&0x04) ? TFT_D2_Pin : TFT_D2_Pin << 16;\
>>>                                 B =  ((v)&0x08) ? TFT_D3_Pin : TFT_D3_Pin << 16;\
>>>                                 B |= ((v)&0x10) ? TFT_D4_Pin : TFT_D4_Pin << 16;\
>>>                                 B |= ((v)&0x20) ? TFT_D5_Pin : TFT_D5_Pin << 16;\
>>>                                 B |= ((v)&0x40) ? TFT_D6_Pin : TFT_D6_Pin << 16;\
>>>                                 A |= ((v)&0x80) ? TFT_D7_Pin : TFT_D7_Pin << 16
>>>
>>> #define APPLYDOREGS(A,B,C)    *(uint32_t *)(&GPIOA->BSRR) = A;\
>>>                             *(uint32_t *)(&GPIOB->BSRR) = B;\
>>>                             *(uint32_t *)(&GPIOC->BSRR) = C
>>>
>>> //#define APPLYDOREGS(A,B,C)    GPIOA->BSRR = A;\
>>> //                            GPIOB->BSRR = B;\
>>> //                            GPIOC->BSRR = C
>>>
>>> static void TftFillData (uint16_t w, int len)
>>> {
>>>     uint32_t AH,AL,BH,BL,CH,CL;
>>>
>>>     TFT_RS_TPYA_GPIO_Port->BRR = TFT_RS_TPYA_Pin;
>>>     TFT_NCS_GPIO_Port->BRR = TFT_NCS_Pin;
>>>     PREPAREDOREGS(AH, BH, CH, 0x2c);
>>>     APPLYDOREGS(AH, BH, CH);
>>>     TFT_NWR_TPXA_GPIO_Port->BRR = TFT_NWR_TPXA_Pin;
>>>     __DSB();
>>>     __ISB();
>>>     TFT_NWR_TPXA_GPIO_Port->BSRR = TFT_NWR_TPXA_Pin;
>>>
>>>     TFT_RS_TPYA_GPIO_Port->BSRR = TFT_RS_TPYA_Pin;
>>>     PREPAREDOREGS(AH, BH, CH, (uint8_t)(w >> 8));
>>>     PREPAREDOREGS(AL, BL, CL, (uint8_t)(w & 0xff));
>>>     while (len--)
>>>     {
>>>         APPLYDOREGS(AH, BH, CH);
>>>         TFT_NWR_TPXA_GPIO_Port->BRR = TFT_NWR_TPXA_Pin;
>>>         __DSB();
>>>         __ISB();
>>>         TFT_NWR_TPXA_GPIO_Port->BSRR = TFT_NWR_TPXA_Pin;
>>>
>>>         APPLYDOREGS(AL, BL, CL);
>>>         TFT_NWR_TPXA_GPIO_Port->BRR = TFT_NWR_TPXA_Pin;
>>>         __DSB();
>>>         __ISB();
>>>         TFT_NWR_TPXA_GPIO_Port->BSRR = TFT_NWR_TPXA_Pin;
>>>     }
>>>     TFT_NCS_GPIO_Port->BSRR = TFT_NCS_Pin;
>>> }
>>>


Další informace o konferenci Hw-list