On Thu, Nov 21, 2013 at 10:03 AM, Michael Matz <m...@suse.de> wrote:
> Hello,
>
> after much pondering about the issue we came up with this design to
> handle restrict more generally.  Without a completely different way of
> representing conflicts (or non-conflicts) of memory references we're bound
> to somehow encode the necessary information into the points-to set (or in
> any case information related to pointer ssa names).  This in turn means
> that the location sensitive nature of restrict needs to be made explicit
> in the IL, i.e. we basically need some starting point when a pointer
> becomes restrict (ADD_RESTRICT), and also an ending point (DEL_RESTRICT),
> which must act as barrier for other memory accesses (if it wouldn't some
> transformations could move references from outside restrict regions into
> the restrict region making them disasmbiguable with the restrict
> references, introducing a bug).
>

Can you use block/scope information to address this ? References from
enclosing scopes can be considered possible aliases.

David

> We also need to use our points-to solver to propagate restrict tags
> conservatively, postprocessing the information to remove too conservative
> estimates afterwards per SSA name.
>
> And if we want to use restrict based disambiguation we also need to
> transfer the barriers into RTL barriers (I'm using an asm with an explicit
> MEM to refer to the pointer in question, so not all memory is clobbered).
> There's some potential for improvement here by removing useless
> ADD_RESTRICT / DEL_RESTRICT pairs.
>
> There's another improvement when enlargening the set of SSA names to be
> considered for postprocessin.  Right now only the result of ADD_RESTRICT
> assigns are handled, that can be improved to also process SSA names that
> trivial depend on such (i.e. are offsetted and themself restrict typed).
>
> That facility is used to implement restrict parameters to functions,
> replacing the current ad-hoc way in the points-to solver.  Other uses
> should be done under control of the frontends, as only those know the
> semantics for real.
>
> I have a patch that more aggressively creates ADD_RESTRICT/DEL_RESTRICT
> pairs (basically whenever there's an assignment from non-restrict pointers
> to a restrict pointer, on the grounds that this "invents" a new restrict
> set), but that breaks C programs that we don't want to break (I consider
> them invalid, but there's disagreement).
>
> Some older incarnations of this were bootstrapped, but this specific patch
> is only now in regstrapping on x86_64-linux.  Okay for trunk if that
> passes?




>
>
> Ciao,
> Michael.
> ---------------------------
>         * tree.def (ADD_RESTRICT): New tree code.
>         * cfgexpand.c (expand_debug_expr): Handle it.
>         * expr.c (expand_pointer_clobber): New function.
>         (expand_expr_real_2): Use it to handle ADD_RESTRICT.
>         * expr.h (expand_pointer_clobber): Declare.
>         * function.c (gimplify_parameters): Return a second gimple_seq,
>         handle restrict parameters.
>         * function.h (gimplify_parameters): Adjust.
>         * gimple-pretty-print.c (dump_binary_rhs): Handle ADD_RESTRICT.
>         * gimplify.c (gimplify_body): Append second gimple_seq,
>         adjust call to gimplify_parameters.
>         * internal-fn.def (DEL_RESTRICT): New internal function code.
>         * internal-fn.c (expand_DEL_RESTRICT): New function.
>         * tree-cfg.c (verify_gimple_assign_binary): Check ADD_RESTRICT.
>         * tree-inline.c (estimate_operator_cost): Handle ADD_RESTRICT.
>         * tree-pretty-print.c (dump_generic_node): Ditto.
>         * tree-ssa-dce.c (propagate_necessity): DEL_RESTRICT calls
>         are only clobbers.
>         * tree-ssa-structalias.c (build_fake_var_decl_uid): New static
>         function.
>         (build_fake_var_decl): Rewrite in terms of above.
>         (make_heapvar): Take uid parameter.
>         (make_constraint_from_restrict_uid): New.
>         (make_constraint_from_restrict): Use above.
>         (make_constraint_from_global_restrict): Explicitely set global flag.
>         (handle_lhs_call): Adjust call to make_heapvar.
>         (find_func_aliases_for_internal_call): New.
>         (find_func_aliases_for_call): Use it.
>         (find_func_aliases): Handle ADD_RESTRICT.
>         (intra_create_variable_infos): Remove any explicit handling
>         of restrict parameters.
>         (set_uids_in_ptset): Update instead of overwrite
>         vars_contains_escaped_heap flag.
>         (find_what_var_points_to_1): Renamed from ...
>         (find_what_var_points_to): ... this, which is now wrapper
>         postprocessing points-to flags.
>         (compute_points_to_sets): Ignore DEL_RESTRICT calls.
>
> Index: cfgexpand.c
> ===================================================================
> --- cfgexpand.c (revision 205123)
> +++ cfgexpand.c (working copy)
> @@ -3785,6 +3785,7 @@ expand_debug_expr (tree exp)
>        /* Fall through.  */
>
>      adjust_mode:
> +    case ADD_RESTRICT:
>      case PAREN_EXPR:
>      case NOP_EXPR:
>      case CONVERT_EXPR:
> Index: expr.c
> ===================================================================
> --- expr.c      (revision 205123)
> +++ expr.c      (working copy)
> @@ -7988,6 +7988,41 @@ expand_cond_expr_using_cmove (tree treeo
>    return NULL_RTX;
>  }
>
> +/* Given a memory pointer PTR, expand an RTL asm statement
> +   that merely clobbers memory reachable from that pointer
> +   via arbitrary offsets.  */
> +
> +void
> +expand_pointer_clobber (tree ptr, location_t loc)
> +{
> +  tree ref = build_simple_mem_ref (ptr);
> +  rtx op = expand_expr (ref, NULL_RTX, BLKmode, EXPAND_MEMORY);
> +  rtx body;
> +
> +  op = validize_mem (op);
> +
> +  /* There's no way to construct a tree expression doing exactly what
> +     we need (representing a reference to arbitrarily memory reachable
> +     from a given pointer, i.e. with arbitrary offsets.  Hence
> +     construct that by massaging the MEM attributes.  */
> +  clear_mem_offset (op);
> +  clear_mem_size (op);
> +  PUT_MODE (op, BLKmode);
> +
> +  rtvec argvec = rtvec_alloc (0);
> +  rtvec constraintvec = rtvec_alloc (0);
> +  rtvec labelvec = rtvec_alloc (0);
> +
> +  body = gen_rtx_ASM_OPERANDS (BLKmode,
> +                              ggc_strdup (""),
> +                              ggc_strdup ("=m"), 0, argvec, constraintvec,
> +                              labelvec, loc);
> +
> +  MEM_VOLATILE_P (body) = 1;
> +
> +  emit_insn (gen_rtx_SET (VOIDmode, op, body));
> +}
> +
>  rtx
>  expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
>                     enum expand_modifier modifier)
> @@ -8047,6 +8082,13 @@ expand_expr_real_2 (sepops ops, rtx targ
>
>    switch (code)
>      {
> +    case ADD_RESTRICT:
> +      /* We can handle add_restrict like a conversion, treeop1 will be
> +         ignored.  But do create a barrier to contain the restrict
> +        section.  */
> +      expand_pointer_clobber (treeop0, loc);
> +
> +      /* FALLTHRU.  */
>      case NON_LVALUE_EXPR:
>      case PAREN_EXPR:
>      CASE_CONVERT:
> Index: expr.h
> ===================================================================
> --- expr.h      (revision 205123)
> +++ expr.h      (working copy)
> @@ -719,6 +719,8 @@ extern rtx extract_low_bits (enum machin
>  extern rtx expand_mult (enum machine_mode, rtx, rtx, rtx, int);
>  extern rtx expand_mult_highpart_adjust (enum machine_mode, rtx, rtx, rtx, 
> rtx, int);
>
> +extern void expand_pointer_clobber (tree, location_t);
> +
>  extern rtx assemble_static_space (unsigned HOST_WIDE_INT);
>  extern int safe_from_p (const_rtx, tree, int);
>  extern bool split_comparison (enum rtx_code, enum machine_mode,
> Index: function.c
> ===================================================================
> --- function.c  (revision 205123)
> +++ function.c  (working copy)
> @@ -3595,10 +3595,11 @@ gimplify_parm_type (tree *tp, int *walk_
>  /* Gimplify the parameter list for current_function_decl.  This involves
>     evaluating SAVE_EXPRs of variable sized parameters and generating code
>     to implement callee-copies reference parameters.  Returns a sequence of
> -   statements to add to the beginning of the function.  */
> +   statements to add to the beginning of the function and another
> +   sequence to add to the end of the function (via *STMT_AFTER).  */
>
>  gimple_seq
> -gimplify_parameters (void)
> +gimplify_parameters (gimple_seq *stmts_after)
>  {
>    struct assign_parm_data_all all;
>    tree parm;
> @@ -3606,6 +3607,7 @@ gimplify_parameters (void)
>    vec<tree> fnargs;
>    unsigned i;
>
> +  *stmts_after = NULL;
>    assign_parms_initialize_all (&all);
>    fnargs = assign_parms_augmented_arg_list (&all);
>
> @@ -3690,6 +3692,17 @@ gimplify_parameters (void)
>               DECL_HAS_VALUE_EXPR_P (parm) = 1;
>             }
>         }
> +      if (POINTER_TYPE_P (TREE_TYPE (parm))
> +         && TYPE_RESTRICT (TREE_TYPE (parm))
> +         && !DECL_HAS_VALUE_EXPR_P (parm))
> +       {
> +         tree t = fold_build2 (ADD_RESTRICT, TREE_TYPE (parm), parm,
> +                               build_int_cst (integer_type_node,
> +                                              allocate_decl_uid ()));
> +         gimplify_assign (parm, t, &stmts);
> +         gimple g = gimple_build_call_internal (IFN_DEL_RESTRICT, 1, parm);
> +         gimple_seq_add_stmt (stmts_after, g);
> +       }
>      }
>
>    fnargs.release ();
> Index: function.h
> ===================================================================
> --- function.h  (revision 205123)
> +++ function.h  (working copy)
> @@ -841,6 +841,6 @@ extern void preserve_temp_slots (rtx);
>  extern int aggregate_value_p (const_tree, const_tree);
>  extern void push_function_context (void);
>  extern void pop_function_context (void);
> -extern gimple_seq gimplify_parameters (void);
> +extern gimple_seq gimplify_parameters (gimple_seq *);
>
>  #endif  /* GCC_FUNCTION_H */
> Index: gimple-pretty-print.c
> ===================================================================
> --- gimple-pretty-print.c       (revision 205123)
> +++ gimple-pretty-print.c       (working copy)
> @@ -348,6 +348,7 @@ dump_binary_rhs (pretty_printer *buffer,
>      case COMPLEX_EXPR:
>      case MIN_EXPR:
>      case MAX_EXPR:
> +    case ADD_RESTRICT:
>      case VEC_WIDEN_MULT_HI_EXPR:
>      case VEC_WIDEN_MULT_LO_EXPR:
>      case VEC_WIDEN_MULT_EVEN_EXPR:
> Index: gimplify.c
> ===================================================================
> --- gimplify.c  (revision 205123)
> +++ gimplify.c  (working copy)
> @@ -1005,8 +1005,9 @@ gimplify_bind_expr (tree *expr_p, gimple
>           && !DECL_HARD_REGISTER (t)
>           && !TREE_THIS_VOLATILE (t)
>           && !DECL_HAS_VALUE_EXPR_P (t)
> -         /* Only care for variables that have to be in memory.  Others
> -            will be rewritten into SSA names, hence moved to the top-level.  
> */
> +         /* Only care for variables that have to be in memory.
> +            Others will be rewritten into SSA names, hence moved
> +            to the top-level.  */
>           && !is_gimple_reg (t)
>           && flag_stack_reuse != SR_NONE)
>         {
> @@ -8356,7 +8357,7 @@ gimple
>  gimplify_body (tree fndecl, bool do_parms)
>  {
>    location_t saved_location = input_location;
> -  gimple_seq parm_stmts, seq;
> +  gimple_seq parm_stmts, parm_stmts_after, seq;
>    gimple outer_bind;
>    struct gimplify_ctx gctx;
>    struct cgraph_node *cgn;
> @@ -8393,7 +8394,8 @@ gimplify_body (tree fndecl, bool do_parm
>
>    /* Resolve callee-copies.  This has to be done before processing
>       the body so that DECL_VALUE_EXPR gets processed correctly.  */
> -  parm_stmts = do_parms ? gimplify_parameters () : NULL;
> +  parm_stmts_after = NULL;
> +  parm_stmts = do_parms ? gimplify_parameters (&parm_stmts_after) : NULL;
>
>    /* Gimplify the function's body.  */
>    seq = NULL;
> @@ -8432,6 +8434,10 @@ gimplify_body (tree fndecl, bool do_parm
>             DECL_IGNORED_P (parm) = 0;
>           }
>      }
> +  /* Same for statements that need to come after the body.  */
> +  if (!gimple_seq_empty_p (parm_stmts_after))
> +    gimplify_seq_add_seq (gimple_bind_body_ptr (outer_bind),
> +                         parm_stmts_after);
>
>    if (nonlocal_vlas)
>      {
> Index: internal-fn.c
> ===================================================================
> --- internal-fn.c       (revision 205123)
> +++ internal-fn.c       (working copy)
> @@ -148,6 +148,16 @@ expand_UBSAN_NULL (gimple stmt ATTRIBUTE
>    gcc_unreachable ();
>  }
>
> +/* Expand the DEL_RESTRICT internal function into a RTL
> +   asm that merely clobbers memory reachable via the pointer.  */
> +
> +static void
> +expand_DEL_RESTRICT (gimple stmt)
> +{
> +  tree ptr = gimple_call_arg (stmt, 0);
> +  expand_pointer_clobber (ptr, gimple_location (stmt));
> +}
> +
>  /* Routines to expand each internal function, indexed by function number.
>     Each routine has the prototype:
>
> Index: internal-fn.def
> ===================================================================
> --- internal-fn.def     (revision 205123)
> +++ internal-fn.def     (working copy)
> @@ -45,3 +45,4 @@ DEF_INTERNAL_FN (GOMP_SIMD_VF, ECF_CONST
>  DEF_INTERNAL_FN (GOMP_SIMD_LAST_LANE, ECF_CONST | ECF_LEAF | ECF_NOTHROW)
>  DEF_INTERNAL_FN (ANNOTATE,  ECF_CONST | ECF_LEAF | ECF_NOTHROW)
>  DEF_INTERNAL_FN (UBSAN_NULL, ECF_LEAF | ECF_NOTHROW)
> +DEF_INTERNAL_FN (DEL_RESTRICT,  /*ECF_LEAF |*/ ECF_NOTHROW)
> Index: tree-cfg.c
> ===================================================================
> --- tree-cfg.c  (revision 205123)
> +++ tree-cfg.c  (working copy)
> @@ -3627,6 +3627,21 @@ verify_gimple_assign_binary (gimple stmt
>         return false;
>        }
>
> +    case ADD_RESTRICT:
> +      {
> +       if (!POINTER_TYPE_P (rhs1_type)
> +           || !useless_type_conversion_p (lhs_type, rhs1_type)
> +           || !useless_type_conversion_p (integer_type_node, rhs2_type))
> +         {
> +           error ("Invalid use of add_restrict");
> +           debug_generic_stmt (lhs_type);
> +           debug_generic_stmt (rhs1_type);
> +           debug_generic_stmt (rhs2_type);
> +           return true;
> +         }
> +       return false;
> +      }
> +
>      case TRUTH_ANDIF_EXPR:
>      case TRUTH_ORIF_EXPR:
>      case TRUTH_AND_EXPR:
> Index: tree-inline.c
> ===================================================================
> --- tree-inline.c       (revision 205123)
> +++ tree-inline.c       (working copy)
> @@ -3580,6 +3580,7 @@ estimate_operator_cost (enum tree_code c
>      case COMPLEX_EXPR:
>      case PAREN_EXPR:
>      case VIEW_CONVERT_EXPR:
> +    case ADD_RESTRICT:
>        return 0;
>
>      /* Assign cost of 1 to usual operations.
> Index: tree-pretty-print.c
> ===================================================================
> --- tree-pretty-print.c (revision 205123)
> +++ tree-pretty-print.c (working copy)
> @@ -1927,6 +1927,14 @@ dump_generic_node (pretty_printer *buffe
>        pp_greater (buffer);
>        break;
>
> +    case ADD_RESTRICT:
> +      pp_string (buffer, "ADD_RESTRICT <");
> +      dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
> +      pp_string (buffer, ", ");
> +      dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
> +      pp_character (buffer, '>');
> +      break;
> +
>      case ABS_EXPR:
>        pp_string (buffer, "ABS_EXPR <");
>        dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
> Index: tree-ssa-dce.c
> ===================================================================
> --- tree-ssa-dce.c      (revision 205123)
> +++ tree-ssa-dce.c      (working copy)
> @@ -828,6 +828,10 @@ propagate_necessity (bool aggressive)
>                       || DECL_FUNCTION_CODE (callee) == 
> BUILT_IN_ASSUME_ALIGNED))
>                 continue;
>
> +             if (gimple_call_internal_p (stmt)
> +                 && gimple_call_internal_fn (stmt) == IFN_DEL_RESTRICT)
> +               continue;
> +
>               /* Calls implicitly load from memory, their arguments
>                  in addition may explicitly perform memory loads.  */
>               mark_all_reaching_defs_necessary (stmt);
> Index: tree-ssa-structalias.c
> ===================================================================
> --- tree-ssa-structalias.c      (revision 205123)
> +++ tree-ssa-structalias.c      (working copy)
> @@ -3741,31 +3741,43 @@ make_transitive_closure_constraints (var
>  /* Temporary storage for fake var decls.  */
>  struct obstack fake_var_decl_obstack;
>
> -/* Build a fake VAR_DECL acting as referrer to a DECL_UID.  */
> +/* Build a fake VAR_DECL with DECL_UID being UID (which probably has
> +   to be ultimately allocated by allocate_decl_uid()).  */
>
>  static tree
> -build_fake_var_decl (tree type)
> +build_fake_var_decl_uid (tree type, int uid)
>  {
>    tree decl = (tree) XOBNEW (&fake_var_decl_obstack, struct tree_var_decl);
>    memset (decl, 0, sizeof (struct tree_var_decl));
>    TREE_SET_CODE (decl, VAR_DECL);
>    TREE_TYPE (decl) = type;
> -  DECL_UID (decl) = allocate_decl_uid ();
> +  DECL_UID (decl) = uid;
>    SET_DECL_PT_UID (decl, -1);
>    layout_decl (decl, 0);
>    return decl;
>  }
>
> -/* Create a new artificial heap variable with NAME.
> -   Return the created variable.  */
> +/* Build a fake VAR_DECL acting as referrer to a DECL_UID.  */
> +
> +static tree
> +build_fake_var_decl (tree type)
> +{
> +  return build_fake_var_decl_uid (type, allocate_decl_uid ());
> +}
> +
> +/* Create a new artificial heap variable with NAME and UID.
> +   If UID is -1 allocate a new one.  Return the created variable.  */
>
>  static varinfo_t
> -make_heapvar (const char *name)
> +make_heapvar (const char *name, int uid)
>  {
>    varinfo_t vi;
>    tree heapvar;
>
> -  heapvar = build_fake_var_decl (ptr_type_node);
> +  if (uid == -1)
> +    heapvar = build_fake_var_decl (ptr_type_node);
> +  else
> +    heapvar = build_fake_var_decl_uid (ptr_type_node, uid);
>    DECL_EXTERNAL (heapvar) = 1;
>
>    vi = new_var_info (heapvar, name);
> @@ -3781,22 +3793,34 @@ make_heapvar (const char *name)
>    return vi;
>  }
>
> -/* Create a new artificial heap variable with NAME and make a
> +/* Create a new artificial heap variable with NAME and UID and make a
>     constraint from it to LHS.  Set flags according to a tag used
>     for tracking restrict pointers.  */
>
>  static varinfo_t
> -make_constraint_from_restrict (varinfo_t lhs, const char *name)
> +make_constraint_from_restrict_uid (varinfo_t lhs, const char *name, int uid)
>  {
> -  varinfo_t vi = make_heapvar (name);
> -  vi->is_global_var = 1;
> -  vi->may_have_pointers = 1;
> +  varinfo_t vi;
> +  vi = make_heapvar (name, uid);
>    make_constraint_from (lhs, vi->id);
> +  vi->is_global_var = 0;
> +  /*vi->is_special_var = 1;*/
> +  vi->may_have_pointers = 1;
>    return vi;
>  }
>
>  /* Create a new artificial heap variable with NAME and make a
>     constraint from it to LHS.  Set flags according to a tag used
> +   for tracking restrict pointers.  */
> +
> +static varinfo_t
> +make_constraint_from_restrict (varinfo_t lhs, const char *name)
> +{
> +  return make_constraint_from_restrict_uid (lhs, name, -1);
> +}
> +
> +/* Create a new artificial heap variable with NAME and make a
> +   constraint from it to LHS.  Set flags according to a tag used
>     for tracking restrict pointers and make the artificial heap
>     point to global memory.  */
>
> @@ -3804,6 +3828,7 @@ static varinfo_t
>  make_constraint_from_global_restrict (varinfo_t lhs, const char *name)
>  {
>    varinfo_t vi = make_constraint_from_restrict (lhs, name);
> +  vi->is_global_var = 1;
>    make_copy_constraint (vi, nonlocal_id);
>    return vi;
>  }
> @@ -3999,7 +4024,7 @@ handle_lhs_call (gimple stmt, tree lhs,
>        varinfo_t vi;
>        struct constraint_expr tmpc;
>        rhsc.create (0);
> -      vi = make_heapvar ("HEAP");
> +      vi = make_heapvar ("HEAP", -1);
>        /* We marking allocated storage local, we deal with it becoming
>           global by escaping and setting of vars_contains_escaped_heap.  */
>        DECL_EXTERNAL (vi->decl) = 0;
> @@ -4490,6 +4515,28 @@ find_func_aliases_for_builtin_call (gimp
>    return false;
>  }
>
> +/* Create constraints for the internal call T.  Return true if the call
> +   was handled, otherwise false.  */
> +
> +static bool
> +find_func_aliases_for_internal_call (gimple t)
> +{
> +  switch (gimple_call_internal_fn (t))
> +    {
> +    case IFN_DEL_RESTRICT:
> +      {
> +       /* DEL_RESTRICT is a barrier for what its argument points to.  */
> +       tree ptr = gimple_call_arg (t, 0);
> +       make_constraint_to (get_call_clobber_vi (t)->id, ptr);
> +       return true;
> +      }
> +
> +    default:
> +      /* Fallthru to general call handling.  */;
> +    }
> +  return false;
> +}
> +
>  /* Create constraints for the call T.  */
>
>  static void
> @@ -4505,6 +4552,10 @@ find_func_aliases_for_call (gimple t)
>        && find_func_aliases_for_builtin_call (t))
>      return;
>
> +  if (gimple_call_internal_p (t)
> +      && find_func_aliases_for_internal_call (t))
> +    return;
> +
>    fi = get_fi_for_callee (t);
>    if (!in_ipa_mode
>        || (fndecl && !fi->is_fn_info))
> @@ -4715,6 +4766,16 @@ find_func_aliases (gimple origt)
>             /* Truth value results are not pointer (parts).  Or at least
>                very very unreasonable obfuscation of a part.  */
>             ;
> +         else if (gimple_assign_rhs_code (t) == ADD_RESTRICT)
> +           {
> +             /* Add the specified restrict tag and merge from
> +                the incoming pointer.  */
> +             make_constraint_from_restrict_uid (get_vi_for_tree (lhsop),
> +                                                "RESTRICT_TAG",
> +                                                TREE_INT_CST_LOW
> +                                                  (gimple_assign_rhs2 (t)));
> +             get_constraint_for_rhs (gimple_assign_rhs1 (t), &rhsc);
> +           }
>           else
>             {
>               /* All other operations are merges.  */
> @@ -5852,50 +5913,10 @@ intra_create_variable_infos (void)
>      {
>        varinfo_t p = get_vi_for_tree (t);
>
> -      /* For restrict qualified pointers to objects passed by
> -         reference build a real representative for the pointed-to object.
> -        Treat restrict qualified references the same.  */
> -      if (TYPE_RESTRICT (TREE_TYPE (t))
> -         && ((DECL_BY_REFERENCE (t) && POINTER_TYPE_P (TREE_TYPE (t)))
> -             || TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
> -         && !type_contains_placeholder_p (TREE_TYPE (TREE_TYPE (t))))
> -       {
> -         struct constraint_expr lhsc, rhsc;
> -         varinfo_t vi;
> -         tree heapvar = build_fake_var_decl (TREE_TYPE (TREE_TYPE (t)));
> -         DECL_EXTERNAL (heapvar) = 1;
> -         vi = create_variable_info_for_1 (heapvar, "PARM_NOALIAS");
> -         insert_vi_for_tree (heapvar, vi);
> -         lhsc.var = p->id;
> -         lhsc.type = SCALAR;
> -         lhsc.offset = 0;
> -         rhsc.var = vi->id;
> -         rhsc.type = ADDRESSOF;
> -         rhsc.offset = 0;
> -         process_constraint (new_constraint (lhsc, rhsc));
> -         for (; vi; vi = vi_next (vi))
> -           if (vi->may_have_pointers)
> -             {
> -               if (vi->only_restrict_pointers)
> -                 make_constraint_from_global_restrict (vi, 
> "GLOBAL_RESTRICT");
> -               else
> -                 make_copy_constraint (vi, nonlocal_id);
> -             }
> -         continue;
> -       }
> -
> -      if (POINTER_TYPE_P (TREE_TYPE (t))
> -         && TYPE_RESTRICT (TREE_TYPE (t)))
> -       make_constraint_from_global_restrict (p, "PARM_RESTRICT");
> -      else
> +      for (; p; p = vi_next (p))
>         {
> -         for (; p; p = vi_next (p))
> -           {
> -             if (p->only_restrict_pointers)
> -               make_constraint_from_global_restrict (p, "PARM_RESTRICT");
> -             else if (p->may_have_pointers)
> -               make_constraint_from (p, nonlocal_id);
> -           }
> +         if (p->may_have_pointers)
> +           make_constraint_from (p, nonlocal_id);
>         }
>      }
>
> @@ -6022,7 +6043,7 @@ set_uids_in_ptset (bitmap into, bitmap f
>               && bitmap_bit_p (escaped_vi->solution, i)))
>         {
>           pt->vars_contains_escaped = true;
> -         pt->vars_contains_escaped_heap = vi->is_heap_var;
> +         pt->vars_contains_escaped_heap |= vi->is_heap_var;
>         }
>
>        if (TREE_CODE (vi->decl) == VAR_DECL
> @@ -6045,10 +6066,10 @@ set_uids_in_ptset (bitmap into, bitmap f
>  }
>
>
> -/* Compute the points-to solution *PT for the variable VI.  */
> +/* Compute the points-to solution *PT for the variable VI, part one.  */
>
>  static struct pt_solution
> -find_what_var_points_to (varinfo_t orig_vi)
> +find_what_var_points_to_1 (varinfo_t orig_vi)
>  {
>    unsigned int i;
>    bitmap_iterator bi;
> @@ -6096,7 +6117,7 @@ find_what_var_points_to (varinfo_t orig_
>             /* Nobody cares.  */
>             ;
>           else if (vi->id == anything_id
> -                  || vi->id == integer_id)
> +                   || vi->id == integer_id)
>             pt->anything = 1;
>         }
>      }
> @@ -6126,6 +6147,71 @@ find_what_var_points_to (varinfo_t orig_
>    return *pt;
>  }
>
> +/* Compute the points-to solution *PT for the variable VI, part two.
> +   This modifies the points-to solution to cater for restrict pointers.
> +
> +   Restrict is modelled as a may-be restrict problem together with
> +   a must-be restrict problem.  From the must-be restrict solution we
> +   can later deduce non-aliasing (if the points-to sets don't intersect
> +   the two references can't alias).  The may-be restrict problem provides
> +   a sort of conservative cap for that such that a pointer p1 that is even
> +   remotely related to a restrict pointer r2 points to a superset of what
> +   p1 points to.  In particular we want to handle this situation:
> +
> +      1 int * restrict p1 = ...;
> +      2 temp = p1;
> +      3 int * restrict p2;
> +      4 p2 = temp;
> +
> +      Suppose that 'temp' is address taken, so (2) is a store and
> +      (4) a load.  We want to make sure that p1 and p2 are tagged
> +      the same (remember we're not handling just the C language
> +      definition of restrict).  To ensure this we need to look through
> +      memory (and even handle second level effects, like when a restrict
> +      pointer is stored into a global variable).
> +
> +   That's why we use the points-to solver for the may-be restrict problem
> +   (which handles memory conservatively correct).  The must-be restrict
> +   part then is formulated as a post-processing on the conservatively
> +   correct points-to solution.  For a set of variables their solution
> +   is pruned.  This pruned solution is returned here.  */
> +
> +static struct pt_solution
> +find_what_var_points_to (varinfo_t vi)
> +{
> +  struct pt_solution pt;
> +
> +  pt = find_what_var_points_to_1 (vi);
> +
> +  if (vi->decl && TREE_CODE (vi->decl) == SSA_NAME)
> +    {
> +      gimple g = SSA_NAME_DEF_STMT (vi->decl);
> +      if (g && is_gimple_assign (g)
> +         && gimple_assign_rhs_code (g) == ADD_RESTRICT)
> +       {
> +         /* Restrict pointers only point to their tags.  For now
> +            we leave also the other decls in the points-to set:
> +            changing the set would imply possibly unsharing the bitmap,
> +            and furthermore it's actually good to have precise
> +            decls in there in some cases, e.g. if it's local variables.
> +
> +            In effect this means removing the nonlocal flags.  To
> +            not regard stores via such pointers as inherently useless
> +            we need to set the vars_contains_escaped_heap flag, if the
> +            input contained some nonlocals.  */
> +         if (pt.vars_contains_nonlocal
> +             || pt.nonlocal
> +             || pt.vars_contains_escaped)
> +           pt.vars_contains_escaped_heap = 1;
> +         pt.nonlocal = 0;
> +         pt.vars_contains_escaped = 0;
> +         pt.vars_contains_nonlocal = 0;
> +       }
> +    }
> +
> +  return pt;
> +}
> +
>  /* Given a pointer variable P, fill in its points-to set.  */
>
>  static void
> @@ -6866,10 +6952,14 @@ compute_points_to_sets (void)
>               *pt = find_what_var_points_to (vi);
>               /* Escaped (and thus nonlocal) variables are always
>                  implicitly used by calls.  */
> -             /* ???  ESCAPED can be empty even though NONLOCAL
> -                always escaped.  */
> -             pt->nonlocal = 1;
> -             pt->escaped = 1;
> +             if (!gimple_call_internal_p (stmt)
> +                 || gimple_call_internal_fn (stmt) != IFN_DEL_RESTRICT)
> +               {
> +                 /* ???  ESCAPED can be empty even though NONLOCAL
> +                    always escaped.  */
> +                 pt->nonlocal = 1;
> +                 pt->escaped = 1;
> +               }
>             }
>           else
>             {
> @@ -6887,10 +6977,14 @@ compute_points_to_sets (void)
>               *pt = find_what_var_points_to (vi);
>               /* Escaped (and thus nonlocal) variables are always
>                  implicitly clobbered by calls.  */
> -             /* ???  ESCAPED can be empty even though NONLOCAL
> -                always escaped.  */
> -             pt->nonlocal = 1;
> -             pt->escaped = 1;
> +             if (!gimple_call_internal_p (stmt)
> +                 || gimple_call_internal_fn (stmt) != IFN_DEL_RESTRICT)
> +               {
> +                 /* ???  ESCAPED can be empty even though NONLOCAL
> +                    always escaped.  */
> +                 pt->nonlocal = 1;
> +                 pt->escaped = 1;
> +               }
>             }
>           else
>             {
> Index: tree.def
> ===================================================================
> --- tree.def    (revision 205123)
> +++ tree.def    (working copy)
> @@ -977,6 +977,8 @@ DEFTREECODE (WITH_SIZE_EXPR, "with_size_
>     generated by the builtin targetm.vectorize.mask_for_load_builtin_decl.  */
>  DEFTREECODE (REALIGN_LOAD_EXPR, "realign_load", tcc_expression, 3)
>
> +DEFTREECODE (ADD_RESTRICT, "add_restrict", tcc_binary, 2)
> +
>  /* Low-level memory addressing.  Operands are BASE (address of static or
>     global variable or register), OFFSET (integer constant),
>     INDEX (register), STEP (integer constant), INDEX2 (register),

Reply via email to