VS: unerwartetes Optimierungsverhalten mit _BitScanReverse64 intrinsisch

Lesezeit: 3 Minuten

Benutzer-Avatar
Camleon

Der folgende Code funktioniert im Debugmodus einwandfrei, da _BitScanReverse64 so definiert ist, dass es 0 zurückgibt, wenn kein Bit gesetzt ist. Unter Berufung auf MSDN: (Der Rückgabewert ist) “Nicht Null, wenn Index gesetzt wurde, oder 0, wenn keine gesetzten Bits gefunden wurden.”

Wenn ich diesen Code im Release-Modus kompiliere, funktioniert er immer noch, aber wenn ich Compiler-Optimierungen wie \O1 oder \O2 aktiviere, ist der Index nicht Null und die assert() scheitert.

#include <iostream>
#include <cassert>

using namespace std;

int main()
{
  unsigned long index = 0;
  _BitScanReverse64(&index, 0x0ull);

  cout << index << endl;

  assert(index == 0);

  return 0;
}

Ist das das beabsichtigte Verhalten? Ich verwende Visual Studio Community 2015, Version 14.0.25431.01 Update 3. (Ich habe cout drin gelassen, damit der Variablenindex bei der Optimierung nicht gelöscht wird). Gibt es auch eine effiziente Problemumgehung oder sollte ich diesen Compiler einfach nicht direkt verwenden?

  • Das sofortige Initialisieren des Index macht hier keinen Unterschied, da _BitScanReverse die Initialisierung durchführt.

    – Camleon

    27. Dezember 2016 um 20:11 Uhr

  • Wenn Sie sagen “das Programm stürzt ab”, meinen Sie das assert scheitert, oder? Es ist schon eine Weile her, seit ich VS verwendet habe, aber sollte das nicht assert bei Release-Builds deaktiviert werden?

    – Eran

    27. Dezember 2016 um 20:16 Uhr

  • Auf der Seite von Microsoft zu _BitScanReverse64 steht das nicht index wird gesetzt, wenn kein Bit gesetzt ist; es sagt nur index wird mit einem Wert gesetzt, wenn ein Bit gesetzt ist. Wenn also kein Bit gesetzt ist, könnte _BitScanReverse64 gerade verlassen werden index allein und es bleibt mit dem, was es ursprünglich hatte.

    – Altainien

    27. Dezember 2016 um 20:21 Uhr

  • @Altainia hat imo die richtige Antwort. Sie sollten den Rückgabewert von überprüfen _BitScanReverse64. Wenn es null ist, wird der Wert von index ist undefiniert (zumindest in der Dokumentation). Angenommen, weil nur eine Rückgabe ungleich Null anzeigt index war eingestellt.

    – Eran

    27. Dezember 2016 um 20:29 Uhr

  • index wird auf 0 initialisiert, aber _BitScanReverse64 könnte es intern ändern. Die nicht optimierte Version wird möglicherweise eingestellt index auf Null, wenn keine 1 gefunden wird, aber die optimierte Version lässt diesen Teil weg, um Zeit zu sparen. Beide stimmen mit den Dokumenten überein (“Nicht Null, wenn Index gesetzt wurde, oder 0, wenn keine gesetzten Bits gefunden wurden.”) und die optimierte Version macht weniger und ist daher schneller.

    – Eran

    27. Dezember 2016 um 20:36 Uhr

  • Der Grund, warum die Leute sagen, es sei halb dokumentiert, ist, weil AMD es dokumentiert. Sehen hier, p. 112 (S. 148 im PDF). (Ich kann kein x86-32-Handbuch von AMD finden, aber ich würde schwören, dass es etwas Ähnliches gesagt hat.)

    – Cody Grey

    28. Dezember 2016 um 13:52 Uhr


  • Abgesehen davon sind Ihre Spekulationen darüber, wie das Intrinsic in MSVC funktioniert, genau richtig. Ich habe ziemlich viel Zeit damit verbracht, damit zu spielen, entdeckte ein paar Fehler (nur für 32-Bit-Builds), und versucht herauszufinden, wie man das “halbdokumentierte” Verhalten ausnutzen kann. Leider gibt es keinen anderen Weg als Inline asm. Beachten Sie auch, dass eine suboptimale Codegenerierung möglich ist, wenn Sie den Rückgabewert des Intrinsic nicht überprüfen!

    – Cody Grey

    28. Dezember 2016 um 14:01 Uhr


  • Leider umgeht auch die neueste Version von MSVC (VS 2015 Update 3) die falsche Abhängigkeit in popcnt/lzcnt/tzcnt nicht, wenn Sie die entsprechenden Intrinsics verwenden. Habe noch keine Bug/Feature-Request dafür gestellt. Sie haben alle Fehler, die ich bisher gemeldet habe, ignoriert.

    – Cody Grey

    28. Dezember 2016 um 14:04 Uhr


  • @CodyGray: gcc umgeht das falsche dep für popcnt/lzcnt/tzcnt, aber nicht für bsf/bsr. /Gesichtspalme. 🙁 Ich schreibe gerade einen Fehlerbericht dafür. Danke für die Links, insbesondere zu AMDs Dokumenten.

    – Peter Cordes

    29. Dezember 2016 um 0:08 Uhr


1019420cookie-checkVS: unerwartetes Optimierungsverhalten mit _BitScanReverse64 intrinsisch

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy