2012-04-18 22 views
8

E 'facile vedere che:Le operazioni logiche su più operazioni modulo sono ottimizzate?

(i % 3 == 0) && (i % 5 == 0) 

può essere semplificata:

(i % 15 == 0) 

Eppure esaminando l'output di GCC, sembra che questo non è fatto anche ad alti livelli di ottimizzazione.

Alcuni compilatori eseguono questo tipo di ottimizzazioni oppure esiste una buona ragione per cui questi due test non sono semanticamente equivalenti?

Edit: In risposta a chi dice che questo è un caso frangia, il seguente è un caso simile:

(i < 3) && (i < 5) 

Qualsiasi numero minore di 3, deve essere sempre inferiore a 5. Secondo test è ridondante.

Vorrei anche aggiungere quanto segue in risposta alla risposta che il compilatore non può sapere se l'ambiente è interessato ... Guardate questo codice:

void foo(void) 
{ 
    int i; 
    for (i = 0; i <= 10; i++) 
    { 
     if (i > 20) 
     { 
      puts("Hi"); 
     } 
    } 
} 

funzione intero si riduce a "repz ret "di GCC con -O2. È molto più complesso di qualsiasi cosa di cui sto parlando.

+1

la mia ipotesi è di garantire la valutazione del cortocircuito ... – Anycorn

+0

I compilatori in generale controllano confronti multipli sulla stessa variabile per l'ottimizzazione? Sembra un caso marginale ... – trutheality

+2

@Anycorn, stai dicendo che la valutazione di 'i' può avere effetti collaterali, e il compilatore non fa se lo fa o no? – ikegami

risposta

5

Ignora tutte le risposte stupide sostenendo che questo è terribilmente difficile/impossibile da fare per un compilatore. Non vedo ragioni per cui sarebbe difficile, ma presumibilmente nessuno pensava di farlo o pensava che sarebbe stato sufficientemente importante da ottimizzare. Se vuoi una risposta migliore di questa devi segnalarla sul bug tracker di GCC come richiesta di miglioramento e vedere cosa dicono gli sviluppatori.

+0

Penso che tu intenda * in * sufficientemente. Ma sì, sono d'accordo con te. – Matt

+1

La mia grammatica era corretta. Il soggetto è ancora "nessuno", che fornisce la semantica negativa. :-) –

3

Il tuo esempio è piuttosto semplice ed è infatti facile da condensare in un'unica operazione. Il caso generale di una dichiarazione come questa, però, non è così semplice. Prendiamo il seguente, ad esempio:

((++i) % 3 == 0) && ((++i) % 5 == 0) 

Questa variazione non può essere semplificata fino a una singola operazione di modulo con la stessa facilità (so che questa dichiarazione ha ogni sorta di altri problemi con esso, ma il punto è che il problema isn' t semplice quando stai usando qualcosa di diverso da una semplice variabile di riferimento). Generalmente i compilatori non vedranno che il tuo caso riguarda solo variabili semplici e lo ottimizza in modo diverso rispetto al caso generale; cercano di mantenere le ottimizzazioni coerenti e prevedibili quando possibile.

Aggiornamento: I casi aggiuntivi che sono stati aggiunti alla tua domanda caduta in una classe completamente diversa di ottimizzazione di snippet di codice originale. Sono entrambi ottimizzati via perché sono codice irraggiungibile e possono essere dimostrati come tali in fase di compilazione. La tua domanda originale riguardava la riscrittura di due operazioni in un'unica operazione equivalente che è unica rispetto all'originale. I due frammenti che hai aggiunto non riscrivono il codice esistente, rimuovono solo il codice che non può mai essere eseguito. I compilatori sono in genere molto bravi a identificare e rimuovere il codice morto.

L'ottimizzazione che si sta cercando è una forma di riduzione della forza matematica . La maggior parte dei compilatori offre un certo livello di ottimizzazioni MSR, anche se il loro dettaglio varia in base al compilatore e alle funzionalità della piattaforma di destinazione. Ad esempio, un compilatore che punta a un'architettura CPU che non ha un'istruzione modulo (che deve invece essere utilizzata una funzione di libreria potenzialmente lunga) può ottimizzare dichiarazioni come queste in modo più aggressivo. Se la CPU di destinazione ha il supporto del modulo hardware, lo scrittore del compilatore potrebbe ritenere che le due o tre istruzioni salvate siano un vantaggio troppo piccolo per meritare il tempo e gli sforzi necessari per implementare e testare i miglioramenti dell'ottimizzazione. Ho visto questo in passato con certe operazioni che possono essere fatte in una singola istruzione su una CPU x86 (per esempio) ma richiederebbe dozzine di istruzioni su una CPU RISC.

+0

Non sono d'accordo. I compilatori sono bravi a trovare sottoespressioni comuni (di cui semplicemente "i" è un caso banale) e ottimizzano il loro utilizzo. –

+1

@R ..- Tuttavia, non si classifica esattamente come una sotto-espressione comune. Le ottimizzazioni CSE cercano un sottocomponente che ha più istruzioni in comune e quindi utilizza un valore pre-cache invece di ricalcolare l'espressione più volte. Qui, l'unica parte comune è 'i%', che non è un'istruzione completa e non è calcolabile. Ciò che l'OP sta chiedendo è più strettamente correlato alla famiglia di ottimizzazioni della "riduzione della forza matematica". – bta

+0

Oltre a tutto ciò, ricordare che l'operatore "&&" introduce un punto di sequenza (per l'operazione "cortocircuito"). Se il lato sinistro viene valutato a zero, il lato destro non viene eseguito affatto. A causa dei molti potenziali effetti collaterali coinvolti, i compilatori rischiano di essere molto titubanti nell'ottimizzare un punto di sequenza. Sembra facile per casi semplici come questo, ma come problema generale, è molto più difficile da fare. – bta

1

Onestamente, questo è un caso molto specifico. Se una qualsiasi parte dell'equazione viene modificata, l'ottimizzazione non verrà più applicata. Penso che sia una questione di costi vs guadagni, e il costo di implementare questa ottimizzazione (maggiore tempo di compilazione, maggiore difficoltà di manutenzione) superano i benefici (poche operazioni in meno veloci in rare circostanze).

In generale, il refactoring matematico non può essere applicato a causa della limitazione di precisione e della possibilità di overflow. Anche se non penso che sia un problema qui.

Problemi correlati