EMB_81

COMPILER | SOFTWARE 61 EMBEDDED SETTEMBRE Esistono a loro volta ottimizzazioni che migliorano sia le dimensioni che la velocità del programma, ossia che rendono il programma più compatto e più veloce. Tuttavia, esistono anche metodi che agiscono in senso opposto, come per esempio alcune ottimizzazioni che riducono le dimensioni del codice a scapito della velo- cità o viceversa. Vediamo di dare un’occhiata ad alcuni esempi. Esempi di ottimizzazioni del compilatore Le ottimizzazioni tipiche e ben note a livello di sorgente sono ad esempio il “loop unrolling” o il “function inli- ning”. Entrambi puntano ad aumentare la velocità del programma a scapito di un increemento delle dimensio- ni del codice. Un’altra ottimizzazione comune è l’”Eliminazione del- le Sotto-espressioni Comuni” (Common Subexpression Elimination - CSE), in cui diversi calcoli ridondanti che si producono in ciascun percorso di esecuzione del programma vengono sosti- tuiti da un singolo calcolo (Fig. 1). Un algoritmo più recente e più aggressivo del CSE è l’”Eliminazione Parziale della Ridondanza” (Partial Redundancy Elimi- nation - PRE). Questa ottimizzazione richiede come mini- mo che il calcolo sia ridondante solo in un percorso di esecuzione ed è anche in grado di gestire i loop del programma. Le ottimiz- zazioni CSE e PRE sono anche di aiuto in presenza di numerosi calcoli ridondanti di memoria. Quindi, per esempio arr [i] + arr [i + 3] può essere convertito in ptr = arr + i; ptr [0] + ptr [3]; che può far risparmiare una o più istruzioni. Altre otti- mizzazioni ben note sono, ad esempio, l’”Eliminazione del Codice Morto” (Dead Code Elimination - DCE), in cui il compilatore tenta di eliminare parti di codice che non hanno rilevanza per il risultato di una funzione, o la “Propagazione Costante”. Con l’ottimizzazione con “Migrazione del Codice duran- te il Funzionamento” (Busy Code Motion - BCM), la di- mensione complessiva del programma viene ridotta dal compilatore che cerca di concentrare in un solo blocco istruzioni simili presenti in più blocchi (Fig. 2). Que- sta idea viene utilizzata anche nell’ottimizzazione del linker, descritta più avanti. Nell’ottimizzazione “sche- duling delle istruzioni” dipendente dal target, si sfrutta la conoscenza dello scheduling delle istruzioni presenti nella pipeline della CPU. Mentre viene eseguita un’istruzione della pipeline, l’istruzione successiva inizia già ad essere eseguita. E quando l’istruzione successiva deve attendere il risultato di À nella pipeline. Per quanto possibile, il com- pilatore ordina le istruzioni in modo che gli À @ - ramente possibile. Un’altra area di ottimizzazione riguarda la vettorizzazione, per cui di solito si opera una distinzione tra vettorizzazione manua- le e automatica. Negli ultimi anni questo settore ha subito numerosi cambiamenti, Fig. 1 – Eliminazione delle Sotto-espressioni Comuni Fig. 2 – Migrazione del codice durante il funzionamento (BCM)

RkJQdWJsaXNoZXIy Mzg4NjYz