https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113551

Yuxuan Shui <yshuiv7 at gmail dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
            Summary|[13 Regression]             |[13 Regression]
                   |Miscompilation with -O1     |Miscompilation with -O1
                   |-funswitch-loops            |-fno-strict-overflow
                   |-fno-strict-overflow        |

--- Comment #9 from Yuxuan Shui <yshuiv7 at gmail dot com> ---
So, to add some details to people said above, and to make sure I understood
this correctly.

What gcc did here is:

1. move the `if (!&dso->i)` branch out of the loop, duplicate the loop for the
then/else branches.
2. `&dso->i` cannot be 0, so the else branch is eliminated.
3. in the then branch, this condition confused the compiler. it thought since
`&dso->i` is not 0, `dso` is not 0 either, causing the bug.

I diffed `-fdump` outputs and it does match what I expected to see.

(minus is the correct one, plus the incorrect)

@@ -2686,7 +2686,11 @@
 ;; 4 succs { 5 6 }
 ;; 6 succs { 3 }
 ;; 5 succs { 1 }
-Removing basic block 6
+Folding predicate _1 == 0B to 0
+Exported global range table:
+============================
+_1  : [irange] int * [1, +INF]
+Merging blocks 4 and 6

* * *

this made me think whether loop unswitching is actually relevant here. since
12.3 also unswitches this loop, but doesn't miscompile. so I manually
unswitched the loop:


void bug(struct obj **root, struct obj *dso) {
        if (!&dso->i) {
                while (1) {
                        struct obj *this = *root;

                        if (dso == (void *)0)
                                // should return here
                                return;

                        if (dso == this)
                                return;

                        // shouldn't reach here
                        assert_not_null(dso);
                        break;
                }
        } else {
                while (1) {
                        struct obj *this = *root;

                        if (dso == (void *)0)
                                // should return here
                                return;

                        if (dso == this)
                                return;

                        // shouldn't reach here
                        assert_not_null(dso);
                }
        }
}

and now the miscompile happens without -funswitch-loops. I wonder if this
happens on trunk as well.

looks this this is a -fno-strict-overflow related ranger bug.

Reply via email to