2013-03-14 2 views
7

SommarioGCC 4.7.2 problemi di ottimizzazione

sto porting USB OTG della ST Library per una scheda STM32F4 personalizzato utilizzando l'ultima versione di Sourcery CodeBench Lite toolchain (GCC braccio-nessuno-EABI 4.7.2).

Quando compilo il codice con -O0, il programma funziona correttamente. Quando compilo con -O1 o -O2 fallisce. Quando dico fallire, si ferma. No hard fault, nothing (Beh, ovviamente c'è qualcosa che sta facendo ma non ho un emulatore da usare per eseguire il debug e scoprire, mi dispiace. Il mio gestore di errori non viene chiamato).

dettagli

Sto cercando di fare una chiamata alla funzione seguente ...

void USBD_Init(USB_OTG_CORE_HANDLE *pdev, 
      USB_OTG_CORE_ID_TypeDef coreID, 
      USBD_DEVICE *pDevice,     
      USBD_Class_cb_TypeDef *class_cb, 
      USBD_Usr_cb_TypeDef *usr_cb); 

... ma non sembra farne del corpo della funzione. (È questo un sintomo di "stack-smashing"?)

Le strutture passati a questa funzione hanno le seguenti definizioni:

typedef struct USB_OTG_handle 
{ 
    USB_OTG_CORE_CFGS cfg; 
    USB_OTG_CORE_REGS regs; 
    DCD_DEV  dev; 
} 
USB_OTG_CORE_HANDLE , *PUSB_OTG_CORE_HANDLE; 

typedef enum 
{ 
    USB_OTG_HS_CORE_ID = 0, 
    USB_OTG_FS_CORE_ID = 1 
}USB_OTG_CORE_ID_TypeDef; 

typedef struct _Device_TypeDef 
{ 
    uint8_t *(*GetDeviceDescriptor)(uint8_t speed , uint16_t *length); 
    uint8_t *(*GetLangIDStrDescriptor)(uint8_t speed , uint16_t *length); 
    uint8_t *(*GetManufacturerStrDescriptor)(uint8_t speed , uint16_t *length); 
    uint8_t *(*GetProductStrDescriptor)(uint8_t speed , uint16_t *length); 
    uint8_t *(*GetSerialStrDescriptor)(uint8_t speed , uint16_t *length); 
    uint8_t *(*GetConfigurationStrDescriptor)(uint8_t speed , uint16_t *length); 
    uint8_t *(*GetInterfaceStrDescriptor)(uint8_t speed , uint16_t *length); 
} USBD_DEVICE, *pUSBD_DEVICE; 

typedef struct _Device_cb 
{ 
    uint8_t (*Init)   (void *pdev , uint8_t cfgidx); 
    uint8_t (*DeInit)  (void *pdev , uint8_t cfgidx); 
/* Control Endpoints*/ 
    uint8_t (*Setup)  (void *pdev , USB_SETUP_REQ *req); 
    uint8_t (*EP0_TxSent) (void *pdev);  
    uint8_t (*EP0_RxReady) (void *pdev); 
    /* Class Specific Endpoints*/ 
    uint8_t (*DataIn)  (void *pdev , uint8_t epnum); 
    uint8_t (*DataOut)  (void *pdev , uint8_t epnum); 
    uint8_t (*SOF)   (void *pdev); 
    uint8_t (*IsoINIncomplete) (void *pdev); 
    uint8_t (*IsoOUTIncomplete) (void *pdev); 
    uint8_t *(*GetConfigDescriptor)(uint8_t speed , uint16_t *length); 
    uint8_t *(*GetUsrStrDescriptor)(uint8_t speed ,uint8_t index, uint16_t *length); 

} USBD_Class_cb_TypeDef; 

typedef struct _USBD_USR_PROP 
{ 
    void (*Init)(void); 
    void (*DeviceReset)(uint8_t speed); 
    void (*DeviceConfigured)(void); 
    void (*DeviceSuspended)(void); 
    void (*DeviceResumed)(void); 

    void (*DeviceConnected)(void); 
    void (*DeviceDisconnected)(void);  

} 
USBD_Usr_cb_TypeDef; 

ho cercato di includere tutto il codice sorgente relativo a questo problema. Se volete vedere l'intero codice sorgente è possibile scaricarlo qui: http://www.st.com/st-web-ui/static/active/en/st_prod_software_internet/resource/technical/software/firmware/stm32_f105-07_f2_f4_usb-host-device_lib.zip

Solutions Tentato

ho provato a giocare con #pragma GCC optimize ("O0"), __attribute__((optimize("O0"))), e che dichiara alcune definizioni come volatile, ma niente ha funzionato. Preferirei semplicemente modificare il codice per farlo funzionare bene con l'ottimizzatore comunque.

Domanda

Come posso modificare il codice per renderlo bel gioco con ottimizzatore di GCC?

+2

È probabile che l'attivazione delle ottimizzazioni esponga UB nel codice. Ad esempio, il tuo codice è probabilmente sbagliato anche se le ottimizzazioni sono disabilitate, semplicemente non vedi alcun sintomo. – ildjarn

+11

Questo è un file zip da 3,7 MB, non ho idea che qualcuno possa eseguire il debug di questo per te gratuitamente. Il codice postato è solo alcune dichiarazioni e non ci dice nulla. Dovresti ridurre il codice al minimo possibile e provare a eseguirne il debug. Inoltre, hai attivato tutti gli avvisi e prestato attenzione a loro? – nos

+1

Perché nessun emulatore? Potresti voler investire $ 15 in una scheda STM32F4DISCOVERY con un JTAG incorporato. Non ne ho mai usato uno, e non so se la toolchain di Sourcery CodeBench Lite funzionerà facilmente con esso, ma dovresti essere in grado di far funzionare la libreria ST USB OTG con qualche toolchain (se non la toolchain di Sourcery) e vedi se hai qualche problema con il tuo codice che si interfaccia ad esso. –

risposta

1

Non sembra che ci sia qualcosa di sbagliato nel codice che hai mostrato, quindi questa risposta sarà più generale.

Quali sono gli errori tipici del codice "close to hardware" che funziona correttamente non ottimizzato e non riesce con livelli di ottimizzazione più elevati?

Pensa alle differenze tra -O0 e -O1/-O2: le strategie di ottimizzazione sono, tra le altre cose, lo srotolamento del loop (non sembra essere pericoloso), il tentativo di mantenere i valori nei registri il più a lungo possibile, l'eliminazione del codice morto e il riordino delle istruzioni.

l'utilizzo migliorato del registro causa in genere problemi con livelli di ottimizzazione più elevati se i registri hardware che possono cambiare in qualsiasi momento non vengono dichiarati correttamente volatile (vedere il commento di PokyBrain sopra). Il codice ottimizzato proverà a mantenere i valori nei registri il più a lungo possibile, facendo sì che il programma non noti modifiche sul lato hardware. Assicurarsi di dichiarare hardware registra volatile correttamente

codice morto eliminazione sarà probabilmente portare a problemi se avete bisogno di leggere un registro di hardware per la produzione di qualunque effetto sul l'hardware non noto al compilatore e non fai niente con il valore che hai appena letto.Questi accessi hardware potrebbero essere ottimizzati se non si dichiara la variabile utilizzata per l'accesso in lettura void correttamente (il compilatore dovrebbe emettere un avvertimento, comunque). Assicurati di lanciare manichino legge al (void)

istruzioni riordino: se avete bisogno di accedere a diversi registri hardware in una determinata sequenza per produrre i risultati desiderati e, se lo si fa attraverso i puntatori non riferibili in alcun modo in caso contrario, il compilatore è libero di riordinare le istruzioni risultanti come meglio crede (anche se i registri dell'hardwaresono correttamente dichiarati volatile). Sarà necessario rimuovere le barriere di memoria nel codice per applicare la sequenza di accesso richiesta (__asm__ __volatile__(::: "memory");). Assicurarsi di aggiungere barriere di memoria dove necessario.

Anche se improbabile, potrebbe ancora essere il caso che hai trovato un bug del compilatore. L'ottimizzazione non è un lavoro facile, soprattutto quando si avvicina all'hardware. Potrebbe valere la pena dare un'occhiata al database dei bug di gcc.

Se tutto questo non aiuta, a volte non è possibile evitare di scavare nel codice assembler generato per assicurarsi che faccia ciò che dovrebbe fare.