https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85957
Alexander Cherepanov <ch3root at openwall dot com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |ch3root at openwall dot com --- Comment #20 from Alexander Cherepanov <ch3root at openwall dot com> --- Minimized testcase that should still be quite close to the original: ---------------------------------------------------------------------- #include <stdio.h> __attribute__((noipa)) // imagine it in a separate TU static double opaque(double d) { return d; } int main() { double d; do { d = opaque(1e6); } while (opaque(0)); if (d == 1e6) printf("yes\n"); int i = d * 1e-6; printf("i = %d\n", i); if (i == 1) printf("equal to 1\n"); } ---------------------------------------------------------------------- $ gcc -std=gnu11 -pedantic -Wall -Wextra -m32 -march=i686 -O3 test.c && ./a.out yes i = 0 equal to 1 ---------------------------------------------------------------------- According to https://godbolt.org/z/AmkmS5 , this happens for gcc versions 8.1--9.2 but not for trunk (I haven't tried earlier versions). With gcc 8.3.0 from the stable Debian it works like this: - (as described in comment 7) 120t.dom2 merges two `if`s, in particular deducing that `i == 1` is true if `d == 1e6` is true but not substituting `i` in `printf`; - 142t.loopinit introduces `# d_4 = PHI <d_8(3)>` between the loop and the first `if`; - 181t.dom3 would fold computation of `i` in the `d == 1e6` branch but the introduced `PHI` seems to prevent this. With gcc from the trunk a new pass 180t.fre4 removes that `PHI` and 182t.dom3 then does its work. (The numeration of passes changed slightly since gcc 8.3.0.)