2016-07-03 36 views
9

Assumere un'API in cui ogni funzione restituisce un codice di errore che è zero in caso di errore e non zero per i valori di errore.Ottimizzazione della valutazione dei parametri in linea C statico

Let

int foo(...); 
int bar(...); 

tramite funzioni in questa API. Sia il frammento di codice in cui foo e bar devono essere chiamati in ordine e foo e bar dovrebbe sempre essere chiamato, a prescindere dalle precedenti errore ma la prima restituito il codice di errore diverso da zero deve essere propagato, cioè

int foobar(...) 
{ 
    int rc = 0, rc_; 
    /* ... */ 
    rc_ = foo(...); rc = rc ? rc : rc_; 
    rc_ = bar(...); rc = rc ? rc : rc_; 
    return rc; 
} 

Scrivere la rc, rc_ multiplexing è stancante e soggetto a errori (non importa se un operatore ternario, se/else o qualcos'altro viene utilizzato).

Ci sia un errore di moltiplicazione funzione di supporto

static inline 
int rc_propagate(int r, int p){ return p ? p : r; } 

Questo potrebbe essere utilizzato in foobar come questo

int foobar(...) 
{ 
    int rc = 0; 
    /* ... */ 
    rc = rc_propagate(foo(...), rc); 
    rc = rc_propagate(bar(...), rc); 
    return rc; 
} 

Fa lo standard C consentono di ottimizzare tirando la valutazione del primo parametro di rc_propagate, una funzione inline statica, nel ternario in modo che non possa essere eseguita a causa delle regole di valutazione dell'operatore ternario se il secondo parametro p fosse diverso da zero?

+1

credo che nessuno, ma aspetterò che qualcuno citare la parte pertinente della norma. – immibis

+0

@ 2501: solo che in questo caso non è una funzione esterna, ma statica in linea.I miei dubbi riguardano esclusivamente l'inline statico; in particolare ho appena letto alcune voci del blog degli sviluppatori di LLVM e le possibili ottimizzazioni riguardanti le funzioni di chiamata che sono statiche in linea. – datenwolf

+0

In una nota a margine, perché non scrivi semplicemente: 'rc = rc? rc: foo (...); 'ed evita del tutto il problema? – 2501

risposta

3

Un compilatore (o hardware per quella materia) è autorizzato a ottimizzare il programma finché il programma rimane lo stesso, cioè non è possibile dimostrare che il programma che è stato eseguito fosse diverso da quello scritto.

In questo caso il programma che hai scritto chiamerà sempre la funzione esterna perché non è presente nell'operatore ternario dove potrebbe non essere valutato. La funzione potrebbe avere effetti collaterali interessanti diversi ed è sconosciuta al compilatore. Ciò significa che la versione ottimizzata del programma dovrà chiamare la funzione esterna ad un certo punto (il codice può essere riordinato) per preservare tale comportamento.

Se ciò non fosse vero, potresti provare che il programma che è stato eseguito non era lo stesso di quello che hai scritto. Fare questo sarebbe facile; inserire un'istruzione printf (o equivalente) nella chiamata della funzione esterna.

1. Un concetto di un programma astratto che esiste quando è in esecuzione, non il codice macchina generato o eseguibile.


Utilizzando un argomento d'autorità, si può vedere che nessun compilatore effettivamente di ottimizzare le chiamate a foo() e bar() out:

versioni gcc 4.9.2, 5.3 o 6.1 con -O2:

foobar(): 
pushq %rbx  
call foo()  
movl %eax, %ebx  
call bar()  
testl %ebx, %ebx  
cmove %eax, %ebx  
movl %ebx, %eax  
popq %rbx  
ret 

versioni clang 3.7.1 o 3.8 con -O2:

foobar():       
pushq %rbx  
callq foo()  
movl %eax, %ebx  
callq bar()  
testl %ebx, %ebx  
cmovnel %ebx, %eax  
popq %rbx  
+0

Beh, i miei dubbi riguardano la funzione di propagazione "in linea statica" e senza effetti collaterali, quindi il compilatore in questo caso * fa * sapere cosa sta succedendo all'interno. Voglio solo assicurarmi che tutte le funzioni della catena * vengano chiamate, anche se una di esse restituisce un errore. Creare 'rc_propagate' external farà sicuramente il trucco, ma per quanto riguarda' static inline'? Più tardi fornisce al compilatore una conoscenza completa di ciò che sta accadendo lì. – datenwolf

+0

@datenwolf Saranno chiamati anche con statico in linea. Nota: accenno al fatto che la funzione esterna è sconosciuta, non quella statica, e quindi il primo deve essere chiamato. – 2501

Problemi correlati