From patchwork Fri Aug 31 14:11:26 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Matz X-Patchwork-Id: 964467 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-484867-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="nHNj6RLp"; dkim-atps=neutral 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 4221WG26y0z9s1x for ; Sat, 1 Sep 2018 00:11:37 +1000 (AEST) 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:cc:subject:message-id:mime-version:content-type; q=dns; s=default; b=MReQV0s47yJW0Caq7LVMpgte4snoBl7Gy3kx4gDfl1+WnfHh/j eYP90GptthwA502m1Eujc1D5Fxr3v6IyDKgtxGzHVnWBdS178m/kC+OqL77o1zb/ YN+DCOsK0k6Ew2E3DpaXIWdnjMWcp7kfHCFELOgbbEMIBEq+kepsx1nM4= 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:cc:subject:message-id:mime-version:content-type; s= default; bh=MVyKBvPnSC2/lBhAWdXlPpQxAkU=; b=nHNj6RLpd4lg0kvB7/97 MAxYSRThQolfSuSF+fknwT0OhPbfG+XB/ERsSM79Tvc8s9VzUXNBKS+JKPBmBFhy /3082ZJ4SJEbopZnA6CrXW5nFbnw6rmL2RKOw9Ya8nfXEiccX4i57oPiRuU6xTE6 VYMZ1e6ebTA4rcU3Rtc8cIs= Received: (qmail 7983 invoked by alias); 31 Aug 2018 14:11:30 -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 7968 invoked by uid 89); 31 Aug 2018 14:11:30 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_PASS autolearn=ham version=3.3.2 spammy=duplicated, x86-64-linux, fusion, x8664linux X-HELO: mx1.suse.de Received: from mx2.suse.de (HELO mx1.suse.de) (195.135.220.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 31 Aug 2018 14:11:28 +0000 Received: from relay1.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 45713AD8E; Fri, 31 Aug 2018 14:11:26 +0000 (UTC) Date: Fri, 31 Aug 2018 14:11:26 +0000 (UTC) From: Michael Matz To: gcc-patches@gcc.gnu.org cc: Jakub Jelinek Subject: Fix PR87074: miscompilation with unroll-and-jam Message-ID: User-Agent: Alpine 2.21 (LSU 202 2017-01-01) MIME-Version: 1.0 X-IsSubscribed: yes Hi, as Jakub correctly identified, uses of values produced by the inner loop that occur inside the outer loop prevent fusion as well. We are in LCSSA so the check is easy. (Uses outside the outer loop are okay, see the comment) Regstrapping on x86-64-linux in progress. Okay for trunk? Ciao, Michael. * gimple-loop-jam.c (unroll_jam_possible_p): Check loop exit PHIs for outer-loop uses. testsuite/ * gcc.dg/pr87074.c: New test. diff --git a/gcc/gimple-loop-jam.c b/gcc/gimple-loop-jam.c index 2ecd1bb5a7c..c6bd0428684 100644 --- a/gcc/gimple-loop-jam.c +++ b/gcc/gimple-loop-jam.c @@ -161,7 +161,7 @@ bb_prevents_fusion_p (basic_block bb) gimple_stmt_iterator gsi; /* BB is duplicated by outer unrolling and then all N-1 first copies move into the body of the fused inner loop. If BB exits the outer loop - the last copy still doess so, and the first N-1 copies are cancelled + the last copy still does so, and the first N-1 copies are cancelled by loop unrolling, so also after fusion it's the exit block. But there might be other reasons that prevent fusion: * stores or unknown side-effects prevent fusion @@ -227,6 +227,33 @@ unroll_jam_possible_p (struct loop *outer, struct loop *loop) || !expr_invariant_in_loop_p (outer, niter.niter)) return false; + /* If the inner loop produces any values that are used inside the + outer loop (except the virtual op) then it can flow + back (perhaps indirectly) into the inner loop. This prevents + fusion: without fusion the value at the last iteration is used, + with fusion the value after the initial iteration is used. + + If all uses are outside the outer loop this doesn't prevent fusion; + the value of the last iteration is still used (and the values from + all intermediate iterations are dead). */ + gphi_iterator psi; + for (psi = gsi_start_phis (single_exit (loop)->dest); + !gsi_end_p (psi); gsi_next (&psi)) + { + imm_use_iterator imm_iter; + use_operand_p use_p; + tree op = gimple_phi_result (psi.phi ()); + if (virtual_operand_p (op)) + continue; + FOR_EACH_IMM_USE_FAST (use_p, imm_iter, op) + { + gimple *use_stmt = USE_STMT (use_p); + if (!is_gimple_debug (use_stmt) + && flow_bb_inside_loop_p (outer, gimple_bb (use_stmt))) + return false; + } + } + /* And check blocks belonging to just outer loop. */ bbs = XNEWVEC (basic_block, n_basic_blocks_for_fn (cfun)); n = get_loop_body_with_size (outer, bbs, n_basic_blocks_for_fn (cfun)); @@ -245,7 +272,6 @@ unroll_jam_possible_p (struct loop *outer, struct loop *loop) body would be the after-iter value of the first body) if it's over an associative and commutative operation. We wouldn't be able to handle unknown cycles. */ - gphi_iterator psi; for (psi = gsi_start_phis (loop->header); !gsi_end_p (psi); gsi_next (&psi)) { affine_iv iv; diff --git a/gcc/testsuite/gcc.dg/pr87074.c b/gcc/testsuite/gcc.dg/pr87074.c new file mode 100644 index 00000000000..d838fcd8fc5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr87074.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -floop-unroll-and-jam --param unroll-jam-min-percent=0" } */ +long b; +unsigned c[5]; +unsigned long long d = 3; +int e, f, g; + +void h() { + for (; f < 11; f++) { + b = g; + for (e = 0; e < 5; e++) { + c[e] = e - b - (c[e] >> 5); + g = c[e]; + } + } + if (c[0]) + d = 0; +} + +extern void abort(void); +int main() { + h(); + if (d != 0) + abort (); +}