The following fixes a jump-threading bug when threading through a backedge (thus it's only applicable to GCC 5). The issue is that when we see a backedge walking the SSA value chain might end up picking up values from a previous iteration.
The fix is to add backedge_seen to yet another function and avoid walking the SSA value chain in that case. Bootstrapped and tested on x86_64-unknown-linux-gnu - ok for the branch? (I was sitting on this patch for some months because I only had a proprietary testcase) Thanks, Richard. 2016-12-09 Richard Biener <rguent...@suse.de> PR tree-optimization/78731 * tree-ssa-threadedge.c (simplify_control_stmt_condition): If we've seen a backedge to not walk the SSA value chain. (thread_around_empty_blocks): Pass down whether we've seen a backedge to simplify_control_stmt_condition. (thread_through_normal_block): Likewise. * gcc.dg/torture/pr78731.c: New testcase. Index: gcc/tree-ssa-threadedge.c =================================================================== --- gcc/tree-ssa-threadedge.c (revision 237797) +++ gcc/tree-ssa-threadedge.c (working copy) @@ -574,7 +574,8 @@ simplify_control_stmt_condition (edge e, gimple stmt, gcond *dummy_cond, tree (*simplify) (gimple, gimple), - bool handle_dominating_asserts) + bool handle_dominating_asserts, + bool backedge_seen) { tree cond, cached_lhs; enum gimple_code code = gimple_code (stmt); @@ -593,7 +594,7 @@ simplify_control_stmt_condition (edge e, /* Get the current value of both operands. */ if (TREE_CODE (op0) == SSA_NAME) { - for (int i = 0; i < 2; i++) + for (int i = 0; i < (backedge_seen ? 1 : 2); i++) { if (TREE_CODE (op0) == SSA_NAME && SSA_NAME_VALUE (op0)) @@ -605,7 +606,7 @@ simplify_control_stmt_condition (edge e, if (TREE_CODE (op1) == SSA_NAME) { - for (int i = 0; i < 2; i++) + for (int i = 0; i < (backedge_seen ? 1 : 2); i++) { if (TREE_CODE (op1) == SSA_NAME && SSA_NAME_VALUE (op1)) @@ -689,7 +690,7 @@ simplify_control_stmt_condition (edge e, a loop invariant SSA_NAME used in the condition. */ if (cached_lhs) { - for (int i = 0; i < 2; i++) + for (int i = 0; i < (backedge_seen ? 1 : 2); i++) { if (TREE_CODE (cached_lhs) == SSA_NAME && SSA_NAME_VALUE (cached_lhs)) @@ -940,7 +941,8 @@ thread_around_empty_blocks (edge taken_e /* Extract and simplify the condition. */ cond = simplify_control_stmt_condition (taken_edge, stmt, dummy_cond, - simplify, handle_dominating_asserts); + simplify, handle_dominating_asserts, + *backedge_seen_p); /* If the condition can be statically computed and we have not already visited the destination edge, then add the taken edge to our thread @@ -1326,7 +1328,8 @@ thread_through_normal_block (edge e, /* Extract and simplify the condition. */ cond = simplify_control_stmt_condition (e, stmt, dummy_cond, simplify, - handle_dominating_asserts); + handle_dominating_asserts, + *backedge_seen_p); if (!cond) return 0; Index: gcc/testsuite/gcc.dg/torture/pr78731.c =================================================================== --- gcc/testsuite/gcc.dg/torture/pr78731.c (revision 0) +++ gcc/testsuite/gcc.dg/torture/pr78731.c (working copy) @@ -0,0 +1,41 @@ +/* { dg-do run } */ + +#include <stdio.h> +#include <stdlib.h> + +#define GENERAL 1 +#define BRACKETS 2 +#define QUOTES 3 + +void __attribute__((noinline,noclone)) +foo(char *qb, char* into) +{ + int state = QUOTES; + int save_state = BRACKETS; + + while (qb) + { + switch (state) + { + case BRACKETS: + exit(0); + case GENERAL: + abort (); + case QUOTES: + state = save_state; + save_state = GENERAL; + break; + default: ; + } + printf("State %d btw GENERAL %d\n", state, GENERAL); + } + abort (); +} + +int main() +{ + char *b = "123"; + char out[4]; + foo(b, out); + return 0; +}