[PATCH] Fix pointer-arithmetic in PTA (revised)

H.J. Lu hjl.tools@gmail.com
Tue Jul 8 18:12:00 GMT 2008


Hi Richard,

Your patch miscompiles 464.h264ref in SPEC CPU 2006:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36765

Can you reproduce it?

Thanks.


H.J.
On Mon, Jul 7, 2008 at 8:47 AM, Daniel Berlin <dberlin@dberlin.org> wrote:
> This is fine.
> Thanks
>
> On Mon, Jul 7, 2008 at 9:52 AM, Richard Guenther <rguenther@suse.de> wrote:
>>
>> This is the revised version according to discussion with Danny.  It
>> makes sure to not break ipa-pta by adding a new flag to varinfos
>> that says if the field is representing a full variable (the function
>> decl var does not, but its parameters and the result do).
>>
>> We can use this flag to distinguish between globbing behavior and
>> usual arithmetic behavior.  I have added more testcases, including
>> some ipa-pta testcases that make sure the points-to results are
>> correct.
>>
>> Bootstrapped and tested on x86_64-unknown-linux-gnu, ok for trunk?
>>
>> Thanks,
>> Richard.
>>
>> 2008-07-04  Richard Guenther  <rguenther@suse.de>
>>
>>        * tree-ssa-structalias.c (struct variable_info): Add is_full_var
>> flag.
>>        (new_var_info): Set it to false.
>>        (solution_set_add): Correctly handle pointers outside a var and
>>        inside a field.
>>        (type_safe): Treat variables with is_full_var properly.
>>        (do_sd_constraint): Likewise.
>>        (do_ds_constraint): Likewise.
>>        (process_constraint): Remove zeroing offset for !use_field_sensitive.
>>        (get_constraint_for_ptr_offset): New function.
>>        (get_constraint_for_component_ref): For addresses at least include
>>        the last field of the variable.  Handle is_full_vars properly.
>>        (get_constraint_for_1): Factor common code, handle POINTER_PLUS_EXPR.
>>        (handle_ptr_arith): Remove.
>>        (find_func_aliases): Simplify assignment handling.
>>        (create_function_info_for): For parameter and result varinfos set
>>        is_full_var flag.
>>        (create_variable_info_for): Set is_full_var flag whenever we
>>        just created a single varinfo for a decl.
>>        (init_alias_vars): Initialize use_field_sensitive from
>>        max-fields-for-field-sensitive parameter.
>>
>>        * gcc.dg/torture/pta-ptrarith-1.c: New testcase.
>>        * gcc.dg/torture/pta-ptrarith-2.c: Likewise.
>>        * gcc.dg/torture/ipa-pta-1.c: Likewise.
>>
>> Index: trunk/gcc/tree-ssa-structalias.c
>> ===================================================================
>> *** trunk.orig/gcc/tree-ssa-structalias.c       2008-07-07
>> 13:48:19.000000000 +0200
>> --- trunk/gcc/tree-ssa-structalias.c    2008-07-07 14:10:32.000000000 +0200
>> *************** struct variable_info
>> *** 220,225 ****
>> --- 220,228 ----
>>    /* True for variables whose size is not known or variable.  */
>>    unsigned int is_unknown_size_var:1;
>>
>> +   /* True for (sub-)fields that represent a whole variable.  */
>> +   unsigned int is_full_var : 1;
>> +
>>    /* True if this is a heap variable.  */
>>    unsigned int is_heap_var:1;
>>
>> *************** new_var_info (tree t, unsigned int id, c
>> *** 373,378 ****
>> --- 376,382 ----
>>    ret->is_heap_var = false;
>>    ret->is_special_var = false;
>>    ret->is_unknown_size_var = false;
>> +   ret->is_full_var = false;
>>    var = t;
>>    if (TREE_CODE (var) == SSA_NAME)
>>      var = SSA_NAME_VAR (var);
>> *************** solution_set_add (bitmap set, unsigned H
>> *** 752,773 ****
>>
>>    EXECUTE_IF_SET_IN_BITMAP (set, 0, i, bi)
>>      {
>> !       /* If this is a properly sized variable, only add offset if it's
>> !        less than end.  Otherwise, it is globbed to a single
>> !        variable.  */
>>
>> !       if ((get_varinfo (i)->offset + offset) < get_varinfo (i)->fullsize)
>>        {
>> !         unsigned HOST_WIDE_INT fieldoffset = get_varinfo (i)->offset +
>> offset;
>> !         varinfo_t v = first_vi_for_offset (get_varinfo (i), fieldoffset);
>>          if (!v)
>> !           continue;
>>          bitmap_set_bit (result, v->id);
>> !       }
>> !       else if (get_varinfo (i)->is_artificial_var
>> !              || get_varinfo (i)->is_unknown_size_var)
>> !       {
>> !         bitmap_set_bit (result, i);
>>        }
>>      }
>>
>> --- 756,787 ----
>>
>>    EXECUTE_IF_SET_IN_BITMAP (set, 0, i, bi)
>>      {
>> !       varinfo_t vi = get_varinfo (i);
>>
>> !       /* If this is a variable with just one field just set its bit
>> !          in the result.  */
>> !       if (vi->is_artificial_var
>> !         || vi->is_unknown_size_var
>> !         || vi->is_full_var)
>> !       bitmap_set_bit (result, i);
>> !       else
>>        {
>> !         unsigned HOST_WIDE_INT fieldoffset = vi->offset + offset;
>> !         varinfo_t v = first_vi_for_offset (vi, fieldoffset);
>> !         /* If the result is outside of the variable use the last field.
>>  */
>>          if (!v)
>> !           {
>> !             v = vi;
>> !             while (v->next != NULL)
>> !               v = v->next;
>> !           }
>>          bitmap_set_bit (result, v->id);
>> !         /* If the result is not exactly at fieldoffset include the next
>> !            field as well.  See get_constraint_for_ptr_offset for more
>> !            rationale.  */
>> !         if (v->offset != fieldoffset
>> !             && v->next != NULL)
>> !           bitmap_set_bit (result, v->next->id);
>>        }
>>      }
>>
>> *************** type_safe (unsigned int n, unsigned HOST
>> *** 1375,1381 ****
>>       0.  */
>>    if (ninfo->is_special_var
>>        || ninfo->is_artificial_var
>> !       || ninfo->is_unknown_size_var)
>>      {
>>        *offset = 0;
>>        return true;
>> --- 1389,1396 ----
>>       0.  */
>>    if (ninfo->is_special_var
>>        || ninfo->is_artificial_var
>> !       || ninfo->is_unknown_size_var
>> !       || ninfo->is_full_var)
>>      {
>>        *offset = 0;
>>        return true;
>> *************** do_sd_constraint (constraint_graph_t gra
>> *** 1415,1421 ****
>>           sub-fields off.  This avoids quadratic behavior.  */
>>        EXECUTE_IF_SET_IN_BITMAP (delta, 0, j, bi)
>>        {
>> !         varinfo_t v = lookup_vi_for_tree (get_varinfo (j)->decl);
>>          if (v->next != NULL)
>>            {
>>              if (vars == NULL)
>> --- 1430,1440 ----
>>           sub-fields off.  This avoids quadratic behavior.  */
>>        EXECUTE_IF_SET_IN_BITMAP (delta, 0, j, bi)
>>        {
>> !         varinfo_t v = get_varinfo (j);
>> !         if (v->is_full_var)
>> !           continue;
>> ! !         v = lookup_vi_for_tree (v->decl);
>>          if (v->next != NULL)
>>            {
>>              if (vars == NULL)
>> *************** do_sd_constraint (constraint_graph_t gra
>> *** 1455,1460 ****
>> --- 1474,1480 ----
>>          unsigned int t;
>>
>>          v = first_vi_for_offset (get_varinfo (j), fieldoffset);
>> +         /* If the access is outside of the variable we can ignore it.  */
>>          if (!v)
>>            continue;
>>          t = find (v->id);
>> *************** do_ds_constraint (constraint_t c, bitmap
>> *** 1507,1515 ****
>>         unsigned HOST_WIDE_INT fieldoffset = jvi->offset + loff;
>>         varinfo_t v;
>>
>> !        v = first_vi_for_offset (get_varinfo (j), fieldoffset);
>> !        if (!v)
>> !          continue;
>>         t = find (v->id);
>>
>>         if (bitmap_set_bit (get_varinfo (t)->solution, anything_id)
>> --- 1527,1540 ----
>>         unsigned HOST_WIDE_INT fieldoffset = jvi->offset + loff;
>>         varinfo_t v;
>>
>> !        v = get_varinfo (j);
>> !        if (!v->is_full_var)
>> !          {
>> !            v = first_vi_for_offset (v, fieldoffset);
>> !            /* If the access is outside of the variable we can ignore it.
>>  */
>> !            if (!v)
>> !              continue;
>> !          }
>>         t = find (v->id);
>>
>>         if (bitmap_set_bit (get_varinfo (t)->solution, anything_id)
>> *************** do_ds_constraint (constraint_t c, bitmap
>> *** 1535,1540 ****
>> --- 1560,1566 ----
>>          bitmap tmp;
>>
>>          v = first_vi_for_offset (get_varinfo (j), fieldoffset);
>> +         /* If the access is outside of the variable we can ignore it.  */
>>          if (!v)
>>            continue;
>>          t = find (v->id);
>> *************** process_constraint (constraint_t t)
>> *** 2597,2608 ****
>>    gcc_assert (rhs.var < VEC_length (varinfo_t, varmap));
>>    gcc_assert (lhs.var < VEC_length (varinfo_t, varmap));
>>
>> -   if (!use_field_sensitive)
>> -     {
>> -       t->rhs.offset = 0;
>> -       t->lhs.offset = 0;
>> -     }
>> -
>>    /* ANYTHING == ANYTHING is pointless.  */
>>    if (lhs.var == anything_id && rhs.var == anything_id)
>>      return;
>> --- 2623,2628 ----
>> *************** bitpos_of_field (const tree fdecl)
>> *** 2678,2683 ****
>> --- 2698,2816 ----
>>  }
>>
>>
>> + /* Get constraint expressions for offsetting PTR by OFFSET.  Stores the
>> +    resulting constraint expressions in *RESULTS.  */
>> + + static void
>> + get_constraint_for_ptr_offset (tree ptr, tree offset,
>> +                              VEC (ce_s, heap) **results)
>> + {
>> +   struct constraint_expr *c;
>> +   unsigned int j, n;
>> +   unsigned HOST_WIDE_INT rhsunitoffset, rhsoffset;
>> + +   /* If we do not do field-sensitive PTA adding offsets to pointers
>> +      does not change the points-to solution.  */
>> +   if (!use_field_sensitive)
>> +     {
>> +       get_constraint_for (ptr, results);
>> +       return;
>> +     }
>> + +   /* If the offset is not a non-negative integer constant that fits
>> +      in a HOST_WIDE_INT, we have to fall back to a conservative
>> +      solution which includes all sub-fields of all pointed-to
>> +      variables of ptr.
>> +      ???  As we do not have the ability to express this, fall back
>> +      to anything.  */
>> +   if (!host_integerp (offset, 1))
>> +     {
>> +       struct constraint_expr temp;
>> +       temp.var = anything_id;
>> +       temp.type = SCALAR;
>> +       temp.offset = 0;
>> +       VEC_safe_push (ce_s, heap, *results, &temp);
>> +       return;
>> +     }
>> + +   /* Make sure the bit-offset also fits.  */
>> +   rhsunitoffset = TREE_INT_CST_LOW (offset);
>> +   rhsoffset = rhsunitoffset * BITS_PER_UNIT;
>> +   if (rhsunitoffset != rhsoffset / BITS_PER_UNIT)
>> +     {
>> +       struct constraint_expr temp;
>> +       temp.var = anything_id;
>> +       temp.type = SCALAR;
>> +       temp.offset = 0;
>> +       VEC_safe_push (ce_s, heap, *results, &temp);
>> +       return;
>> +     }
>> + +   get_constraint_for (ptr, results);
>> +   if (rhsoffset == 0)
>> +     return;
>> + +   /* As we are eventually appending to the solution do not use
>> +      VEC_iterate here.  */
>> +   n = VEC_length (ce_s, *results);
>> +   for (j = 0; j < n; j++)
>> +     {
>> +       varinfo_t curr;
>> +       c = VEC_index (ce_s, *results, j);
>> +       curr = get_varinfo (c->var);
>> + +       if (c->type == ADDRESSOF
>> +         && !curr->is_full_var)
>> +       {
>> +         varinfo_t temp, curr = get_varinfo (c->var);
>> + +         /* Search the sub-field which overlaps with the
>> +            pointed-to offset.  As we deal with positive offsets
>> +            only, we can start the search from the current variable.  */
>> +         temp = first_vi_for_offset (curr, curr->offset + rhsoffset);
>> + +         /* If the result is outside of the variable we have to provide
>> +            a conservative result, as the variable is still reachable
>> +            from the resulting pointer (even though it technically
>> +            cannot point to anything).  The last sub-field is such
>> +            a conservative result.
>> +            ???  If we always had a sub-field for &object + 1 then
>> +            we could represent this in a more precise way.  */
>> +         if (temp == NULL)
>> +           {
>> +             temp = curr;
>> +             while (temp->next != NULL)
>> +               temp = temp->next;
>> +             continue;
>> +           }
>> + +         /* If the found variable is not exactly at the pointed to
>> +            result, we have to include the next variable in the
>> +            solution as well.  Otherwise two increments by offset / 2
>> +            do not result in the same or a conservative superset
>> +            solution.  */
>> +         if (temp->offset != curr->offset + rhsoffset
>> +             && temp->next != NULL)
>> +           {
>> +             struct constraint_expr c2;
>> +             c2.var = temp->next->id;
>> +             c2.type = ADDRESSOF;
>> +             c2.offset = 0;
>> +             VEC_safe_push (ce_s, heap, *results, &c2);
>> +           }
>> +         c->var = temp->id;
>> +         c->offset = 0;
>> +       }
>> +       else if (c->type == ADDRESSOF
>> +              /* If this varinfo represents a full variable just use it.
>>  */
>> +              && curr->is_full_var)
>> +       c->offset = 0;
>> +       else
>> +       c->offset = rhsoffset;
>> +     }
>> + }
>> + +
>>  /* Given a COMPONENT_REF T, return the constraint_expr vector for it.
>>     If address_p is true the result will be taken its address of.  */
>>
>> *************** get_constraint_for_component_ref (tree t
>> *** 2714,2728 ****
>>    /* Pretend to take the address of the base, we'll take care of
>>       adding the required subset of sub-fields below.  */
>>    get_constraint_for_1 (t, results, true);
>> -   result = VEC_last (ce_s, *results);
>> -
>>    gcc_assert (VEC_length (ce_s, *results) == 1);
>>
>>    /* This can also happen due to weird offsetof type macros.  */
>>    if (TREE_CODE (t) != ADDR_EXPR && result->type == ADDRESSOF)
>>      result->type = SCALAR;
>>
>> !   if (result->type == SCALAR)
>>      {
>>        /* In languages like C, you can access one past the end of an
>>         array.  You aren't allowed to dereference it, so we can
>> --- 2847,2864 ----
>>    /* Pretend to take the address of the base, we'll take care of
>>       adding the required subset of sub-fields below.  */
>>    get_constraint_for_1 (t, results, true);
>>    gcc_assert (VEC_length (ce_s, *results) == 1);
>> +   result = VEC_last (ce_s, *results);
>>
>>    /* This can also happen due to weird offsetof type macros.  */
>>    if (TREE_CODE (t) != ADDR_EXPR && result->type == ADDRESSOF)
>>      result->type = SCALAR;
>>
>> !   if (result->type == SCALAR
>> !       && get_varinfo (result->var)->is_full_var)
>> !     /* For single-field vars do not bother about the offset.  */
>> !     result->offset = 0;
>> !   else if (result->type == SCALAR)
>>      {
>>        /* In languages like C, you can access one past the end of an
>>         array.  You aren't allowed to dereference it, so we can
>> *************** get_constraint_for_component_ref (tree t
>> *** 2751,2762 ****
>>                    break;
>>                }
>>            }
>> !         /* assert that we found *some* field there. The user couldn't be
>> !            accessing *only* padding.  */
>> !         /* Still the user could access one past the end of an array
>> !            embedded in a struct resulting in accessing *only* padding.  */
>> !         gcc_assert (VEC_length (ce_s, *results) >= 1
>> !                     || ref_contains_array_ref (orig_t));
>>        }
>>        else if (bitmaxsize == 0)
>>        {
>> --- 2887,2911 ----
>>                    break;
>>                }
>>            }
>> !         /* If we are going to take the address of this field then
>> !            to be able to compute reachability correctly add at least
>> !            the last field of the variable.  */
>> !         if (address_p
>> !             && VEC_length (ce_s, *results) == 0)
>> !           {
>> !             curr = get_varinfo (cexpr.var);
>> !             while (curr->next != NULL)
>> !               curr = curr->next;
>> !             cexpr.var = curr->id;
>> !             VEC_safe_push (ce_s, heap, *results, &cexpr);
>> !           }
>> !         else
>> !           /* Assert that we found *some* field there. The user couldn't be
>> !              accessing *only* padding.  */
>> !           /* Still the user could access one past the end of an array
>> !              embedded in a struct resulting in accessing *only* padding.
>>  */
>> !           gcc_assert (VEC_length (ce_s, *results) >= 1
>> !                       || ref_contains_array_ref (orig_t));
>>        }
>>        else if (bitmaxsize == 0)
>>        {
>> *************** get_constraint_for_1 (tree t, VEC (ce_s,
>> *** 2900,2923 ****
>>                VEC_safe_push (ce_s, heap, *results, &temp);
>>                return;
>>              }
>> -           else
>> -             {
>> -               temp.var = anything_id;
>> -               temp.type = SCALAR;
>> -               temp.offset = 0;
>> -               VEC_safe_push (ce_s, heap, *results, &temp);
>> -               return;
>> -             }
>>            break;
>> !         default:
>> !           {
>> !             temp.type = ADDRESSOF;
>> !             temp.var = anything_id;
>> !             temp.offset = 0;
>> !             VEC_safe_push (ce_s, heap, *results, &temp);
>> !             return;
>> !           }
>>          }
>>        }
>>      case tcc_reference:
>>        {
>> --- 3049,3058 ----
>>                VEC_safe_push (ce_s, heap, *results, &temp);
>>                return;
>>              }
>>            break;
>> !         default:;
>>          }
>> +       break;
>>        }
>>      case tcc_reference:
>>        {
>> *************** get_constraint_for_1 (tree t, VEC (ce_s,
>> *** 2934,2948 ****
>>          case COMPONENT_REF:
>>            get_constraint_for_component_ref (t, results, address_p);
>>            return;
>> !         default:
>> !           {
>> !             temp.type = ADDRESSOF;
>> !             temp.var = anything_id;
>> !             temp.offset = 0;
>> !             VEC_safe_push (ce_s, heap, *results, &temp);
>> !             return;
>> !           }
>>          }
>>        }
>>      case tcc_unary:
>>        {
>> --- 3069,3077 ----
>>          case COMPONENT_REF:
>>            get_constraint_for_component_ref (t, results, address_p);
>>            return;
>> !         default:;
>>          }
>> +       break;
>>        }
>>      case tcc_unary:
>>        {
>> *************** get_constraint_for_1 (tree t, VEC (ce_s,
>> *** 2963,2977 ****
>>
>>              /* FALLTHRU  */
>>            }
>> !         default:
>> !           {
>> !             temp.type = ADDRESSOF;
>> !             temp.var = anything_id;
>> !             temp.offset = 0;
>> !             VEC_safe_push (ce_s, heap, *results, &temp);
>> !             return;
>> !           }
>>          }
>>        }
>>      case tcc_exceptional:
>>        {
>> --- 3092,3110 ----
>>
>>              /* FALLTHRU  */
>>            }
>> !         default:;
>>          }
>> +       break;
>> +       }
>> +     case tcc_binary:
>> +       {
>> +       if (TREE_CODE (t) == POINTER_PLUS_EXPR)
>> +         {
>> +           get_constraint_for_ptr_offset (TREE_OPERAND (t, 0),
>> +                                          TREE_OPERAND (t, 1), results);
>> +           return;
>> +         }
>> +       break;
>>        }
>>      case tcc_exceptional:
>>        {
>> *************** get_constraint_for_1 (tree t, VEC (ce_s,
>> *** 2982,3018 ****
>>              get_constraint_for_1 (PHI_RESULT (t), results, address_p);
>>              return;
>>            }
>> -           break;
>>          case SSA_NAME:
>>            {
>>              get_constraint_for_ssa_var (t, results, address_p);
>>              return;
>>            }
>> !           break;
>> !         default:
>> !           {
>> !             temp.type = ADDRESSOF;
>> !             temp.var = anything_id;
>> !             temp.offset = 0;
>> !             VEC_safe_push (ce_s, heap, *results, &temp);
>> !             return;
>> !           }
>>          }
>>        }
>>      case tcc_declaration:
>>        {
>>        get_constraint_for_ssa_var (t, results, address_p);
>>        return;
>>        }
>> !     default:
>> !       {
>> !       temp.type = ADDRESSOF;
>> !       temp.var = anything_id;
>> !       temp.offset = 0;
>> !       VEC_safe_push (ce_s, heap, *results, &temp);
>> !       return;
>> !       }
>>      }
>>  }
>>
>>  /* Given a gimple tree T, return the constraint expression vector for it.
>>  */
>> --- 3115,3142 ----
>>              get_constraint_for_1 (PHI_RESULT (t), results, address_p);
>>              return;
>>            }
>>          case SSA_NAME:
>>            {
>>              get_constraint_for_ssa_var (t, results, address_p);
>>              return;
>>            }
>> !         default:;
>>          }
>> +       break;
>>        }
>>      case tcc_declaration:
>>        {
>>        get_constraint_for_ssa_var (t, results, address_p);
>>        return;
>>        }
>> !     default:;
>>      }
>> + +   /* The default fallback is a constraint from anything.  */
>> +   temp.type = ADDRESSOF;
>> +   temp.var = anything_id;
>> +   temp.offset = 0;
>> +   VEC_safe_push (ce_s, heap, *results, &temp);
>>  }
>>
>>  /* Given a gimple tree T, return the constraint expression vector for it.
>>  */
>> *************** do_structure_copy (tree lhsop, tree rhso
>> *** 3298,3377 ****
>>      }
>>  }
>>
>> - - /* Handle pointer arithmetic EXPR when creating aliasing constraints.
>> -    Expressions of the type PTR + CST can be handled in two ways:
>> - -    1- If the constraint for PTR is ADDRESSOF for a non-structure
>> -       variable, then we can use it directly because adding or
>> -       subtracting a constant may not alter the original ADDRESSOF
>> -       constraint (i.e., pointer arithmetic may not legally go outside
>> -       an object's boundaries).
>> - -    2- If the constraint for PTR is ADDRESSOF for a structure variable,
>> -       then if CST is a compile-time constant that can be used as an
>> -       offset, we can determine which sub-variable will be pointed-to
>> -       by the expression.
>> - -    Return true if the expression is handled.  For any other kind of
>> -    expression, return false so that each operand can be added as a
>> -    separate constraint by the caller.  */
>> - - static bool
>> - handle_ptr_arith (VEC (ce_s, heap) *lhsc, tree expr)
>> - {
>> -   tree op0, op1;
>> -   struct constraint_expr *c, *c2;
>> -   unsigned int i = 0;
>> -   unsigned int j = 0;
>> -   VEC (ce_s, heap) *temp = NULL;
>> -   unsigned HOST_WIDE_INT rhsunitoffset, rhsoffset;
>> - -   if (TREE_CODE (expr) != POINTER_PLUS_EXPR)
>> -     return false;
>> - -   op0 = TREE_OPERAND (expr, 0);
>> -   op1 = TREE_OPERAND (expr, 1);
>> -   gcc_assert (POINTER_TYPE_P (TREE_TYPE (op0)));
>> - -   /* If the offset is not a non-negative integer constant that fits
>> -      in a HOST_WIDE_INT, we cannot handle it here.  */
>> -   if (!host_integerp (op1, 1))
>> -     return false;
>> - -   /* Make sure the bit-offset also fits.  */
>> -   rhsunitoffset = TREE_INT_CST_LOW (op1);
>> -   rhsoffset = rhsunitoffset * BITS_PER_UNIT;
>> -   if (rhsunitoffset != rhsoffset / BITS_PER_UNIT)
>> -     return false;
>> - -   get_constraint_for (op0, &temp);
>> - -   for (i = 0; VEC_iterate (ce_s, lhsc, i, c); i++)
>> -     for (j = 0; VEC_iterate (ce_s, temp, j, c2); j++)
>> -       {
>> -       if (c2->type == ADDRESSOF && rhsoffset != 0)
>> -         {
>> -           varinfo_t temp = get_varinfo (c2->var);
>> - -           /* An access one after the end of an array is valid,
>> -              so simply punt on accesses we cannot resolve.  */
>> -           temp = first_vi_for_offset (temp, rhsoffset);
>> -           if (temp == NULL)
>> -             continue;
>> -           c2->var = temp->id;
>> -           c2->offset = 0;
>> -         }
>> -       else
>> -         c2->offset = rhsoffset;
>> -       process_constraint (new_constraint (*c, *c2));
>> -       }
>> - -   VEC_free (ce_s, heap, temp);
>> - -   return true;
>> - }
>> -
>>  /* Create a constraint ID = OP.  */
>>
>>  static void
>> --- 3422,3427 ----
>> *************** find_func_aliases (tree origt)
>> *** 3771,3859 ****
>>            }
>>        }
>>      }
>> !   /* Otherwise, just a regular assignment statement.  */
>> !   else if (TREE_CODE (t) == GIMPLE_MODIFY_STMT)
>>      {
>>        tree lhsop = GIMPLE_STMT_OPERAND (t, 0);
>>        tree rhsop = GIMPLE_STMT_OPERAND (t, 1);
>> -       int i;
>>
>> !       if (AGGREGATE_TYPE_P (TREE_TYPE (lhsop))
>> !         && AGGREGATE_TYPE_P (TREE_TYPE (rhsop)))
>> !       {
>> !         do_structure_copy (lhsop, rhsop);
>> !       }
>>        else
>>        {
>> !         /* Only care about operations with pointers, structures
>> !            containing pointers, dereferences, and call expressions.  */
>> !         if (could_have_pointers (lhsop)
>> !             || TREE_CODE (rhsop) == CALL_EXPR)
>>            {
>> !             get_constraint_for (lhsop, &lhsc);
>> !             switch (TREE_CODE_CLASS (TREE_CODE (rhsop)))
>> !               {
>> !                 /* RHS that consist of unary operations,
>> !                    exceptional types, or bare decls/constants, get
>> !                    handled directly by get_constraint_for.  */
>> !                 case tcc_reference:
>> !                 case tcc_declaration:
>> !                 case tcc_constant:
>> !                 case tcc_exceptional:
>> !                 case tcc_expression:
>> !                 case tcc_vl_exp:
>> !                 case tcc_unary:
>> !                     {
>> !                       unsigned int j;
>> ! !                       get_constraint_for (rhsop, &rhsc);
>> !                       for (j = 0; VEC_iterate (ce_s, lhsc, j, c); j++)
>> !                         {
>> !                           struct constraint_expr *c2;
>> !                           unsigned int k;
>> ! !                           for (k = 0; VEC_iterate (ce_s, rhsc, k, c2);
>> k++)
>> !                             process_constraint (new_constraint (*c, *c2));
>> !                         }
>> ! !                     }
>> !                   break;
>>
>> !                 case tcc_binary:
>> !                     {
>> !                       /* For pointer arithmetic of the form
>> !                          PTR + CST, we can simply use PTR's
>> !                          constraint because pointer arithmetic is
>> !                          not allowed to go out of bounds.  */
>> !                       if (handle_ptr_arith (lhsc, rhsop))
>> !                         break;
>> !                     }
>> !                   /* FALLTHRU  */
>> ! !                 /* Otherwise, walk each operand.  Notice that we
>> !                    can't use the operand interface because we need
>> !                    to process expressions other than simple operands
>> !                    (e.g. INDIRECT_REF, ADDR_EXPR, CALL_EXPR).  */
>> !                 default:
>> !                   for (i = 0; i < TREE_OPERAND_LENGTH (rhsop); i++)
>> !                     {
>> !                       tree op = TREE_OPERAND (rhsop, i);
>> !                       unsigned int j;
>> ! !                       gcc_assert (VEC_length (ce_s, rhsc) == 0);
>> !                       get_constraint_for (op, &rhsc);
>> !                       for (j = 0; VEC_iterate (ce_s, lhsc, j, c); j++)
>> !                         {
>> !                           struct constraint_expr *c2;
>> !                           while (VEC_length (ce_s, rhsc) > 0)
>> !                             {
>> !                               c2 = VEC_last (ce_s, rhsc);
>> !                               process_constraint (new_constraint (*c,
>> *c2));
>> !                               VEC_pop (ce_s, rhsc);
>> !                             }
>> !                         }
>> !                     }
>> !               }
>>            }
>>        }
>>      }
>> --- 3821,3849 ----
>>            }
>>        }
>>      }
>> !   /* Otherwise, just a regular assignment statement.  Only care about
>> !      operations with pointer result, others are dealt with as escape
>> !      points if they have pointer operands.  */
>> !   else if (TREE_CODE (t) == GIMPLE_MODIFY_STMT
>> !          && could_have_pointers (GIMPLE_STMT_OPERAND (t, 0)))
>>      {
>>        tree lhsop = GIMPLE_STMT_OPERAND (t, 0);
>>        tree rhsop = GIMPLE_STMT_OPERAND (t, 1);
>>
>> !       if (AGGREGATE_TYPE_P (TREE_TYPE (lhsop)))
>> !       do_structure_copy (lhsop, rhsop);
>>        else
>>        {
>> !         unsigned int j;
>> !         get_constraint_for (lhsop, &lhsc);
>> !         get_constraint_for (rhsop, &rhsc);
>> !         for (j = 0; VEC_iterate (ce_s, lhsc, j, c); j++)
>>            {
>> !             struct constraint_expr *c2;
>> !             unsigned int k;
>>
>> !             for (k = 0; VEC_iterate (ce_s, rhsc, k, c2); k++)
>> !               process_constraint (new_constraint (*c, *c2));
>>            }
>>        }
>>      }
>> *************** create_function_info_for (tree decl, con
>> *** 4222,4229 ****
>>    stats.total_vars++;
>>
>>    /* If it's varargs, we don't know how many arguments it has, so we
>> !      can't do much.
>> !   */
>>    if (is_varargs)
>>      {
>>        vi->fullsize = ~0;
>> --- 4212,4218 ----
>>    stats.total_vars++;
>>
>>    /* If it's varargs, we don't know how many arguments it has, so we
>> !      can't do much.  */
>>    if (is_varargs)
>>      {
>>        vi->fullsize = ~0;
>> *************** create_function_info_for (tree decl, con
>> *** 4257,4262 ****
>> --- 4246,4252 ----
>>        VEC_safe_push (varinfo_t, heap, varmap, argvi);
>>        argvi->offset = i;
>>        argvi->size = 1;
>> +       argvi->is_full_var = true;
>>        argvi->fullsize = vi->fullsize;
>>        insert_into_field_list_sorted (vi, argvi);
>>        stats.total_vars ++;
>> *************** create_function_info_for (tree decl, con
>> *** 4293,4298 ****
>> --- 4283,4289 ----
>>        resultvi->offset = i;
>>        resultvi->size = 1;
>>        resultvi->fullsize = vi->fullsize;
>> +       resultvi->is_full_var = true;
>>        insert_into_field_list_sorted (vi, resultvi);
>>        stats.total_vars ++;
>>        if (DECL_RESULT (decl))
>> *************** create_variable_info_for (tree decl, con
>> *** 4411,4416 ****
>> --- 4402,4408 ----
>>          vi->is_unknown_size_var = 1;
>>          vi->fullsize = ~0;
>>          vi->size = ~0;
>> +         vi->is_full_var = true;
>>          VEC_free (fieldoff_s, heap, fieldstack);
>>          return index;
>>        }
>> *************** create_variable_info_for (tree decl, con
>> *** 4447,4452 ****
>> --- 4439,4446 ----
>>          stats.total_vars++;
>>        }
>>      }
>> +   else
>> +     vi->is_full_var = true;
>>
>>    VEC_free (fieldoff_s, heap, fieldstack);
>>
>> *************** init_base_vars (void)
>> *** 5198,5203 ****
>> --- 5192,5199 ----
>>  static void
>>  init_alias_vars (void)
>>  {
>> +   use_field_sensitive = (MAX_FIELDS_FOR_FIELD_SENSITIVE > 1);
>> +
>>    bitmap_obstack_initialize (&pta_obstack);
>>    bitmap_obstack_initialize (&oldpta_obstack);
>>    bitmap_obstack_initialize (&predbitmap_obstack);
>> Index: trunk/gcc/testsuite/gcc.dg/torture/pta-ptrarith-1.c
>> ===================================================================
>> *** /dev/null   1970-01-01 00:00:00.000000000 +0000
>> --- trunk/gcc/testsuite/gcc.dg/torture/pta-ptrarith-1.c 2008-07-07
>> 13:48:47.000000000 +0200
>> ***************
>> *** 0 ****
>> --- 1,33 ----
>> + /* { dg-do run } */
>> + /* { dg-options "-fdump-tree-alias" } */
>> + /* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
>> + + struct Foo {
>> +   int *p;
>> + };
>> + + void __attribute__((noinline))
>> + foo (void *p)
>> + {
>> +   struct Foo *f = (struct Foo *)p - 1;
>> +   *f->p = 0;
>> + }
>> + + int bar (void)
>> + {
>> +   struct Foo f;
>> +   int i = 1;
>> +   f.p = &i;
>> +   foo (&f + 1);
>> +   return i;
>> + }
>> + extern void abort (void);
>> + int main()
>> + {
>> +   if (bar () != 0)
>> +     abort ();
>> +   return 0;
>> + }
>> + + /* { dg-final { scan-tree-dump "ESCAPED = { ESCAPED NONLOCAL f .* i }"
>> "alias" } } */
>> + /* { dg-final { cleanup-tree-dump "alias" } } */
>> Index: trunk/gcc/testsuite/gcc.dg/torture/ipa-pta-1.c
>> ===================================================================
>> *** /dev/null   1970-01-01 00:00:00.000000000 +0000
>> --- trunk/gcc/testsuite/gcc.dg/torture/ipa-pta-1.c      2008-07-07
>> 13:48:47.000000000 +0200
>> ***************
>> *** 0 ****
>> --- 1,40 ----
>> + /* { dg-do compile } */
>> + /* { dg-options "-fipa-pta -fdump-ipa-pta" } */
>> + /* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
>> + + struct X { char x; char y; };
>> + + void bar (char *p);
>> + + void test1 (char a, char b, char c, char d, char e, char f, char g, char
>> h)
>> + {
>> +   char *p = &a;
>> +   p++;
>> +   bar (p);
>> + }
>> + + void test2 (struct X a, char b, char c, char d, char e, char f, char g,
>> char h)
>> + {
>> +   char *p = &a.x;
>> +   p++;
>> +   bar (p);
>> + }
>> + + void test3 (struct X a, char b, char c, char d, char e, char f, char g,
>> char h)
>> + {
>> +   char *p = &a.y;
>> +   bar (p);
>> + }
>> + + void test4 (int a, char b, char c, char d, char e, char f, char g, char
>> h)
>> + {
>> +   char *p = (char *)&a;
>> +   p++;
>> +   p++;
>> +   p++;
>> +   p++;
>> +   bar (p);
>> + }
>> + + /* { dg-final { scan-ipa-dump "bar.arg0 = { test4.arg0 test3.arg0
>> test2.arg0 test1.arg0 }" "pta" } } */
>> + /* { dg-final { cleanup-ipa-dump "pta" } } */
>> Index: trunk/gcc/testsuite/gcc.dg/torture/pta-ptrarith-2.c
>> ===================================================================
>> *** /dev/null   1970-01-01 00:00:00.000000000 +0000
>> --- trunk/gcc/testsuite/gcc.dg/torture/pta-ptrarith-2.c 2008-07-07
>> 14:15:36.000000000 +0200
>> ***************
>> *** 0 ****
>> --- 1,36 ----
>> + /* { dg-do run } */
>> + /* { dg-options "-fdump-tree-alias" } */
>> + /* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
>> + + struct Foo {
>> +   int **p;
>> +   int **q;
>> + };
>> + + int __attribute__((noinline))
>> + bar (void)
>> + {
>> +   struct Foo f;
>> +   int j, i = 1;
>> +   char *p;
>> +   int *x = &i;
>> +   int *y = &j;
>> +   f.p = &y;
>> +   f.q = &x;
>> +   p = (char *)&f;
>> +   for (j = 0; j < sizeof (int *); ++j)
>> +     p++;
>> +   return ***(int ***)p;
>> + }
>> + extern void abort (void);
>> + int main()
>> + {
>> +   if (bar () != 1)
>> +     abort ();
>> +   return 0;
>> + }
>> + + /* In theory = { i } is the correct solution.  But it's not easy to scan
>> +    for that reliably, so just use what we create now.  */
>> + /* { dg-final { scan-tree-dump "= { i j }" "alias" } } */
>> + /* { dg-final { cleanup-tree-dump "alias" } } */
>>
>



-- 
H.J.



More information about the Gcc-patches mailing list