Implementare tre passi LLVM (dentro lo stesso passo LocalOpts già scritto durante il LAB 2) che realizzano le seguenti ottimizzazioni locali:
-
Algebraic Identity
$x + 0 = 0 + x \Rightarrow x$ $x \times 1 = 1 \times x \Rightarrow x$
-
Strength Reduction (più avanzato)
$15 \times x = x \times 15 \Rightarrow (x << 4) – x$ $y = x / 8 ⇒ y = x >> 3$
-
Multi-Instruction Optimization
$a = b + 1, c = a − 1 ⇒ a = b + 1, c = b$
Consideriamo i seguenti problemi di Dataflow Analysis:
- Very Busy Expressions
- Dominator Analysis
- Constant Propagation
Per ognuno di essi…
- Derivare una formalizzazione riempiendo lo specchietto coi parametri adeguati
Implementare un passo di Loop-Invariant Code Motion (LICM) che sposti al di fuori del loop le istruzioni non dipendenti dal loop stesso.
L'algoritmo si suddivide nei seguenti passaggi:
- Dato l'insieme di nodi di un loop, calcolare le reaching definitions.
- Determinare le istruzioni loop-invariant, definite tali se entrambi gli operandi lo sono a loro volta.
Un operando è loop-invariant se:
- è una costante
- è un argomento di funzione
- la sua reaching definition non è contenuta nel loop ed è a sua volta loop-invariant
- Calcolare i dominatori (dominance tree)
- Trovare le uscite del loop, ovvero i successori al di fuori del loop
- Determinare la presenza di istruzioni candidate per la Code Motion:
- istruzioni loop invariant
- l’istruzione (la definizione) domina tutti gli usi (sottointeso nel SSA)
- il basic block contenente l'istruzione domina tutte le uscite del loop OPPURE la variabile definita dall'istruzione è dead all'uscita del loop, ovvero non ha usi
- Spostare le istruzioni trovate nel blocco preheader.
Implementare un passo di Loop Fusion che sia in grado di fondere due loop se verificate le seguenti condizioni:
-
$L_j$ e$L_k$ devono essere adiacenti- Non ci devono essere statements da eseguire tra la fine di
$L_j$ e l'inizio di$L_k$ . Garanzia che tutte le volte che esegue il primo dei due eseguirà anche il secondo; dal punto di vista di dominanza non avrebbe senso fondere i due loop altrimenti.
- Non ci devono essere statements da eseguire tra la fine di
-
$L_j$ e$L_k$ devono iterare lo stesso numero di volte -
$L_j$ e$L_k$ devono essere control flow equivalenti- Se
$L_j$ esegue, anche$L_k$ deve eseguire, o viceversa
- Se
- Non ci devono essere dipendenze a distanza negativa
- una distanza negativa accade tra
$L_j$ e$L_k$ ($L_j$ prima di$L_k$ ), quando ad un’iterazione$m$ ,$L_k$ usa un valore che è calcolato da$L_j$ ad una iterazione futura$m+n$ (con$n>0$ )
- una distanza negativa accade tra
Una volta verificate tutte queste condizioni, si può trasformare il codice. In particolare:
- Si devono modificare gli usi della induction variable nel body del loop 2 con quelli della induction variable del loop 1 (in SSA sono due variabili diverse)
- Si deve modificare il CFG perché il body del loop 2 sia agganciato a seguito del body del loop 1 nel loop 1