


Come è già stato detto nell’articolo Gcc Optimizations le ottimizzazioni sono una delle caratteristiche avanzate di GCC e sono state introdotte per limitare il tempo di compilazione, o l’uso della memoria, oppure per raggiungere un compromesso tra velocità e spazio occupato dall’eseguibile generato dalla compilazione.
Vediamo adesso un metodo alternativo per diminuire le dimensioni del codice : “thumb mode”.
Le ottimizzazioni a tempo di compilazione introducono sicuramente dei miglioramenti, ad esempio l’opzione -Os è utile per diminuire le dimensioni del codice, ma non sempre è possibile applicarle e comunque i miglioramenti sono spesso limitati. Dato che i sistemi embedded hanno molto a cuore la dimensione del codice, si sono cercate altre strade per ottenere questo obiettivo. Un altro modo per diminuire le dimensioni del codice è utilizzare la “thumb mode”, che permette la cosiddetta “compressione del codice”: praticamente questa modalità introduce un set di istruzioni alternativo che compie le stesse operazioni di quello standard ARM, ma con la differenza che è a 16 bit contro i 32 bit di quello standard. Ma come si fa a rendere un’istruzione più piccola? Si riesce ad ottenere ciò principalmente facendo sì che un’istruzione Thumb utilizzi solo i primi 8 GPRs (General Purpose Registers) invece che 15 (solo qualche istruzione, come MOV o CMP, può utilizzare tutti i registri). Ecco come si presentano la classica fase di fetch-decode-execute e quella utilizzata per la modalità Thumb:
Per essere utilizzata a dovere, un’istruzione THUMB dovrà essere convertita a runtime dal processore nella corrispondente istruzione ARM a 32 bit, quindi è necessario che il processore sia “Thumb aware”, cioè che sia provvisto di un decompressore Thumb nella pipeline.
Ecco un esempio di come convertire un’istruzione ADD da Thumb ad ARM:
Dunque qual è il vantaggio di usare istruzioni Thumb? Almeno il 35-40% di risparmio di memoria: se utilizziamo la Thumb mode sono richieste un numero maggiore di istruzioni rispetto alla modalità ARM, ma ciascuna di esse occupa la metà! La conseguenza di ciò è semplicissima: è sufficiente meno memoria per contenere lo stesso numero di istruzioni, o equivalentemente possiamo dire che nella stessa memoria entrano più istruzioni.
E il rovescio della medaglia? Deriva più che altro dal fatto che prima di eseguire un’istruzione bisogna convertirla nell’equivalente ARM, ma la perdita prestazionale è poco significativa rispetto al risparmio di spazio.
In ogni caso è possibile utilizzare la modalità “interworking”, mediante la quale si può avere insieme codice Thumb e codice ARM: in questo modo si può decidere a livello di subroutine se dare maggiore peso al risparmio di memoria oppure alle prestazioni, ad esempio il codice molto restrittivo in termini prestazionali (come gestori di eccezioni o device drivers) può utilizzare ARM (rinunciando ovviamente al risparmio di memoria), mentre la maggior parte del codice può utilizzare la Thumb mode.
Ad esempio, per utilizzare la modalità interworking in GCC, occorre chiamarlo aggiungendo l’opzione -mthumb-interwork
Ma come fa il processore a capire se una funzione va eseguita in modalità ARM o Thumb? Quando viene chiamata una funzione si ha un “branch”, cioè viene eseguita un’istruzione del tipo BX Rx (Branch and eXchange), dove Rx è l’indirizzo dove comincia il codice da eseguire. A questo punto il processore controlla il bit 0 di Rx: se esso è settato ad 1 va in Thumb mode, altrimenti va in ARM mode.
Articolo scritto da l3golas (giacomofazio@gmail.com)











maggio 15th, 2008 at 01:26
Il nuovo ARM Cortex utilizza il set di istruzioni Thumb2 che altro non e` che un misto di istruzioni a 16 e 32 bit, senza bisogno di commutare da modalita` Thumb ad ARM e viceversa. In questo modo si hanno entrambi i vantaggi: compattezza del codice e velocita` di esecuzione.
Rispondi