2016-07-03 5 views
9

Nehmen Sie eine API an, in der jede Funktion einen Fehlercode zurückgibt, der Null ist, wenn kein Fehler vorliegt, und ungleich Null für Fehlerwerte.C statische Inline-Parameterauswertung Optimierung

Lassen Sie in diesem API
int foo(...); 
int bar(...); 

Funktionen sein. Lassen Sie ein Codefragment, in der foo und bar haben, um und foo und bar sollte immer genannt werden, aufgerufen werden, unabhängig von vorherigen Fehlern aber die zurück ersten Nicht-Null-Fehlercode propagiert werden, dh

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

Schreiben der RC, rc_ Multiplexing ist ermüdend und fehleranfällig (egal ob ein ternärer Operator, wenn/sonst oder etwas anderes verwendet wird).

Es werde eine Fehler propagiert Helferfunktion

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

Diese

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

in foobar wie diese

verwendet werden könnte Ist der C-Standard ermöglichen, indem die Auswertung des ersten Parameters zu optimieren rc_propagate, eine statische Inline-Funktion, in das ternäre, so dass es aufgrund der ternären Operator-Bewertungsregeln nicht ausgeführt werden kann, wenn der zweite Parameter p ungleich Null war?

+1

ich nicht glaube, aber ich werde warten, bis jemand zu zitieren der relevante Teil des Standards. – immibis

+0

@ 2501: Nur, dass es in diesem Fall keine externe Funktion ist, sondern statisch inline.Meine Zweifel betreffen ausschließlich statische Inline; speziell habe ich gerade ein paar Blogeinträge der LLVM-Entwickler gelesen und mögliche Optimierungen hinsichtlich des Aufrufs von Funktionen, die inline statisch sind. – datenwolf

+0

Nebenbei, warum schreibst du nicht einfach: 'rc = rc? rc: foo (...); 'und vermeiden Sie das Problem insgesamt? – 2501

Antwort

3

Ein Compiler (oder Hardware für diese Angelegenheit) darf das Programm so lange optimieren, da das Programm gleich bleibt, das heißt man nicht nachweisen kann, dass das Programm, die unterschiedlichen ausgeführt wurde von dem einen war man schrieb.

In diesem Fall ruft das Programm, das Sie geschrieben haben, immer die externe Funktion auf, da es im ternären Operator nicht vorhanden ist, wo es nicht ausgewertet werden kann. Die Funktion kann verschiedene interessante Nebenwirkungen haben und ist dem Compiler unbekannt. Dies bedeutet, dass die optimierte Version des Programms die externe Funktion irgendwann aufrufen muss (der Code kann neu geordnet werden), um dieses Verhalten beizubehalten.

Wenn das nicht wahr wäre, könnten Sie beweisen, dass das Programm, das ausgeführt wurde, nicht das gleiche war wie das, das Sie geschrieben haben. Dies zu tun wäre einfach; Setzen Sie eine printf (oder eine äquivalente) Anweisung in den externen Funktionsaufruf.

1. Ein Konzept eines abstrakten Programms, das bei der Ausführung vorhanden ist, nicht der generierte Maschinencode oder die ausführbare Datei. siehe


ein Argument aus Autorität verwenden, können Sie, dass kein Compiler optimiert tatsächlich die Anrufe zu foo() und bar() aus:

gcc-Versionen 4.9.2, 5.3 oder 6.1 mit -O2:

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

Klirren Versionen 3.7.1 oder 3.8 mit -O2:

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

Nun, meine Zweifel sind, dass die Ausbreitungsfunktion 'statisch inline' ist und keine Nebenwirkungen hat, so dass der Compiler in diesem Fall * weiß, was im Inneren passiert. Ich möchte nur sicherstellen, dass alle Funktionen in der Kette * aufgerufen werden, auch wenn einer von ihnen einen Fehler zurückgibt. 'Rc_propagate' external wird sicherlich den Trick machen, aber was ist mit' static inline'? Letzteres gibt dem Compiler vollständige Kenntnis darüber, was dort passiert. – datenwolf

+0

@datenwolf Sie werden auch mit statischem Inline aufgerufen. Anmerkung: Ich erwähne, dass die externe Funktion unbekannt ist, nicht die statische, und daher muss die erstere aufgerufen werden. – 2501