From patchwork Sun Jun 16 18:08:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Hubicka X-Patchwork-Id: 1116615 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-503029-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=ucw.cz 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 45Rj562SkCz9s4Y for ; Mon, 17 Jun 2019 04:08:21 +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:subject:message-id:mime-version:content-type; q=dns; s= default; b=ehJTD4OQT9zeizaQIiaLVCXnAr8rWyqOfqJr4NTyogzsMpVnl+MrV NctIB+g5a7P2XB1fEiB21MEo1OF/h2mxwpODQRJI7YCqC4G8ghLME9CiOxRGKgR7 xhMSOLnzv9KRKW8u9c2F7+SX6DkXPlQKrKay6FLTNm4HWnbLm+H6ec= 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=j0tVf8sMe4Z/FMoNkhy6tlIS1fE=; b=MYg0rajNcwpciGks0Jlh /heB8WcGvZTNDCHgtjE8YuqxoS70gMQdAjdpQiKMwLYQfX5EaxgOiZkFAKXdRuOX mPQ4HU/zsXYZ0w/K0+W0dNlxXnqRbUP8BYyQCEgc4VeB+bwe2E83WWfYDA6b5rYm y90oKefolnmRXM+ktHSalF4= Received: (qmail 95776 invoked by alias); 16 Jun 2019 18:08: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 95767 invoked by uid 89); 16 Jun 2019 18:08:13 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-9.7 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, KAM_NUMSUBJECT autolearn=ham version=3.3.1 spammy=compares, COMPONENT_REF, component_ref, enabling X-HELO: nikam.ms.mff.cuni.cz Received: from nikam.ms.mff.cuni.cz (HELO nikam.ms.mff.cuni.cz) (195.113.20.16) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sun, 16 Jun 2019 18:08:11 +0000 Received: by nikam.ms.mff.cuni.cz (Postfix, from userid 16202) id 637BB2825AE; Sun, 16 Jun 2019 20:08:08 +0200 (CEST) Date: Sun, 16 Jun 2019 20:08:08 +0200 From: Jan Hubicka To: gcc-patches@gcc.gnu.org, rguenther@suse.de, d@dcepelik.cz Subject: Fix aliasing_component_refs WRT trailing arrays of size 0 Message-ID: <20190616180808.trrvddiqe5jxvgu6@kam.mff.cuni.cz> MIME-Version: 1.0 Content-Disposition: inline User-Agent: NeoMutt/20170113 (1.7.2) Hi, while enabling bit more of alias oracle I have noticed that the size comparsion in aliasing_component_refs_p may lead to false negatives when struct contain trailing array of size 0. In that case the size of a an element of that array is bigger then size of the struct. This is fixed by the following patch: while walking the access path we look for component refs of arrays size 0 or NULL and if they are at the end of struct we record them. I added check that there is at most one in the path passing array_at_struct_end_p. Leter the size compares is used for following decisions 1) whether walk path1 or path2. Here we want to take into account the size of path1/2 may actually increase, so in addition to compare type1 and type2 we want to compare with the element size of trailing array. 2) when looking for type match we still want to compare type1/type2 because there is no way to bypass the outer structure. However we do not want to give up too early deciding that type in question is too small. 3) When deciding whether one path can continue by another, we can actually use the bigger size. Note that we do not need to bother about zero sized array reference in the path continuation since memory access of ref type will not write/read into the array. I can only construct exaple when the outer types does not match (becuase then we do conservative offset/max_size decision) and thus the extra union but I think the testcase is still valid C. Bootstrapped/regtested x86_64-linux, comitted. * gcc.dg/tree-ssa/alias-access-path-4.c: New testcase. * gcc.dg/tree-ssa/alias-access-path-5.c: New testcase. * tree-ssa-alias.c (aliasing_component_refs_p): Watch for arrays at the end of structures. Index: tree-ssa-alias.c =================================================================== --- tree-ssa-alias.c (revision 272354) +++ tree-ssa-alias.c (working copy) @@ -877,22 +877,62 @@ aliasing_component_refs_p (tree ref1, tree *refp; int same_p1 = 0, same_p2 = 0; bool maybe_match = false; + tree end_struct_ref1 = NULL, end_struct_ref2 = NULL; /* Choose bases and base types to search for. */ base1 = ref1; while (handled_component_p (base1)) - base1 = TREE_OPERAND (base1, 0); + { + /* Generally access paths are monotous in the size of object. The + exception are trailing arrays of structures. I.e. + struct a {int array[0];}; + or + struct a {int array1[0]; int array[];}; + Such struct has size 0 but accesses to a.array may have non-zero size. + In this case the size of TREE_TYPE (base1) is smaller than + size of TREE_TYPE (TREE_OPERNAD (base1, 0)). + + Because we compare sizes of arrays just by sizes of their elements, + we only need to care about zero sized array fields here. */ + if (TREE_CODE (base1) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (TREE_OPERAND (base1, 1))) == ARRAY_TYPE + && (!TYPE_SIZE (TREE_TYPE (TREE_OPERAND (base1, 1))) + || integer_zerop (TYPE_SIZE (TREE_TYPE (TREE_OPERAND (base1, 1))))) + && array_at_struct_end_p (base1)) + { + gcc_checking_assert (!end_struct_ref1); + end_struct_ref1 = base1; + } + base1 = TREE_OPERAND (base1, 0); + } type1 = TREE_TYPE (base1); base2 = ref2; while (handled_component_p (base2)) - base2 = TREE_OPERAND (base2, 0); + { + if (TREE_CODE (base2) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (TREE_OPERAND (base2, 1))) == ARRAY_TYPE + && (!TYPE_SIZE (TREE_TYPE (TREE_OPERAND (base2, 1))) + || integer_zerop (TYPE_SIZE (TREE_TYPE (TREE_OPERAND (base2, 1))))) + && array_at_struct_end_p (base2)) + { + gcc_checking_assert (!end_struct_ref2); + end_struct_ref2 = base2; + } + base2 = TREE_OPERAND (base2, 0); + } type2 = TREE_TYPE (base2); /* Now search for the type1 in the access path of ref2. This would be a common base for doing offset based disambiguation on. This however only makes sense if type2 is big enough to hold type1. */ int cmp_outer = compare_type_sizes (type2, type1); - if (cmp_outer >= 0) + + /* If type2 is big enough to contain type1 walk its access path. + We also need to care of arrays at the end of structs that may extend + beyond the end of structure. */ + if (cmp_outer >= 0 + || (end_struct_ref2 + && compare_type_sizes (TREE_TYPE (end_struct_ref2), type1) >= 0)) { refp = &ref2; while (true) @@ -900,7 +940,11 @@ aliasing_component_refs_p (tree ref1, /* We walk from inner type to the outer types. If type we see is already too large to be part of type1, terminate the search. */ int cmp = compare_type_sizes (type1, TREE_TYPE (*refp)); - if (cmp < 0) + + if (cmp < 0 + && (!end_struct_ref1 + || compare_type_sizes (TREE_TYPE (end_struct_ref1), + TREE_TYPE (*refp)) < 0)) break; /* If types may be of same size, see if we can decide about their equality. */ @@ -957,13 +1001,18 @@ aliasing_component_refs_p (tree ref1, } /* If we didn't find a common base, try the other way around. */ - if (cmp_outer <= 0) + if (cmp_outer <= 0 + || (end_struct_ref1 + && compare_type_sizes (TREE_TYPE (end_struct_ref1), type1) <= 0)) { refp = &ref1; while (true) { int cmp = compare_type_sizes (type2, TREE_TYPE (*refp)); - if (cmp < 0) + if (cmp < 0 + && (!end_struct_ref2 + || compare_type_sizes (TREE_TYPE (end_struct_ref2), + TREE_TYPE (*refp)) < 0)) break; /* If types may be of same size, see if we can decide about their equality. */ @@ -1022,8 +1071,14 @@ aliasing_component_refs_p (tree ref1, But we can still have a path that goes B1.path1...B2.path2 with a part that we do not see. So we can only disambiguate now if there is no B2 in the tail of path1 and no B1 on the tail of path2. */ if (compare_type_sizes (TREE_TYPE (ref2), type1) >= 0 + && (!end_struct_ref1 + || compare_type_sizes (TREE_TYPE (ref2), + TREE_TYPE (end_struct_ref1)) >= 0) && type_has_components_p (TREE_TYPE (ref2)) && (base1_alias_set == ref2_alias_set || alias_set_subset_of (base1_alias_set, ref2_alias_set))) @@ -1034,6 +1089,9 @@ aliasing_component_refs_p (tree ref1, /* If this is ptr vs. decl then we know there is no ptr ... decl path. */ if (!ref2_is_decl && compare_type_sizes (TREE_TYPE (ref1), type2) >= 0 + && (!end_struct_ref2 + || compare_type_sizes (TREE_TYPE (ref1), + TREE_TYPE (end_struct_ref2)) >= 0) && type_has_components_p (TREE_TYPE (ref1)) && (base2_alias_set == ref1_alias_set || alias_set_subset_of (base2_alias_set, ref1_alias_set))) Index: testsuite/gcc.dg/tree-ssa/alias-access-path-4.c =================================================================== --- testsuite/gcc.dg/tree-ssa/alias-access-path-4.c (nonexistent) +++ testsuite/gcc.dg/tree-ssa/alias-access-path-4.c (working copy) @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +struct a {int v1; + int v2;}; +struct b {struct a a[0];}; +union c {struct b b;}; + +int +test (struct b *bptr1, union c *cptr, int i, int j) +{ + bptr1->a[i].v1=123; + cptr->b.a[j].v2=1; + return bptr1->a[i].v1; +} +int +test2 (struct b *bptr1, union c *cptr, int i, int j) +{ + bptr1->a[i].v1=124; + cptr->b.a[j].v1=1; + return bptr1->a[i].v1; +} +/* { dg-final { scan-tree-dump-times "return 123" 1 "optimized"} } */ +/* { dg-final { scan-tree-dump-not "return 124" "optimized"} } */ Index: testsuite/gcc.dg/tree-ssa/alias-access-path-5.c =================================================================== --- testsuite/gcc.dg/tree-ssa/alias-access-path-5.c (nonexistent) +++ testsuite/gcc.dg/tree-ssa/alias-access-path-5.c (working copy) @@ -0,0 +1,25 @@ + +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +struct a {int v1; + int v2;}; +struct b {int array[0]; struct a a[];}; +union c {struct b b;}; + +int +test (struct b *bptr1, union c *cptr, int i, int j) +{ + bptr1->a[i].v1=123; + cptr->b.a[j].v2=1; + return bptr1->a[i].v1; +} +int +test2 (struct b *bptr1, union c *cptr, int i, int j) +{ + bptr1->a[i].v1=124; + cptr->b.a[j].v1=1; + return bptr1->a[i].v1; +} +/* { dg-final { scan-tree-dump-times "return 123" 1 "optimized"} } */ +/* { dg-final { scan-tree-dump-not "return 124" "optimized"} } */