This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Overhaul middle-end handling of restrict


On Thu, 21 Nov 2013, Xinliang David Li wrote:

> On Thu, Nov 21, 2013 at 10:03 AM, Michael Matz <matz@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.

Apart from the issue that LTO drops all BLOCKs this makes the middle-end
feature too much tied to the C family frontends and their definition
of restrict.  It also requires BLOCK lookup / matching at the time
of the alias query (which generally deals with "refs" which may
end up not refering to any BLOCK or to different BLOCKs than the
GIMPLE they are used in).

It also suddenly makes having (correct) BLOCK info cause code generation
differences.

That said, you would somehow need to remember the BLOCK a restrict
"tag" is live in which doesn't make it a good fit for the current
alias-info we associate with SSA names.  If you don't allow
disambiguations against refs in nested BLOCKs then a single
"tag" decl with its associated BLOCK is enough to remember
(thus one additional pointer).

But well - I always wondered how other compilers implement support
for restrict (and how restricted that support is, and how strictly
following the standard).

The only other scheme I can come up with is to allow non-dependences
to be recorded and maintained throughout the compilation and have
frontends create them.

Richard.

> 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),
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746
GF: Jeff Hawn, Jennifer Guild, Felix Imend"orffer


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]