From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 7039 invoked by alias); 18 Oct 2004 21:04:04 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 7023 invoked from network); 18 Oct 2004 21:04:03 -0000 Received: from unknown (HELO x93.infopact.nl) (212.29.160.93) by sourceware.org with SMTP; 18 Oct 2004 21:04:03 -0000 Received: from steven.lr-s.tudelft.nl (70-90.ipact.nl [82.210.90.70]) by x93.infopact.nl (8.12.10/8.12.10) with ESMTP id i9IL3MZq012161; Mon, 18 Oct 2004 23:03:47 +0200 From: Steven Bosscher To: gcc-patches@gcc.gnu.org Subject: Fix a tcb crash and a potential bug on mainline Date: Mon, 18 Oct 2004 21:09:00 -0000 User-Agent: KMail/1.5.4 Organization: SUSE Labs Cc: dnovillo@redhat.com, amacleod@redhat.com MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline Message-Id: <200410182303.52997.stevenb@suse.de> X-CanItPRO-Stream: NoScan X-Spam-Score: undef - spam-scanning disabled X-Canit-Stats-ID: 1146228 - 90f30373308a X-Scanned-By: CanIt (www . canit . ca) X-SW-Source: 2004-10/txt/msg01547.txt.bz2 Hi, So here is an interesting tree CFG cleanup bug seen on the t-c-branch, but it may well be that it also exists on mainline (haven't tried it). Consider this function, extern void abort (void) __attribute__ ((__noreturn__)); extern void foo (const char *s); int bar (const char **mangled) { const char *c; int type_quals; switch (**mangled) { case 'C': type_quals = 1; break; case 'u': type_quals = 4; break; default: abort (); } switch (type_quals) { case 6: c = "volatile __restrict"; break; case 4: c = "const volatile __restrict"; break; default: abort (); } if (c != ((void *)0)) foo (c); } After some constant propagating and jump threading, we eventually find out that only the path with "case 4" matters and we end up with the two following basic blocks: ;; basic block 2, loop depth 0, count 0 ;; prev block 1, next block 3 ;; pred: 0 [33.3%] (exec) ;; succ: 3 [33.3%] 4 [33.3%] 7 [33.3%] (exec) # type_quals_8 = PHI <4(0)>; :; switch (4) { case 4: goto ; case 6: goto ; default : goto ; } ;; basic block 4, loop depth 0, count 0 ;; prev block 3, next block 5 ;; pred: 2 [33.3%] ;; succ: 6 [10.0%] (false) 5 [90.0%] (true) # c_13 = PHI <&"volatile __restrict"[0](2)>; :; if (c_13 != 0B) goto ; else goto ; Then we try to do cleanup_tree_cfg() which calls cleanup_control_flow() which iterates over all basic blocks with FOR_EACH_BB. When we find that we'll always go to from block 2, we replace the switch with an unconditional jump and block 4 becomes unreachable. We remove the edge from block 2 to block 4, and we remove the matching PHI arguments with remove_phi_arg_num(). Now it gets interesting. remove_phi_arg_num() removes the PHI defining c_13, and then releases the PHI_RESULT, so c_13 ends up on the SSA free list, even though it is still used in the COND_EXPR in block 4. Later on cleanup_control_flow() tries to do its thing on basic block 4. It tries to fold "(c_13 != 0B)", but c_13 is on the free list, so it does not have a TREE_TYPE, so fold crashes. I think the root cause of this bug is that c_13 is put on the free list, and I think its SSA_NAME_DEF_STMT should be set to the empty statement, because remove_phi_arg_num() cannot know if there are any immediate uses of it still left. I don't know if making that change could have some unforseen effects, so I decided to re-hide the the bug by just not looking at unreachable blocks in cleanup_control_flow(). I've tried to convince myself that this can not happen in other situations, but I'm not sure. This may be something Andrew may want to look into as part of his immediate uses work?? This fix is completely untested at the moment, but it's quite obvious and it fixes the ICE I was seeing. Still, I am a bit surprised that we have not been in trouble over this bug before - perhaps we should still fix the remove_phi_arg_num() issue instead of papering it over this way? Gr. Steven Index: tree-cfg.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/tree-cfg.c,v retrieving revision 2.55.2.5 diff -c -3 -p -r2.55.2.5 tree-cfg.c *** tree-cfg.c 13 Oct 2004 16:04:10 -0000 2.55.2.5 --- tree-cfg.c 18 Oct 2004 21:00:37 -0000 *************** cleanup_control_flow (void) *** 1853,1858 **** --- 1852,1863 ---- FOR_EACH_BB (bb) { + /* We can have unreachable blocks here if we run before + delete_unreachable_blocks or if a block visited before + this one had an edge to bb that we removed. */ + if (EDGE_COUNT (bb->preds) == 0) + continue; + bsi = bsi_last (bb); if (bsi_end_p (bsi))