Wie kann ich einen Aufruf erhalten, wenn zum Zeitpunkt der Kompilierung eine Edge-Bedingung bekannt ist?

8

Ich habe die folgende Situation: Es gibt eine große Menge von Vorlagen wie std::vector , die memmove() aufrufen, um Teile des Arrays zu verschieben. Manchmal möchten sie Teile der Länge Null "verschieben" - zum Beispiel, wenn der Array-Schwanz entfernt wird (wie std::vector::erase() ), wollen sie den Rest des Arrays bewegen was passieren wird have Länge Null und diese Null wird zur Kompilierzeit bekannt sein (Ich sah die Disassemblierung - der Compiler ist sich dessen bewusst), aber der Compiler gibt immer noch einen memmove() Aufruf aus.

Also im Grunde könnte ich einen Wrapper haben:

%Vor%

aber dies würde eine zusätzliche Laufzeitprüfung in Fällen einführen, in denen count in der Kompilierzeit nicht bekannt ist, die ich nicht will.

Ist es irgendwie möglich, __assume Hinweis zu verwenden geben Sie dem Compiler an, dass, wenn er sicher weiß, dass count null ist, er die memmove() eliminieren sollte?

    
sharptooth 05.10.2011, 07:32
quelle

4 Antworten

4

Diese Lösung verwendet einen Trick, der in der C ++ -Kompilierungszeitkonstantenerkennung - beschrieben wird Trick verwendet die Tatsache, dass Kompilierzeit Integer Null in einen Zeiger umgewandelt werden kann, und dies kann zusammen mit dem Überladen verwendet werden, um nach der Eigenschaft "Kompilierzeit bekannt" zu suchen.

%Vor%

Oder in Ihrem Fall, wie Sie sowieso nur auf Null überprüfen möchten, könnte man is_const_0 direkt für maximale Einfachheit und Portabilität verwenden:

%Vor%

Hinweis: Der Code hier verwendet eine Version von is_const einfacher als in der verknüpften Frage. Dies liegt daran, dass Visual Studio in diesem Fall standardkonformer als GCC ist. Wenn Sie gcc als Ziel verwenden, können Sie die folgende is_const-Variante verwenden (angepasst für alle möglichen Integralwerte, einschließlich negativ und INT_MAX):

%Vor%     
Suma 05.10.2011 08:04
quelle
3

Der Punkt von __assume besteht darin, den Compiler zu veranlassen, bei der Optimierung Teile des Codes zu überspringen. In dem von Ihnen angegebenen Link wird das Beispiel mit der default -Klausel des switch -Konstrukts angegeben - dort teilt der Hinweis dem Compiler mit, dass die Klausel niemals erreicht wird, obwohl es theoretisch möglich wäre. Sie sagen dem Optimierer im Grunde: "Hey, ich weiß es besser, wirf diesen Code weg."

Für default kann nicht geschrieben werden (es sei denn, Sie decken den gesamten Bereich in case s ab, was manchmal problematisch ist), da dies zu einem Kompilierungsfehler führen würde. Sie brauchen also den Hinweis, den Code zu optimieren, den Sie wissen, der nicht benötigt wird.

In Ihrem Fall - der Code kann erreicht werden, aber nicht immer, daher wird Ihnen der __assume Hinweis nicht viel helfen. Sie müssen überprüfen, ob count wirklich 0 ist. Wenn Sie nicht sicher sind, dass es nie 0 sein kann, schreiben Sie es einfach nicht ein.

    
littleadv 05.10.2011 07:39
quelle
1

Ich denke, dass Sie die Bedeutung von __assume falsch verstanden haben. Es sagt dem Compiler nicht, sein Verhalten zu ändern, wenn weiß, was die Werte sind, sondern es teilt ihm mit, was die Werte sein werden, wenn er sie nicht selbst ableiten kann.

Wenn Sie in Ihrem Fall __assume that count > 0 angegeben haben, wird der Test übersprungen, da Sie bereits darauf hingewiesen haben, dass das Ergebnis immer true ist. Dadurch wird die Bedingung entfernt und% co_de aufgerufen % immer , was genau das ist, was Sie vermeiden möchten.

Ich kenne die intrinsics von VS nicht, aber in GCC gibt es eine wahrscheinlich / unwahrscheinlich intrinsisch ( memmove ), die verwendet werden kann, um Hinweis den Compiler Was ist das wahrscheinlichste Ergebnis des Tests? Das wird den Test nicht entfernen, wird aber Layout-Code, so dass die meisten wahrscheinlich (wie in durch Ihre Definition ) Zweig ist effizienter (wird nicht verzweigen).

    
quelle
1

Wenn es möglich ist, das memmove umzubenennen, denke ich ungefähr so würde tun - Ссылка

%Vor%

Ich denke das gleiche ist wahrscheinlich ohne die Klasse möglich - muss man sich die Umrechnungsregeln anschauen um es zu bestätigen.

Es sollte auch möglich sein, das ursprüngliche memmove () zu überladen, z. indem man ein Objekt (wie Temp (sizeof (a)) als drittes Argument.

Nicht sicher, welcher Weg bequemer wäre.

    
Shelwien 08.10.2011 01:09
quelle