From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 22153 invoked by alias); 13 Nov 2007 15:45:17 -0000 Received: (qmail 22088 invoked by uid 22791); 13 Nov 2007 15:45:13 -0000 X-Spam-Check-By: sourceware.org Received: from smtp-out.google.com (HELO smtp-out.google.com) (216.239.45.13) by sourceware.org (qpsmtpd/0.31) with ESMTP; Tue, 13 Nov 2007 15:45:00 +0000 Received: from zps18.corp.google.com (zps18.corp.google.com [172.25.146.18]) by smtp-out.google.com with ESMTP id lADFivvL023754 for ; Tue, 13 Nov 2007 07:44:57 -0800 Received: from py-out-1112.google.com (pyea73.prod.google.com [10.34.153.73]) by zps18.corp.google.com with ESMTP id lADFiklT025505 for ; Tue, 13 Nov 2007 07:44:57 -0800 Received: by py-out-1112.google.com with SMTP id a73so2266824pye for ; Tue, 13 Nov 2007 07:44:57 -0800 (PST) Received: by 10.64.213.3 with SMTP id l3mr16771165qbg.1194968696604; Tue, 13 Nov 2007 07:44:56 -0800 (PST) Received: from legolas.novillo.homelinux.org ( [99.229.48.247]) by mx.google.com with ESMTPS id f13sm4558318qba.2007.11.13.07.44.52 (version=TLSv1/SSLv3 cipher=RC4-MD5); Tue, 13 Nov 2007 07:44:53 -0800 (PST) Message-ID: <4739C673.5080905@google.com> Date: Tue, 13 Nov 2007 16:30:00 -0000 From: Diego Novillo User-Agent: Thunderbird 2.0.0.5 (X11/20070727) MIME-Version: 1.0 To: Richard Guenther CC: gcc-patches@gcc.gnu.org Subject: Re: Fix PR 33870 References: <84fc9c000711080245n4f52e669gbcecaa3485f55161@mail.gmail.com> In-Reply-To: <84fc9c000711080245n4f52e669gbcecaa3485f55161@mail.gmail.com> Content-Type: multipart/mixed; boundary="------------060709080203040903000508" X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org X-SW-Source: 2007-11/txt/msg00725.txt.bz2 This is a multi-part message in MIME format. --------------060709080203040903000508 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 4038 Richard Guenther wrote: > taking the address of result.x.pDirty causes the SFT to be marked as > in substructure and the problem re-surfaces. Yes. Thanks for the test case. The original patch did not take into account that the nesting level of the memory reference is also important. There are two problems here: 1- Given an arbitrary memory expression M dereferencing a pointer P into a nested structure, the offset computed for M is the offset starting at P. However, the offsets computed for the original SFTs are offsets from the top of the pointed-to memory object O. So, when we recognize this situation, we must adjust the offsets. This was the situation recognized and fixed by the original patch. The bug was in the detection of whether P is "pointing to the middle of an object". This is where the nesting level comes in to play. Suppose that M was the expression p_3->b[3] and the original pointed-to object was v.x.y: struct { ... struct { ... struct { ... int b[4]; } y; } x; } v; p_3 = &v.x.y; If alias analysis created SFTs for this structure, the array 'b' will have 4 SFTs associated with it. Say SFT.12, SFT.13, SFT.14 and SFT.15. However, only SFT.12 will be added to the alias set of p_3's name tag. So, when we see the expression 'p_3->b[3]', we compute an offset of 96, but we need SFT.14 which will probably have an offset much higher than that. So, we adjust 96 by the offset of SFT.12 and get to SFT.14. In the original patch, we recognized this situation by asking whether the SFT.12 was inside a nested structure. However, it may happen that the pointer was actually pointing to the base of the original object 'v'. In which case, we would have the expression 'p_3->x.y.b[3]', which also takes us to SFT.12. But in this case, the offset we computed from 'p_3->x.y.b[3]' is *already* the right offset, so adding the offset of SFT.12 to it gives us the wrong offset. So, what this patch does is determine the nesting level of each SFT and the nesting level of the memory expression. We only need to adjust the offset of an SFT if the nesting level of the memory expression is lower than the nesting level of the SFT that we are analyzing. 2- The second problem we have with this scheme is that we rely on the presence of key SFTs to adjust offsets when we detect references to nested aggregates. This is something we cannot easily undo because inside the operand scanner we cannot really start doing use-def chain chasing to determine the original pointed-to objects. This work has already been done by alias analysis, so duplicating this in the operand scanner would be wasteful. This means that this scheme cannot tolerate these key SFTs to be partitioned away. If they are partitioned, then inside the operand scanner is essentially impossible to determine where in the structure is an arbitrary memory expression referring to. This is shown in the new test gcc.dg/tree-ssa/alias-16.c. One way to deal with this would be to use the pointed-to set for the base pointer instead of the alias set of the name tag. This has the problem that we'd miss the compile-time benefits of partitioning, as we would be traversing the original sets instead of the partitioned (smaller) alias sets. Also, we may want to get rid of the duplicate pointed-to/alias sets in the future (not sure if they're both worth keeping). The other way of dealing with this is to recognize which SFTs are important to not partition and make sure they are never partitioned. During alias analysis, if a nested SFT is added to the alias set of a pointer, then it is marked as unpartitionable. The partitioner, in turn, gives these SFTs a very high score and makes sure that they are never added to a partition. The effects of this are/should be negligible as it only involves a single SFT and nested structures. The new test alias-16.c tests for these edge cases. Tested on x86_64 and ppc64. Committed to trunk. Diego. --------------060709080203040903000508 Content-Type: text/plain; name="20071113-33870-nesting-level.diff.txt" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="20071113-33870-nesting-level.diff.txt" Content-length: 21492 2007-11-12 Diego Novillo PR 33870 * tree.h (strcut tree_memory_tag): Add field unpartitionable. Remove field in_nested_struct. (struct tree_struct_field_tag): Add field nesting_level. (SFT_IN_NESTED_STRUCT): Remove. (SFT_NESTING_LEVEL): Define. (SFT_UNPARTITIONABLE_P): Define. * tree-ssa-alias.c (mem_sym_score): If MP->VAR is not partitionable, return LONG_MAX. (compute_memory_partitions): Do not partition SFTs marked unpartitionable. (create_sft): Add argument NESTING_LEVEL. Set SFT_NESTING_LEVEL with it. Update all users. (create_overlap_variables_for): Show nesting level. * tree-dfa.c (dump_subvars_for): Likewise. (dump_variable): Likewise. Show whether the SFT is partitionable or not. * tree-flow.h (struct fieldoff): Remove field in_nested_struct. Add field nesting_level. * tree-ssa-structalias.c (struct variable_info): Remove field in_nested_struct. (push_fields_onto_fieldstack): Add argument NESTING_LEVEL. Update all users. Update documentation. Update PAIR->NESTING_LEVEL with NESTING_LEVEL. Make recursive calls with NESTING_LEVEL + 1. (set_uids_in_ptset): If an SFT is added to the points-to set, mark it as unpartitionable. * tree-ssa-operands.c (ref_nesting_level): New. (add_vars_for_offset): Call it. Add argument FULL_REF. Update callers. If VAR is inside a nested structure and the nesting level of FULL_REF is lower than the nesting level of VAR, adjust OFFSET by the offset of VAR. testsuite/ChangeLog PR 33870 * gcc.c-torture/execute/pr33870-1.c: New test. * gcc.dg/tree-ssa/alias-16.c: New test. Index: tree.h =================================================================== --- tree.h (revision 130139) +++ tree.h (working copy) @@ -2555,10 +2555,10 @@ struct tree_memory_tag GTY(()) bitmap GTY ((skip)) aliases; /* True if this tag has global scope. */ - unsigned int is_global:1; + unsigned int is_global : 1; - /* True if this SFT is for a field in a nested structure. */ - unsigned int in_nested_struct : 1; + /* True if this tag should not be grouped into a memory partition. */ + unsigned int unpartitionable : 1; }; #define MTAG_GLOBAL(NODE) (TREE_MEMORY_TAG_CHECK (NODE)->mtag.is_global) @@ -2579,6 +2579,11 @@ struct tree_struct_field_tag GTY(()) /* Alias set for a DECL_NONADDRESSABLE_P field. Otherwise -1. */ alias_set_type alias_set; + + /* Nesting level for this subvariable. This indicates how many + structures are wrapping this field. Fields at the top level have + a nesting level of 0. */ + unsigned int nesting_level; }; #define SFT_PARENT_VAR(NODE) (STRUCT_FIELD_TAG_CHECK (NODE)->sft.parent_var) @@ -2587,8 +2592,10 @@ struct tree_struct_field_tag GTY(()) #define SFT_NONADDRESSABLE_P(NODE) \ (STRUCT_FIELD_TAG_CHECK (NODE)->sft.alias_set != -1) #define SFT_ALIAS_SET(NODE) (STRUCT_FIELD_TAG_CHECK (NODE)->sft.alias_set) -#define SFT_IN_NESTED_STRUCT(NODE) \ - (STRUCT_FIELD_TAG_CHECK (NODE)->sft.common.in_nested_struct) +#define SFT_NESTING_LEVEL(NODE) \ + (STRUCT_FIELD_TAG_CHECK (NODE)->sft.nesting_level) +#define SFT_UNPARTITIONABLE_P(NODE) \ + (STRUCT_FIELD_TAG_CHECK (NODE)->sft.common.unpartitionable) /* Memory Partition Tags (MPTs) group memory symbols under one common name for the purposes of placing memory PHI nodes. */ Index: testsuite/gcc.c-torture/execute/pr33870-1.c =================================================================== --- testsuite/gcc.c-torture/execute/pr33870-1.c (revision 0) +++ testsuite/gcc.c-torture/execute/pr33870-1.c (revision 0) @@ -0,0 +1,94 @@ +extern void abort (void); + +typedef struct PgHdr PgHdr; +typedef unsigned char u8; +struct PgHdr { +int y; +struct { + unsigned int pgno; + PgHdr *pNextHash, *pPrevHash; + PgHdr *pNextFree, *pPrevFree; + PgHdr *pNextAll; + u8 inJournal; + short int nRef; + PgHdr *pDirty, *pPrevDirty; + unsigned int notUsed; +} x; +}; +PgHdr **xx; +volatile int vx; +static inline PgHdr *merge_pagelist(PgHdr *pA, PgHdr *pB) +{ + PgHdr result; + PgHdr *pTail; + xx = &result.x.pDirty; + pTail = &result; + while( pA && pB ){ + if( pA->x.pgnox.pgno ){ + pTail->x.pDirty = pA; + pTail = pA; + pA = pA->x.pDirty; + }else{ + pTail->x.pDirty = pB; + pTail = pB; + pB = pB->x.pDirty; + } + vx = (*xx)->y; + } + if( pA ){ + pTail->x.pDirty = pA; + }else if( pB ){ + pTail->x.pDirty = pB; + }else{ + pTail->x.pDirty = 0; + } + return result.x.pDirty; +} + +PgHdr * __attribute__((noinline)) sort_pagelist(PgHdr *pIn) +{ + PgHdr *a[25], *p; + int i; + __builtin_memset (a, 0, sizeof (a)); + while( pIn ){ + p = pIn; + pIn = p->x.pDirty; + p->x.pDirty = 0; + for(i=0; i<25 -1; i++){ + if( a[i]==0 ){ + a[i] = p; + break; + }else{ + p = merge_pagelist(a[i], p); + a[i] = 0; + a[i] = 0; + } + } + if( i==25 -1 ){ + a[i] = merge_pagelist(a[i], p); + } + } + p = a[0]; + for(i=1; i<25; i++){ + p = merge_pagelist (p, a[i]); + } + return p; +} + +int main() +{ + PgHdr a[5]; + PgHdr *p; + a[0].x.pgno = 5; + a[0].x.pDirty = &a[1]; + a[1].x.pgno = 4; + a[1].x.pDirty = &a[2]; + a[2].x.pgno = 1; + a[2].x.pDirty = &a[3]; + a[3].x.pgno = 3; + a[3].x.pDirty = 0; + p = sort_pagelist (&a[0]); + if (p->x.pDirty == p) + abort (); + return 0; +} Index: testsuite/gcc.dg/tree-ssa/alias-16.c =================================================================== --- testsuite/gcc.dg/tree-ssa/alias-16.c (revision 0) +++ testsuite/gcc.dg/tree-ssa/alias-16.c (revision 0) @@ -0,0 +1,33 @@ +/* { dg-do run } */ +/* { dg-options "-O --param max-aliased-vops=1" } */ + +/* Compile with -O --param max-aliased-vops=1. This partitions all + the initial SFTs for 'm' which was causing the operand scanner to + miss adding the right SFTs to p->b[2]. */ +extern void abort (void); + +struct X { + int a; + struct Y { + int b[4]; + } b; + struct Y c; +} m; + +struct X n; + +foo (int i) +{ + struct Y *p = (i > 10) ? &m.b : &n.c; + p->b[2] = 10; + m.b.b[3] = 6; + n.c.b[2] = 3; + return p->b[2] + n.c.b[2] + m.b.b[3]; +} + +main() +{ + if (foo (3) != 12) + abort (); + return 0; +} Index: tree-ssa-alias.c =================================================================== --- tree-ssa-alias.c (revision 130139) +++ tree-ssa-alias.c (working copy) @@ -828,6 +828,13 @@ count_mem_refs (long *num_vuses_p, long static inline long mem_sym_score (mem_sym_stats_t mp) { + /* Unpartitionable SFTs are automatically thrown to the bottom of + the list. They are not stored in partitions, but they are used + for computing overall statistics. */ + if (TREE_CODE (mp->var) == STRUCT_FIELD_TAG + && SFT_UNPARTITIONABLE_P (mp->var)) + return LONG_MAX; + return mp->frequency_writes * 64 + mp->frequency_reads * 32 + mp->num_direct_writes * 16 + mp->num_direct_reads * 8 + mp->num_indirect_writes * 4 + mp->num_indirect_reads * 2 @@ -1392,8 +1399,8 @@ update_reference_counts (struct mem_ref_ static void build_mp_info (struct mem_ref_stats_d *mem_ref_stats, - VEC(mem_sym_stats_t,heap) **mp_info_p, - VEC(tree,heap) **tags_p) + VEC(mem_sym_stats_t,heap) **mp_info_p, + VEC(tree,heap) **tags_p) { tree var; referenced_var_iterator rvi; @@ -1591,6 +1598,15 @@ compute_memory_partitions (void) if (!need_to_partition_p (mem_ref_stats)) break; + /* SFTs that are marked unpartitionable should not be added to + partitions. These SFTs are special because they mark the + first SFT into a structure where a pointer is pointing to. + This is needed by the operand scanner to find adjacent + fields. See add_vars_for_offset for details. */ + if (TREE_CODE (mp_p->var) == STRUCT_FIELD_TAG + && SFT_UNPARTITIONABLE_P (mp_p->var)) + continue; + mpt = find_partition_for (mp_p); estimate_vop_reduction (mem_ref_stats, mp_p, mpt); } @@ -3774,7 +3790,8 @@ get_or_create_used_part_for (size_t uid) static tree create_sft (tree var, tree field, unsigned HOST_WIDE_INT offset, - unsigned HOST_WIDE_INT size, alias_set_type alias_set) + unsigned HOST_WIDE_INT size, alias_set_type alias_set, + unsigned nesting_level) { tree subvar = create_tag_raw (STRUCT_FIELD_TAG, field, "SFT"); @@ -3794,6 +3811,8 @@ create_sft (tree var, tree field, unsign SFT_OFFSET (subvar) = offset; SFT_SIZE (subvar) = size; SFT_ALIAS_SET (subvar) = alias_set; + SFT_NESTING_LEVEL (subvar) = nesting_level; + return subvar; } @@ -3814,7 +3833,7 @@ create_overlap_variables_for (tree var) return; push_fields_onto_fieldstack (TREE_TYPE (var), &fieldstack, 0, NULL, - TREE_TYPE (var)); + TREE_TYPE (var), 0); if (VEC_length (fieldoff_s, fieldstack) != 0) { subvar_t *subvars; @@ -3897,7 +3916,6 @@ create_overlap_variables_for (tree var) field, skip it. Note that we always need the field at offset 0 so we can properly handle pointers to the structure. */ - if ((fo->offset != 0 && ((fo->offset <= up->minused && fo->offset + fosize <= up->minused) @@ -3906,8 +3924,9 @@ create_overlap_variables_for (tree var) && fosize == lastfosize && currfotype == lastfotype)) continue; - subvar = create_sft (var, fo->type, fo->offset, - fosize, fo->alias_set); + + subvar = create_sft (var, fo->type, fo->offset, fosize, + fo->alias_set, fo->nesting_level); VEC_quick_push (tree, *subvars, subvar); if (dump_file) @@ -3918,7 +3937,8 @@ create_overlap_variables_for (tree var) SFT_OFFSET (subvar)); fprintf (dump_file, " size " HOST_WIDE_INT_PRINT_DEC, SFT_SIZE (subvar)); - fprintf (dump_file, "\n"); + fprintf (dump_file, " nesting level %d\n", + SFT_NESTING_LEVEL (subvar)); } lastfotype = currfotype; Index: tree-dfa.c =================================================================== --- tree-dfa.c (revision 130139) +++ tree-dfa.c (working copy) @@ -287,7 +287,9 @@ dump_subvars_for (FILE *file, tree var) for (i = 0; VEC_iterate (tree, sv, i, subvar); ++i) { print_generic_expr (file, subvar, dump_flags); - fprintf (file, "@" HOST_WIDE_INT_PRINT_UNSIGNED " ", SFT_OFFSET (subvar)); + fprintf (file, "@" HOST_WIDE_INT_PRINT_UNSIGNED, SFT_OFFSET (subvar)); + fprintf (file, "[%u]", SFT_NESTING_LEVEL (subvar)); + fprintf (file, " "); } fprintf (file, "}"); @@ -417,6 +419,15 @@ dump_variable (FILE *file, tree var) fprintf (file, ", partition symbols: "); dump_decl_set (file, MPT_SYMBOLS (var)); } + + if (TREE_CODE (var) == STRUCT_FIELD_TAG) + { + fprintf (file, ", offset: " HOST_WIDE_INT_PRINT_UNSIGNED, + SFT_OFFSET (var)); + fprintf (file, ", nesting: %u", SFT_NESTING_LEVEL (var)); + fprintf (file, ", partitionable: %s", + SFT_UNPARTITIONABLE_P (var) ? "NO" : "YES"); + } } fprintf (file, "\n"); Index: tree-flow.h =================================================================== --- tree-flow.h (revision 130139) +++ tree-flow.h (working copy) @@ -1159,9 +1159,9 @@ struct fieldoff /* Field. */ tree decl; - /* True if this field is inside a structure nested inside the base - containing object. */ - unsigned int in_nested_struct : 1; + /* Nesting level. This number represents how many structures are + wrapping this field. */ + unsigned nesting_level; /* Offset from the base of the base containing object to this field. */ HOST_WIDE_INT offset; @@ -1173,8 +1173,8 @@ typedef struct fieldoff fieldoff_s; DEF_VEC_O(fieldoff_s); DEF_VEC_ALLOC_O(fieldoff_s,heap); -int push_fields_onto_fieldstack (tree, VEC(fieldoff_s,heap) **, - HOST_WIDE_INT, bool *, tree); +int push_fields_onto_fieldstack (tree, VEC(fieldoff_s,heap) **, HOST_WIDE_INT, + bool *, tree, unsigned); void sort_fieldstack (VEC(fieldoff_s,heap) *); void init_alias_heapvars (void); Index: tree-ssa-structalias.c =================================================================== --- tree-ssa-structalias.c (revision 130139) +++ tree-ssa-structalias.c (working copy) @@ -253,15 +253,6 @@ struct variable_info variable. This is used for C++ placement new. */ unsigned int no_tbaa_pruning : 1; - /* True if this variable is inside a structure nested in the - structure for the base variable. For instance, in - struct X { int a; struct Y { int b; int c; } }, the variables for - fields 'b' and 'c' are inside a nested structure. We are not - interested in tracking how many levels of nesting, just whether - there is nesting at all. This is later used to adjust offsets - for pointers pointing into sub-structures. */ - unsigned int in_nested_struct : 1; - /* Points-to set for this variable. */ bitmap solution; @@ -4050,19 +4041,28 @@ sort_fieldstack (VEC(fieldoff_s,heap) *f fieldoff_compare); } -/* Given a TYPE, and a vector of field offsets FIELDSTACK, push all the fields - of TYPE onto fieldstack, recording their offsets along the way. - OFFSET is used to keep track of the offset in this entire structure, rather - than just the immediately containing structure. Returns the number - of fields pushed. +/* Given a TYPE, and a vector of field offsets FIELDSTACK, push all + the fields of TYPE onto fieldstack, recording their offsets along + the way. + + OFFSET is used to keep track of the offset in this entire + structure, rather than just the immediately containing structure. + Returns the number of fields pushed. + HAS_UNION is set to true if we find a union type as a field of - TYPE. ADDRESSABLE_TYPE is the type of the outermost object that could have - its address taken. */ + TYPE. + + ADDRESSABLE_TYPE is the type of the outermost object that could + have its address taken. + + NESTING_LEVEL indicates whether TYPE is a structure nested inside + another, it starts at 0 and it is incremented by one on every + structure recursed into. */ int push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack, HOST_WIDE_INT offset, bool *has_union, - tree addressable_type) + tree addressable_type, unsigned nesting_level) { tree field; int count = 0; @@ -4119,11 +4119,14 @@ push_fields_onto_fieldstack (tree type, if (!AGGREGATE_TYPE_P (TREE_TYPE (type))) /* var_can_have_subvars */ push = true; else if (!(pushed = push_fields_onto_fieldstack - (TREE_TYPE (type), fieldstack, - offset + i * TREE_INT_CST_LOW (elsz), has_union, + (TREE_TYPE (type), + fieldstack, + offset + i * TREE_INT_CST_LOW (elsz), + has_union, (TYPE_NONALIASED_COMPONENT (type) ? addressable_type - : TREE_TYPE (type))))) + : TREE_TYPE (type)), + nesting_level + 1))) /* Empty structures may have actual size, like in C++. So see if we didn't push any subfields and the size is nonzero, push the field onto the stack */ @@ -4142,12 +4145,7 @@ push_fields_onto_fieldstack (tree type, pair->alias_set = get_alias_set (addressable_type); else pair->alias_set = -1; - - /* If the base offset is positive, this field belongs to - a structure nested inside the base structure. */ - if (offset > 0) - pair->in_nested_struct = true; - + pair->nesting_level = nesting_level; count++; } else @@ -4171,11 +4169,14 @@ push_fields_onto_fieldstack (tree type, if (!var_can_have_subvars (field)) push = true; else if (!(pushed = push_fields_onto_fieldstack - (TREE_TYPE (field), fieldstack, - offset + bitpos_of_field (field), has_union, + (TREE_TYPE (field), + fieldstack, + offset + bitpos_of_field (field), + has_union, (DECL_NONADDRESSABLE_P (field) ? addressable_type - : TREE_TYPE (field)))) + : TREE_TYPE (field)), + nesting_level + 1)) && DECL_SIZE (field) && !integer_zerop (DECL_SIZE (field))) /* Empty structures may have actual size, like in C++. So @@ -4196,12 +4197,7 @@ push_fields_onto_fieldstack (tree type, pair->alias_set = get_alias_set (addressable_type); else pair->alias_set = -1; - - /* If the base offset is positive, this field belongs to - a structure nested inside the base structure. */ - if (offset > 0) - pair->in_nested_struct = true; - + pair->nesting_level = nesting_level; count++; } else @@ -4401,7 +4397,7 @@ create_variable_info_for (tree decl, con if (var_can_have_subvars (decl) && use_field_sensitive && !hasunion) { push_fields_onto_fieldstack (decltype, &fieldstack, 0, &hasunion, - decltype); + decltype, 0); if (hasunion) { VEC_free (fieldoff_s, heap, fieldstack); @@ -4512,7 +4508,6 @@ create_variable_info_for (tree decl, con newvi->offset = fo->offset; newvi->size = TREE_INT_CST_LOW (fo->size); newvi->fullsize = vi->fullsize; - newvi->in_nested_struct = fo->in_nested_struct; insert_into_field_list (vi, newvi); VEC_safe_push (varinfo_t, heap, varmap, newvi); if (is_global && (!flag_whole_program || !in_ipa_mode)) @@ -4764,8 +4759,20 @@ set_uids_in_ptset (tree ptr, bitmap into if (no_tbaa_pruning || (!is_derefed && !vi->directly_dereferenced) || alias_sets_conflict_p (ptr_alias_set, var_alias_set)) - bitmap_set_bit (into, DECL_UID (sft)); - SFT_IN_NESTED_STRUCT (sft) = vi->in_nested_struct; + { + bitmap_set_bit (into, DECL_UID (sft)); + + /* If SFT is inside a nested structure, it will + be needed by the operand scanner to adjust + offsets when adding operands to memory + expressions that dereference PTR. This means + that memory partitioning may not partition + this SFT because the operand scanner will not + be able to find the other SFTs next to this + one. */ + if (SFT_NESTING_LEVEL (sft) > 0) + SFT_UNPARTITIONABLE_P (sft) = true; + } } } else Index: tree-ssa-operands.c =================================================================== --- tree-ssa-operands.c (revision 130139) +++ tree-ssa-operands.c (working copy) @@ -1367,8 +1367,33 @@ access_can_touch_variable (tree ref, tre return true; } + +/* Given an aggregate expression FULL_REF, return the number of + aggregates that are containing FULL_REF. So, given a structure + reference a.b.c.d, the nesting level for this expression is 2 (the + number of '.' in the expression minus 1). */ + +static unsigned +ref_nesting_level (tree full_ref) +{ + unsigned nesting_level = 0; + + if (!handled_component_p (full_ref)) + return 0; + + full_ref = TREE_OPERAND (full_ref, 0); + while (handled_component_p (full_ref)) + { + nesting_level++; + full_ref = TREE_OPERAND (full_ref, 0); + } + + return nesting_level; +} + + /* Add the actual variables FULL_REF can access, given a member of - full_ref's points-to set VAR, where FULL_REF is an access of SIZE at + FULL_REF's points-to set VAR, where FULL_REF is an access of SIZE at OFFSET from var. IS_CALL_SITE is true if this is a call, and IS_DEF is true if this is supposed to be a vdef, and false if this should be a VUSE. @@ -1386,10 +1411,12 @@ access_can_touch_variable (tree ref, tre This is necessary because foop only actually points to foo's first member, so that is all the points-to set contains. However, an access to foop->a may be touching some single SFT if we have created some - SFT's for a structure. */ + SFT's for a structure. + + FULL_REF is the original memory expression being analyzed. */ static bool -add_vars_for_offset (tree var, unsigned HOST_WIDE_INT offset, +add_vars_for_offset (tree full_ref, tree var, unsigned HOST_WIDE_INT offset, unsigned HOST_WIDE_INT size, bool is_def) { bool added = false; @@ -1397,14 +1424,21 @@ add_vars_for_offset (tree var, unsigned subvar_t sv; unsigned int i; - if (SFT_IN_NESTED_STRUCT (var)) + if (full_ref + && SFT_NESTING_LEVEL (var) > 0 + && ref_nesting_level (full_ref) < SFT_NESTING_LEVEL (var)) { /* Since VAR is an SFT inside a nested structure, the OFFSET computed by get_ref_base_and_extent is the offset from the - start of the immediately containing structure. However, to - find out what other SFTs are affected by this reference, we - need to know the offsets starting at the root structure in - the nesting hierarchy. + start of the immediately containing structure. If VAR is an + SFT inside a nested structure, then FULL_REF may be a + reference to the structure immediately enclosing SFT, and so + OFFSET will be the offset from the start of the immediately + enclosing structure. + + However, to find out what other SFTs are affected by this + reference, we need to know the offsets starting at the root + structure in the nesting hierarchy. For instance, given the following structure: @@ -1541,7 +1575,7 @@ add_virtual_operand (tree var, stmt_ann_ if it is a potential points-to location. */ if (TREE_CODE (al) == STRUCT_FIELD_TAG && TREE_CODE (var) == NAME_MEMORY_TAG) - none_added &= !add_vars_for_offset (al, offset, size, + none_added &= !add_vars_for_offset (full_ref, al, offset, size, flags & opf_def); else { --------------060709080203040903000508--