Wie kann ich zusätzliche Aufrufe an eine idempotente Funktion verhindern?

8

Gibt es eine Möglichkeit, gcc mitzuteilen, dass eine Funktion, die Nebenwirkungen hat, nur einmal aufgerufen werden sollte, wenn zwei aufeinanderfolgende Aufrufe dieselben Argumente haben. Ich möchte folgendes Verhalten:

%Vor%

Ich kann foo eine globale Variable überprüfen lassen, bevor sie funktioniert, aber das ist nicht optimal.

%Vor%

Da foo eine Inline-Funktion ist, sollte der Compiler in der Lage sein, auf Aufrufe von foo() zu schauen und zu sehen, dass er nicht ausgeführt werden muss. Das Problem ist, dass der Compiler für globale Variablen nicht so optimiert werden kann. Gibt es eine Möglichkeit, dem Compiler mitzuteilen, dass dies sicher ist?

    
vanjoe 22.08.2014, 21:17
quelle

6 Antworten

0

Der Grund, warum ich zögerte, nur die letzten Argumente zu überprüfen, war, dass der Funktionsaufruf innerhalb einiger sehr enger innerer Schleifen lag, so dass die zusätzlichen Vergleichs- und Verzweigungsbefehle besonders auf Plattformen mit (oder sehr schlechten) ärgerlich wären ) Verzweigungsvorhersage.

Ich habe beschlossen zu sehen, was gcc tut, als ich es versuchte. Ich habe den folgenden Code verwendet:

%Vor%

Dies kompiliert ( gcc -O2 main.c ) auf x86 (nicht mein letztes Ziel) zu:

%Vor%

Wie du sehen kannst, wird myfun nur zweimal so genannt, wie ich es möchte. Daher sieht es so aus, als ob gcc das richtig machen könnte. Wenn jemand hier auf Einschränkungen der Optimierungen eingehen möchte, wäre ich sehr interessiert.

    
vanjoe 30.04.2015, 18:30
quelle
7
  

... eine Funktion mit Nebeneffekten sollte nur einmal aufgerufen werden, wenn zwei aufeinanderfolgende Aufrufe dieselben Argumente haben ...

Diese Funktion muss dann idempotent sein, obwohl sie Nebenwirkungen hat.

C ++ - Standard unterscheidet nur Funktionen mit Nebeneffekten (I / O-Funktionen) und ohne. Aus Sicht des Compilers, wenn die Funktion undurchsichtig ist (keine Definition in der gleichen Übersetzungseinheit), muss sie Nebeneffekte haben und daher ist sie eine Compiler-Speicherbarriere und der Compiler kann den Aufruf nicht optimieren oder den Rückgabewert ableiten (es sei denn eine interne Funktion des Compilers wie memcpy ).

Idempotenz, Informatik-Bedeutung :

  

In der Informatik wird der Begriff idempotent umfassender verwendet, um eine Operation zu beschreiben, die bei einmaliger oder mehrfacher Ausführung dieselben Ergebnisse liefert. [4] Dies kann je nach Kontext, in dem es angewendet wird, eine andere Bedeutung haben. Bei Methoden oder Unterprogrammaufrufen mit Nebeneffekten zum Beispiel bedeutet dies, dass der modifizierte Zustand nach dem ersten Aufruf gleich bleibt. In der funktionalen Programmierung hat eine idempotente Funktion jedoch die Eigenschaft f (f (x)) = f (x) für irgendeinen Wert x. [5]

Und C ++ hat diese Vorstellung nicht.

    
Maxim Egorushkin 22.08.2014 21:30
quelle
5

Sie könnten static Variablen verwenden:

%Vor%     
Paweł Stawarz 22.08.2014 21:25
quelle
3

Damit ein Compiler eine Funktion mit Nebeneffekten optimieren kann, müsste er die von ihm erzeugten Nebenwirkungen verstehen. GCC hat keine Anmerkung, um die Art der Nebenwirkungen zu beschreiben, daher ist dies nicht möglich.

Wenn die Funktion in der gleichen Kompilierungseinheit ist, könnte der Compiler herausfinden, dass die Aufrufe redundant sind, aber das funktioniert nur, wenn die Funktion einfach genug ist, damit der Compiler vollständig versteht, was selten der Fall ist. Sie können diese Logik besser in den Anrufer oder Angerufenen einfügen.

Zur Vollständigkeit, wenn die Funktion nicht Seiteneffekte hat, können Sie __attribute__((pure)) und __attribute__((const)) verwenden, um dies dem Compiler mitzuteilen.

    
jtaylor 22.08.2014 21:25
quelle
2

Nein. Dieses Verhalten ist nicht Teil der Semantik irgendeiner Sprache der vielen, die ich gesehen habe und schon gar nicht C / C ++. Gcc kann keine Optionen zum Kompilieren von Code mit falschem semantischem Verhalten bereitstellen!

Das Umgekehrte ist jedoch möglich. Wenn eine Funktion foo () "rein" ist, dh ohne Nebenwirkungen, dann wird sich ein guter Compiler zB mit y = foo (x) + foo (x) befassen; Verwenden Sie nur einen einzigen Aufruf von foo (). Die Ada-Sprache bietet ein Pragma, um Reinheit für diesen Zweck zu behaupten.

    
Gene 22.08.2014 21:26
quelle
2

Sie können funktor verwenden:

%Vor%

Diese Lösung ist Standard-abhängig, nicht Compiler-abhängig.

Oder du kannst mit foo s static varaibles spielen.

    
GingerPlusPlus 22.08.2014 21:25
quelle

Tags und Links