From patchwork Wed Feb 4 21:20:06 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sebastian Pop X-Patchwork-Id: 436489 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 8047B140172 for ; Thu, 5 Feb 2015 08:21:15 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=CbbmxM+dKrDviQCzG7Im+54ilIHf+YP6mQFufPQAm8RgXzc1JeD0I Htz1L+9k75LTAlqqiM+2+pZLqHS4sgboxp39iZ9xKjVGeb9THT/l680hlUsyMf5m bcJiwzP5k1WkGj20uqtSFsAKqdQCkZ7ubvVPcIqe55GUWtAuPFkUH8= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=VpYFAyPJE792mwvPfTgV7lwIhHg=; b=OOz/Dpu5mISWj3OHJD23 5yCRNmjopIVk/GtdG6upuH9uEAbmKzRO9Lx1bQOsfDjAJwEH1QWGENlNq0ahkb2f dpc04/E9EAhojFIahY/0G5RTgF/GEX4jjoxnfjGfOV07lCn1FaOGquVq83qZQYBg NofpkGwtnqtfmobaAoe94fA= Received: (qmail 26894 invoked by alias); 4 Feb 2015 21:20:13 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 26878 invoked by uid 89); 4 Feb 2015 21:20:12 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.2 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, SPF_PASS, UNWANTED_LANGUAGE_BODY autolearn=ham version=3.3.2 X-HELO: mail-ie0-f179.google.com Received: from mail-ie0-f179.google.com (HELO mail-ie0-f179.google.com) (209.85.223.179) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Wed, 04 Feb 2015 21:20:10 +0000 Received: by mail-ie0-f179.google.com with SMTP id x19so5375635ier.10 for ; Wed, 04 Feb 2015 13:20:08 -0800 (PST) X-Received: by 10.107.137.25 with SMTP id l25mr438631iod.9.1423084808356; Wed, 04 Feb 2015 13:20:08 -0800 (PST) Received: from f1.c.bardezibar.internal (81.37.148.146.bc.googleusercontent.com. [146.148.37.81]) by mx.google.com with ESMTPSA id m5sm1694880ige.5.2015.02.04.13.20.07 (version=SSLv3 cipher=RC4-SHA bits=128/128); Wed, 04 Feb 2015 13:20:07 -0800 (PST) Date: Wed, 4 Feb 2015 21:20:06 +0000 From: Sebastian Pop To: gcc-patches@gcc.gnu.org, Jeff Law Subject: Fix PR64878: do not jump thread across two loop iterations Message-ID: <20150204212006.GA18747@f1.c.bardezibar.internal> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) X-IsSubscribed: yes Hi, The attached patch stops the recursion in the detection of FSM jump-threads at loop phi nodes after having visited a loop phi node. This avoids jump-threading two iterations forward that were possible due to a flip-flop operation that exchange the value of the switch control variable as illustrated in the testcase: do { c = read_from_memory; switch (a) { case 0: if (c == ' ') [...] else a = b; // flip-flop break; case 1: a = 0; b = 15; // this will jump-thread to 15 break; case 15: [...] } } while (...); The patch has passed bootstrap and regression testing on x86_64-linux. Ok to commit? Thanks, Sebastian From 59c486720749fc3d5feac2a5364d52eac60ba2d0 Mon Sep 17 00:00:00 2001 From: Sebastian Pop Date: Wed, 4 Feb 2015 11:17:54 -0600 Subject: [PATCH] PR 64878: do not jump thread across more than one back-edge 2015-02-04 Sebastian Pop Brian Rzycki PR tree-optimization/64878 * tree-ssa-threadedge.c: Include tree-ssa-loop.h. (fsm_find_control_statement_thread_paths): Add parameter seen_loop_phi. Stop recursion at loop phi nodes after having visited a loop phi node. * testsuite/gcc.dg/tree-ssa/ssa-dom-thread-8.c: New. --- gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-8.c | 440 +++++++++++++++++++++++ gcc/tree-ssa-threadedge.c | 20 +- 2 files changed, 457 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-8.c diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-8.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-8.c new file mode 100644 index 0000000..9be75aa --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-8.c @@ -0,0 +1,440 @@ +/* PR 64878 */ +/* { dg-options "-O2" } */ +/* { dg-do run } */ + +struct A { int a1; }; +struct B { char *b1; int b2; int b3; }; +struct C { char *c1; int c2; struct B *c3; }; +extern struct A *f1 (char *s); +static struct A *f2 (struct C *x); +__attribute__ ((noinline, noclone)) int f3 (struct A *x, struct A *z) { asm volatile ("" : : "g" (x), "g" (z) : "memory"); return 0; } +__attribute__ ((noinline, noclone)) void f4 (struct A *x, char *y, struct A *z) { asm volatile ("" : : "g" (x), "g" (z), "g" (y) : "memory"); } +__attribute__ ((noinline, noclone)) struct B *f5 (void) { static char b[32]; static struct B f3 = { b, 0, 32 }; return &f3; } +__attribute__ ((noinline, noclone)) int f6 (struct B *p, char *w, int z) { asm volatile ("" : : "g" (p), "g" (w), "g" (z) : "memory"); return 0; } +__attribute__ ((noinline, noclone)) void f7 (struct B *p) { asm volatile ("" : : "g" (p) : "memory"); } +__attribute__ ((noinline, noclone)) void f8 (struct B *p) { asm volatile ("" : : "g" (p) : "memory"); } +__attribute__ ((noinline, noclone)) void f9 (struct A *x) { asm volatile ("" : : "g" (x) : "memory"); } +__attribute__ ((noinline, noclone)) struct A *f10 (void) { static struct A j; asm volatile ("" : : : "memory"); return &j; } +__attribute__ ((noinline, noclone)) struct A *f11 (void) { static struct A j; asm volatile ("" : : : "memory"); return &j; } +__attribute__ ((noinline, noclone)) struct A *f12 (int b) { static struct A j; asm volatile ("" : : "g" (b) : "memory"); return &j; } +__attribute__ ((noinline, noclone)) struct A *f13 (int i) { static struct A j; asm volatile ("" : : "g" (i) : "memory"); return &j; } +__attribute__ ((noinline, noclone)) struct A *f14 (double d) { static struct A j; asm volatile ("" : : "g" (&d) : "memory"); return &j; } +__attribute__ ((noinline, noclone)) struct A *f15 (char *s) { static struct A j; asm volatile ("" : : "g" (s) : "memory"); return &j; } +char *t = "0123456789abcdef"; +char *u = "0123456789.+-e"; + +__attribute__ ((noinline, noclone)) struct A * +f1 (char *s) +{ + struct C f; + struct A *o; + f.c1 = s; + f.c2 = 0; + f.c3 = f5 (); + o = f2 (&f); + f8 (f.c3); + return o; +} + +static struct A * +f2 (struct C *x) +{ + int a, b, e = 0; + struct A *f = 0, *o; + char *g = 0; + char h = '\0'; + int i = 0, j = 0; + a = 0; + b = 1; + char c; + do + { + c = x->c1[x->c2]; + switch (a) + { + case 0: + if (c == ' ') + x->c2++; + else if (c == '/') + { + a = 4; + j = x->c2++; + } + else + a = b; + break; + case 1: + switch (c) + { + case '{': + a = 0; + b = 15; + f = f10 (); + x->c2++; + break; + case '[': + a = 0; + b = 13; + f = f11 (); + x->c2++; + break; + case 'N': + case 'n': + a = 3; + j = x->c2++; + break; + case '"': + case '\'': + h = c; + f7 (x->c3); + a = 8; + j = ++x->c2; + break; + case 'T': + case 't': + case 'F': + case 'f': + a = 11; + j = x->c2++; + break; + case '0' ... '9': + case '-': + i = 0; + a = 12; + j = x->c2++; + break; + default: + e = 1; + goto out; + } + break; + case 2: + goto out; + case 3: + if (__builtin_strncmp ("null", x->c1 + j, x->c2 - j)) + { + e = 2; + goto out; + } + if (x->c2 - j == 4) + { + f = 0; + b = 2; + a = 0; + } + else + x->c2++; + break; + case 4: + if (c == '*') + a = 5; + else if (c == '/') + a = 6; + else + { + e = 8; + goto out; + } + x->c2++; + break; + case 5: + if (c == '*') + a = 7; + x->c2++; + break; + case 6: + if (c == '\n') + a = 0; + x->c2++; + break; + case 7: + if (c == '/') + a = 0; + else + a = 5; + x->c2++; + break; + case 8: + if (c == h) + { + f6 (x->c3, x->c1 + j, x->c2 - j); + f = f15 (x->c3->b1); + b = 2; + a = 0; + } + else if (c == '\\') + { + b = 8; + a = 9; + } + x->c2++; + break; + case 9: + switch (c) + { + case '"': + case '\\': + f6 (x->c3, x->c1 + j, x->c2 - j - 1); + j = x->c2++; + a = b; + break; + case 'b': + case 'n': + case 'r': + case 't': + f6 (x->c3, x->c1 + j, x->c2 - j - 1); + if (c == 'b') + f6 (x->c3, "\b", 1); + else if (c == 'n') + f6 (x->c3, "\n", 1); + else if (c == 'r') + f6 (x->c3, "\r", 1); + else if (c == 't') + f6 (x->c3, "\t", 1); + j = ++x->c2; + a = b; + break; + case 'u': + f6 (x->c3, x->c1 + j, x->c2 - j - 1); + j = ++x->c2; + a = 10; + break; + default: + e = 7; + goto out; + } + break; + case 10: + if (__builtin_strchr (t, c)) + { + x->c2++; + if (x->c2 - j == 4) + { + unsigned char w[3]; + unsigned int s = + (((x->c1[j] <= '9') ? x->c1[j] - '0' : (x->c1[j] & 7) + 9) << 12) + + (((x->c1[j + 1] <= '9') ? x->c1[j + 1] - '0' : (x->c1[j + 1] & 7) + 9) << 8) + + (((x->c1[j + 2] <= '9') ? x->c1[j + 2] - '0' : (x->c1[j + 2] & 7) + 9) << 4) + + ((x->c1[j + 3] <= '9') ? x->c1[j + 3] - '0' : (x->c1[j + 3] & 7) + 9); + if (s < 0x80) + { + w[0] = s; + f6 (x->c3, (char *) w, 1); + } + else if (s < 0x800) + { + w[0] = 0xc0 | (s >> 6); + w[1] = 0x80 | (s & 0x3f); + f6 (x->c3, (char *) w, 2); + } + else + { + w[0] = 0x0 | (s >> 12); + w[1] = 0x80 | ((s >> 6) & 0x3f); + w[2] = 0x80 | (s & 0x3f); + f6 (x->c3, (char *) w, 3); + } + j = x->c2; + a = b; + } + } + else + { + e = 7; + goto out; + } + break; + case 11: + if (__builtin_strncmp ("true", x->c1 + j, x->c2 - j) == 0) + { + if (x->c2 - j == 4) + { + f = f12 (1); + b = 2; + a = 0; + } + else + x->c2++; + } + else if (__builtin_strncmp ("false", x->c1 + j, x->c2 - j) == 0) + { + if (x->c2 - j == 5) + { + f = f12 (0); + b = 2; + a = 0; + } + else + x->c2++; + } + else + { + e = 3; + goto out; + } + break; + case 12: + if (!c || !__builtin_strchr (u, c)) + { + if (!i) + f = f13 (0); + else + f = f14 (0.0); + b = 2; + a = 0; + } + else + { + if (c == '.' || c == 'e') + i = 1; + x->c2++; + } + break; + case 13: + if (c == ']') + { + x->c2++; + b = 2; + a = 0; + } + else + { + o = f2 (x); + if (((unsigned long) o > (unsigned long) -4000L)) + { + e = 5; + goto out; + } + f3 (f, o); + b = 14; + a = 0; + } + break; + case 14: + if (c == ']') + { + x->c2++; + b = 2; + a = 0; + } + else if (c == ',') + { + x->c2++; + b = 13; + a = 0; + } + else + { + f9 (f); + e = 5; + goto out; + } + break; + case 15: + a = 16; + j = x->c2; + break; + case 16: + if (c == '}') + { + x->c2++; + b = 2; + a = 0; + } + else if (c == '"' || c == '\'') + { + h = c; + f7 (x->c3); + a = 17; + j = ++x->c2; + } + else + { + e = 6; + goto out; + } + break; + case 17: + if (c == h) + { + f6 (x->c3, x->c1 + j, x->c2 - j); + g = __builtin_strdup (x->c3->b1); + b = 18; + a = 0; + } + else if (c == '\\') + { + b = 17; + a = 9; + } + x->c2++; + break; + case 18: + if (c == ':') + { + x->c2++; + b = 19; + a = 0; + } + else + { + e = -6; + goto out; + } + break; + case 19: + o = f2 (x); + if (((unsigned long) o > (unsigned long) -4000L)) + { + e = 6; + goto out; + } + f4 (f, g, o); + __builtin_free (g); + g = 0; + b = 20; + a = 0; + break; + case 20: + if (c == '}') + { + x->c2++; + b = 2; + a = 0; + } + else if (c == ',') + { + x->c2++; + b = 15; + a = 0; + } + else + { + e = 6; + goto out; + } + break; + } + } + while (c); + if (a != 2 && b != 2) + e = 9; +out: + __builtin_free (g); + if (e == 0) + return f; + f9 (f); + return 0; +} + +int +main () +{ + asm volatile ("" : : : "memory"); + struct A *r = f1 ("{ \"id\": null, \"blahah\": \"foobarbazbar\", \"barbar\": { \"barbarbarba\":" + "\"abcdefgh\", \"ijklmnopqr\": \"stuvwxyzabcdefghijklmnopqrstuv\", \"xyzxyz\":" + " [ \"1\" ] } }"); + if (!r) + __builtin_abort (); + return 0; +} diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c index 9e10e44..b2e7764 100644 --- a/gcc/tree-ssa-threadedge.c +++ b/gcc/tree-ssa-threadedge.c @@ -61,6 +61,7 @@ along with GCC; see the file COPYING3. If not see #include "langhooks.h" #include "params.h" #include "tree-ssa-threadedge.h" +#include "tree-ssa-loop.h" #include "builtins.h" #include "cfg.h" #include "cfganal.h" @@ -1006,7 +1007,8 @@ static int max_threaded_paths; static void fsm_find_control_statement_thread_paths (tree expr, hash_set *visited_phis, - vec *&path) + vec *&path, + bool seen_loop_phi) { tree var = SSA_NAME_VAR (expr); gimple def_stmt = SSA_NAME_DEF_STMT (expr); @@ -1030,6 +1032,15 @@ fsm_find_control_statement_thread_paths (tree expr, int next_path_length = 0; basic_block last_bb_in_path = path->last (); + if (loop_containing_stmt (phi)->header == gimple_bb (phi)) + { + /* PR64878: do not take more than a loop phi node: it may be a flip-flop + operation across two latch edges. */ + if (seen_loop_phi) + return; + seen_loop_phi = true; + } + /* Following the chain of SSA_NAME definitions, we jumped from a definition in LAST_BB_IN_PATH to a definition in VAR_BB. When these basic blocks are different, append to PATH the blocks from LAST_BB_IN_PATH to VAR_BB. */ @@ -1090,7 +1101,9 @@ fsm_find_control_statement_thread_paths (tree expr, { vec_safe_push (path, bbi); /* Recursively follow SSA_NAMEs looking for a constant definition. */ - fsm_find_control_statement_thread_paths (arg, visited_phis, path); + fsm_find_control_statement_thread_paths (arg, visited_phis, path, + seen_loop_phi); + path->pop (); continue; } @@ -1357,7 +1370,8 @@ thread_through_normal_block (edge e, hash_set *visited_phis = new hash_set; max_threaded_paths = PARAM_VALUE (PARAM_MAX_FSM_THREAD_PATHS); - fsm_find_control_statement_thread_paths (cond, visited_phis, bb_path); + fsm_find_control_statement_thread_paths (cond, visited_phis, bb_path, + false); delete visited_phis; vec_free (bb_path); -- 1.9.1