diff mbox

[UPC,07/22] lowering, pointer-to-shared ops

Message ID 20151201060236.GA31118@intrepid.com
State New
Headers show

Commit Message

Gary Funck Dec. 1, 2015, 6:02 a.m. UTC
Background
----------

An overview email, describing the UPC-related changes is here:
  https://gcc.gnu.org/ml/gcc-patches/2015-12/msg00005.html

The GUPC branch is described here:
  http://gcc.gnu.org/projects/gupc.html

The UPC-related source code differences are summarized here:
  http://gccupc.org/gupc-changes

All languages (c, c++, fortran, go, lto, objc, obj-c++) have been
bootstrapped; no test suite regressions were introduced,
relative to the GCC trunk.

If you are on the cc-list, your name was chosen either
because you are listed as a maintainer for the area that
applies to the patches described in this email, or you
were a frequent contributor of patches made to files listed
in this email.

In the change log entries included in each patch, the directory
containing the affected files is listed, followed by the files.
When the patches are applied, the change log entries will be
distributed to the appropriate ChangeLog file.

Overview
--------

The UPC lowering pass traverses the current function tree
and rewrites UPC related statements and operations into GENERIC.
The resulting GENERIC tree code will retain UPC pointers-to-shared (PTS)
types, but all operations such as 'get' and 'put' which indirect
through a pointer-to-shared have been lowered to use the internal
representation type.  Most of these operations on UPC pointers-to-shared
is implemented in c/c-upc-pts-ops.c.

The UPC lowering pass is implemented by upc_genericize() in
c/c-upc-low.c.  upc_genericize() is called from finish_function()
in c/c-decl.c. It is called just prior to calling c_genericize(),
if -fupc has been asserted.

The file c/c-upc-rts-names.h defines the names of the UPC runtime
entry points and variables that implement the runtime ABI.
To date, there has been no need to implement target dependent names,
perhaps partly because UPC is supported primarily on POSIX-compliant targets.

UPC requires some special logic for handling file scoped initializations.
This is due to the fact that UPC shared addresses are not known
until runtime and therefore cannot be statically initialized
in the usual way.  For example, 'addr_x' below must be initialized
at runtime.

  shared int x;
  shared int *addr_x = &x;

The routine, upc_check_decl_init(), checks an initialization
statement to determine if it needs special handling.
It is called from store_init_value().  If an initialization
refers to UPC-related constructs that require initialization
at runtime, then upc_decl_init() is called to save the
initialization statement on a list.  This list is
processed by upc_write_global_declarations(), which
is called via a UPC-specific language hook from
c_common_parse_file(), just after calling c_parse_file().


2015-11-30  Gary Funck  <gary@intrepid.com>

	gcc/c-family/
	* c-upc-pts.h: New.  Define the sizes and types of fields
	in the UPC pointer-to-shared representation.
	gcc/c/
	* c-upc-low.c: New.  Lower UPC constructs to GENERIC.
	* c-upc-low.h: New.  Prototypes for c-upc-low.c.
	* c-upc-pts-ops.c: New. Implement UPC pointer-to-shared-operations.
	* c-upc-pts-ops.h: New. Prototypes for c-upc-pts-ops.c.
	* c-upc-rts-names.h: New.  Names of some functions in the UPC runtime.

Comments

Richard Biener Dec. 1, 2015, 11:42 a.m. UTC | #1
On Mon, 30 Nov 2015, Gary Funck wrote:

> 
> Background
> ----------
> 
> An overview email, describing the UPC-related changes is here:
>   https://gcc.gnu.org/ml/gcc-patches/2015-12/msg00005.html
> 
> The GUPC branch is described here:
>   http://gcc.gnu.org/projects/gupc.html
> 
> The UPC-related source code differences are summarized here:
>   http://gccupc.org/gupc-changes
> 
> All languages (c, c++, fortran, go, lto, objc, obj-c++) have been
> bootstrapped; no test suite regressions were introduced,
> relative to the GCC trunk.
> 
> If you are on the cc-list, your name was chosen either
> because you are listed as a maintainer for the area that
> applies to the patches described in this email, or you
> were a frequent contributor of patches made to files listed
> in this email.
> 
> In the change log entries included in each patch, the directory
> containing the affected files is listed, followed by the files.
> When the patches are applied, the change log entries will be
> distributed to the appropriate ChangeLog file.
> 
> Overview
> --------
> 
> The UPC lowering pass traverses the current function tree
> and rewrites UPC related statements and operations into GENERIC.
> The resulting GENERIC tree code will retain UPC pointers-to-shared (PTS)
> types, but all operations such as 'get' and 'put' which indirect
> through a pointer-to-shared have been lowered to use the internal
> representation type.  Most of these operations on UPC pointers-to-shared
> is implemented in c/c-upc-pts-ops.c.
> 
> The UPC lowering pass is implemented by upc_genericize() in
> c/c-upc-low.c.  upc_genericize() is called from finish_function()
> in c/c-decl.c. It is called just prior to calling c_genericize(),
> if -fupc has been asserted.
> 
> The file c/c-upc-rts-names.h defines the names of the UPC runtime
> entry points and variables that implement the runtime ABI.
> To date, there has been no need to implement target dependent names,
> perhaps partly because UPC is supported primarily on POSIX-compliant targets.
> 
> UPC requires some special logic for handling file scoped initializations.
> This is due to the fact that UPC shared addresses are not known
> until runtime and therefore cannot be statically initialized
> in the usual way.  For example, 'addr_x' below must be initialized
> at runtime.
> 
>   shared int x;
>   shared int *addr_x = &x;
> 
> The routine, upc_check_decl_init(), checks an initialization
> statement to determine if it needs special handling.
> It is called from store_init_value().  If an initialization
> refers to UPC-related constructs that require initialization
> at runtime, then upc_decl_init() is called to save the
> initialization statement on a list.  This list is
> processed by upc_write_global_declarations(), which
> is called via a UPC-specific language hook from
> c_common_parse_file(), just after calling c_parse_file().
> 
> 
> 2015-11-30  Gary Funck  <gary@intrepid.com>
> 
> 	gcc/c-family/
> 	* c-upc-pts.h: New.  Define the sizes and types of fields
> 	in the UPC pointer-to-shared representation.
> 	gcc/c/
> 	* c-upc-low.c: New.  Lower UPC constructs to GENERIC.
> 	* c-upc-low.h: New.  Prototypes for c-upc-low.c.
> 	* c-upc-pts-ops.c: New. Implement UPC pointer-to-shared-operations.
> 	* c-upc-pts-ops.h: New. Prototypes for c-upc-pts-ops.c.
> 	* c-upc-rts-names.h: New.  Names of some functions in the UPC runtime.
> 
> Index: gcc/c-family/c-upc-pts.h
> ===================================================================
> --- gcc/c-family/c-upc-pts.h	(.../trunk)	(revision 0)
> +++ gcc/c-family/c-upc-pts.h	(.../branches/gupc)	(revision 231080)
> @@ -0,0 +1,40 @@
> +/* Define UPC pointer-to-shared representation characteristics.
> +   Copyright (C) 2008-2015 Free Software Foundation, Inc.
> +   Contributed by Gary Funck <gary@intrepid.com>
> +     and Nenad Vukicevic <nenad@intrepid.com>.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify
> +it under the terms of the GNU General Public License as published by
> +the Free Software Foundation; either version 3, or (at your option)
> +any later version.
> +
> +GCC is distributed in the hope that it will be useful,
> +but WITHOUT ANY WARRANTY; without even the implied warranty of
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +GNU General Public License for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#ifndef GCC_C_FAMILY_UPC_PTS_H
> +#define GCC_C_FAMILY_UPC_PTS_H 1
> +
> +#define UPC_PTS_SIZE            (LONG_TYPE_SIZE + POINTER_SIZE)
> +#define UPC_PTS_PHASE_SIZE      (LONG_TYPE_SIZE / 2)
> +#define UPC_PTS_THREAD_SIZE     (LONG_TYPE_SIZE / 2)
> +#define UPC_PTS_VADDR_SIZE      POINTER_SIZE
> +#define UPC_PTS_PHASE_TYPE      ((LONG_TYPE_SIZE == 64) \
> +				? "uint32_t" : "uint16_t")
> +#define UPC_PTS_THREAD_TYPE     ((LONG_TYPE_SIZE == 64) \
> +				? "uint32_t" : "uint16_t")
> +#define UPC_PTS_VADDR_TYPE      "char *"
> +
> +#define UPC_MAX_THREADS (1 << (((UPC_PTS_THREAD_SIZE) < 30) \
> +				 ? (UPC_PTS_THREAD_SIZE) : 30))
> +#define UPC_MAX_BLOCK_SIZE ((1 << (((UPC_PTS_PHASE_SIZE) < 30) \
> +				    ? (UPC_PTS_PHASE_SIZE) : 30)) - 1)
> +
> +#endif  /* !GCC_C_FAMILY_UPC_PTS_H */
> Index: gcc/c/c-upc-low.c
> ===================================================================
> --- gcc/c/c-upc-low.c	(.../trunk)	(revision 0)
> +++ gcc/c/c-upc-low.c	(.../branches/gupc)	(revision 231080)
> @@ -0,0 +1,1434 @@
> +/* c-upc-low.c: UPC language specific tree lowering pass
> +   Copyright (C) 2006-2015 Free Software Foundation, Inc.
> +   Contributed by Gary Funck <gary@intrepid.com>
> +     and Nenad Vukicevic <nenad@intrepid.com>.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify
> +it under the terms of the GNU General Public License as published by
> +the Free Software Foundation; either version 3, or (at your option)
> +any later version.
> +
> +GCC is distributed in the hope that it will be useful,
> +but WITHOUT ANY WARRANTY; without even the implied warranty of
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +GNU General Public License for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "tm.h"
> +#include "tree.h"
> +#include "alias.h"
> +#include "fold-const.h"
> +#include "stringpool.h"
> +#include "hard-reg-set.h"
> +#include "c-tree.h"
> +#include "c-family/c-pragma.h"
> +#include "output.h"
> +#include "langhooks.h"
> +#include "function.h"
> +#include "tree-hasher.h"
> +#include "is-a.h"
> +#include "cgraph.h"
> +#include "gimple-expr.h"
> +#include "gimple-low.h"
> +#include "gimplify.h"
> +#include "stor-layout.h"
> +#include "varasm.h"
> +#include "timevar.h"
> +#include "tree-iterator.h"
> +#include "c-upc-low.h"
> +#include "c-upc.h"
> +#include "c-upc-gasp.h"
> +#include "c-upc-pts-ops.h"
> +#include "c-upc-rts-names.h"
> +
> +static GTY (()) tree upc_init_stmt_list;
> +
> +static void get_lc_mode_name (char *, machine_mode);
> +static tree upc_expand_get (location_t, tree, int);
> +static tree upc_expand_put (location_t, tree, tree, int);
> +static tree upc_create_tmp_var (tree);
> +static tree upc_copy_value_to_tmp_var (tree *, tree);
> +static tree upc_make_bit_field_ref (tree, tree, int, int);
> +static tree upc_build_shared_var_addr (location_t, tree);
> +static tree upc_shared_addr (location_t, tree);
> +static tree upc_shared_addr_rep (location_t, tree);
> +static tree upc_simplify_shared_ref (location_t, tree);
> +static void upc_strip_useless_generic_pts_cvt (tree *);
> +static void upc_write_init_func (void);
> +
> +/* Given a shared variable's VAR_DECL node, map to another
> +   VAR_DECL that has a similar external symbol name, with
> +   the "shared" qualifier removed from its type.  This
> +   "shadow variable" is used to generate conventional
> +   address constants when referring to a shared variable.  */
> +static int_tree_htab_type *unshared_vars_map;
> +
> +static tree create_unshared_var (location_t, const tree);
> +static tree lookup_unshared_var (const tree);
> +static void map_unshared_var (const tree, const tree);
> +static tree unshared_var_addr (location_t, const tree);
> +static tree unshared_var_name (const tree);
> +static void upc_free_unshared_var_table (void);
> +
> +static void upc_genericize_addr_expr (location_t, tree *);
> +static void upc_genericize_array_ref (location_t, tree *);
> +static void upc_genericize_compound_expr (tree *, int);
> +static void upc_genericize_cond_expr (tree *, int);
> +static void upc_genericize_decl_expr (tree *);
> +static tree upc_genericize_expr (tree *, int *, void *);
> +static void upc_genericize_function (tree);
> +static void upc_genericize_field_ref (location_t, tree *);
> +static void upc_genericize_forall_stmt (tree *);
> +static void upc_genericize_indirect_ref (location_t, tree *);
> +static void upc_genericize_modify_expr (location_t, tree *, int);
> +static void upc_genericize_pts_arith_expr (location_t, tree *);
> +static void upc_genericize_pts_cond_expr (location_t, tree *);
> +static void upc_genericize_pts_cvt (location_t, tree *);
> +static void upc_genericize_pts_to_int_cvt (location_t, tree *);
> +static void upc_genericize_real_imag_ref (location_t, tree *);
> +static void upc_genericize_shared_inc_dec_expr (location_t, tree *, int);
> +static void upc_genericize_shared_var_ref (location_t, tree *);
> +static void upc_genericize_walk (tree *, int);
> +static void upc_genericize_stmt_list (tree *);
> +static void upc_genericize_sync_stmt (location_t, tree *);
> +
> +/* Create a new temporary variable declaration of type TYPE.
> +   Push the variable into the current function binding.  */
> +
> +static tree
> +upc_create_tmp_var (tree type)
> +{
> +  tree tmp_var;
> +  /* We don't allow types that are addressable or incomplete.  */
> +  gcc_assert (!TREE_ADDRESSABLE (type) && COMPLETE_TYPE_P (type));
> +  /* The temp. must not be shared qualified.  If it is, then 
> +     remove the 'shared' qualifier.  */
> +  if (SHARED_TYPE_P (type))
> +    type = build_unshared_type (type);
> +  tmp_var = create_tmp_var_raw (type, "UPC");
> +  DECL_CONTEXT (tmp_var) = current_function_decl;
> +  DECL_SEEN_IN_BIND_EXPR_P (tmp_var) = 1;
> +  /* record_vars() will do what we want, but not if GIMPLE_DF is set.
> +     (since we haven't gimplified yet, it should not be set).  */
> +  gcc_assert (!cfun->gimple_df);
> +  record_vars (tmp_var);
> +  return tmp_var;
> +}
> +
> +/* Create a temporary variable and initialize it to VAL.
> +   The expression used to initialize the temporary value
> +   is returned in *VAL_EXPR.  */
> +
> +static tree
> +upc_copy_value_to_tmp_var (tree *val_expr, tree val)
> +{
> +  const tree type = TREE_TYPE (val);
> +  const tree tmp_var = upc_create_tmp_var (type);
> +  *val_expr = build2 (INIT_EXPR, type, tmp_var, val);
> +  SET_EXPR_LOCATION (*val_expr, EXPR_LOC_OR_LOC (val, input_location));
> +  return tmp_var;
> +}
> +
> +static void
> +get_lc_mode_name (char *mname, machine_mode mode)
> +{
> +  char *m = mname;
> +  const char *m_upper = GET_MODE_NAME (mode);
> +  while (*m_upper)
> +    *m++ = TOLOWER (*m_upper++);
> +  *m = '\0';
> +}
> +
> +/* Generate a call to the runtime to implement a 'get' of a shared
> +   object.  SRC is a reference to  a UPC shared value; it must
> +   be addressable.  */
> +
> +static tree
> +upc_expand_get (location_t loc, tree src, int want_stable_value)
> +{
> +  tree type = TREE_TYPE (src);
> +  /* Drop the shared qualifier.  */
> +  tree result_type = TYPE_MAIN_VARIANT (type);
> +  int strict_mode = TYPE_STRICT (type)
> +    || (!TYPE_RELAXED (type) && get_upc_consistency_mode ());
> +  int doprofcall = flag_upc_debug
> +                   || (flag_upc_instrument && get_upc_pupc_mode ());
> +  machine_mode mode = TYPE_MODE (type);
> +  machine_mode op_mode = (mode == TImode) ? BLKmode : mode;
> +  expanded_location s = expand_location (loc);
> +  const char *src_filename = s.file;
> +  const int src_line = s.line;
> +  char libfunc_name[16], mname[8];
> +  tree src_addr, result, result_tmp, libfunc, lib_args, lib_call;
> +  src_addr = upc_shared_addr_rep (loc, src);
> +  gcc_assert (TREE_TYPE (src_addr) == upc_pts_rep_type_node);
> +  get_lc_mode_name (mname, (op_mode));
> +  sprintf (libfunc_name, "__get%s%s%s%s",
> +           strict_mode ? "s" : "",
> +           doprofcall ? "g" : "",
> +	   mname,
> +	   (op_mode == BLKmode)
> +	     ? (doprofcall ? "5" : "3")
> +	     : (doprofcall ? "3" : "2"));
> +  libfunc = identifier_global_value (get_identifier (libfunc_name));
> +  if (!libfunc)
> +    internal_error ("UPC runtime function %s not found", libfunc_name);

I think for all these you should use builtins.  You definitely shouldn't
ICE here if it is an error to not include upc.h (or whatever is required
to make above lookup succeed).

> +  if (op_mode == BLKmode)
> +    {
> +      tree size = size_in_bytes (result_type);
> +      tree result_addr;
> +      result_tmp = upc_create_tmp_var (result_type);
> +      TREE_ADDRESSABLE (result_tmp) = 1;
> +      result_addr = build_fold_addr_expr_loc (loc, result_tmp);
> +      /* A DECL_EXPR is sometimes needed (for example when applying
> +         sizeof() to a UPC shared VLA) to properly declare
> +	 the type of the temp. variable used to hold the result
> +	 of the expression.  */
> +      result_addr = build2 (COMPOUND_EXPR, TREE_TYPE (result_addr),
> +			    build1 (DECL_EXPR, TREE_TYPE (result_tmp),
> +				    result_tmp),
> +			    result_addr);
> +      lib_args = tree_cons (NULL_TREE, result_addr,
> +			    tree_cons (NULL_TREE, src_addr,
> +				       tree_cons (NULL_TREE, size,
> +						  NULL_TREE)));
> +      if (doprofcall)
> +	lib_args = upc_gasp_add_src_args (lib_args,
> +					  src_filename, src_line);
> +      lib_call = build_function_call (loc, libfunc, lib_args);
> +      result = build2 (COMPOUND_EXPR, result_type, lib_call, result_tmp);
> +    }
> +  else
> +    {
> +      lib_args = tree_cons (NULL_TREE, src_addr, NULL_TREE);
> +      if (doprofcall)
> +	lib_args = upc_gasp_add_src_args (lib_args,
> +					  src_filename, src_line);
> +      lib_call = build_function_call (loc, libfunc, lib_args);
> +      if (!lang_hooks.types_compatible_p (result_type, TREE_TYPE (lib_call)))
> +	lib_call = build1 (NOP_EXPR, result_type, lib_call);
> +      result = lib_call;
> +      if (want_stable_value)
> +        {
> +	  tree result_tmp_init_expr;
> +          result_tmp = upc_copy_value_to_tmp_var (&result_tmp_init_expr,
> +	                                          result);
> +          result = build2 (COMPOUND_EXPR, result_type,
> +	                   result_tmp_init_expr, result_tmp);
> +	}
> +    }
> +  return result;
> +}
> +
> +/* Generate a call to the runtime to implement a 'put' into a shared
> +   object.  DEST is a reference to the destination in UPC shared memory;
> +   it must be addressable.  SRC is the value to be stored into the
> +   destination.  If WANT_VALUE is set, then return a compound expression
> +   which evaluates to the value of SRC.  */
> +
> +static tree
> +upc_expand_put (location_t loc, tree dest, tree src, int want_value)
> +{
> +  tree type = TREE_TYPE (dest);
> +  int strict_mode = TYPE_STRICT (type)
> +    || (!TYPE_RELAXED (type) && get_upc_consistency_mode ());
> +  int doprofcall = flag_upc_debug
> +                   || (flag_upc_instrument && get_upc_pupc_mode ());
> +  machine_mode mode = TYPE_MODE (type);
> +  machine_mode op_mode = (mode == TImode) ? BLKmode : mode;
> +  int is_src_shared = (TREE_SHARED (src)
> +		       || SHARED_TYPE_P (TREE_TYPE (src)));
> +  int local_copy = want_value
> +    || (op_mode == BLKmode
> +	&& !(is_src_shared && INDIRECT_REF_P (src))
> +	&& (!is_gimple_addressable (src)
> +	    || !is_gimple_variable (src)
> +	    || needs_to_live_in_memory (src)));
> +  int is_shared_copy = !local_copy && (op_mode == BLKmode) && is_src_shared;
> +  char libfunc_name[16], mname[8];
> +  expanded_location s = expand_location (loc);
> +  const char *src_filename = s.file;
> +  const int src_line = s.line;
> +  tree dest_addr, libfunc, lib_args, src_tmp_init_expr, result;
> +  dest_addr = upc_shared_addr_rep (loc, dest);
> +  gcc_assert (TREE_TYPE (dest_addr) == upc_pts_rep_type_node);
> +  if (local_copy)
> +    src = upc_copy_value_to_tmp_var (&src_tmp_init_expr, src);
> +  lib_args = tree_cons (NULL_TREE, dest_addr, NULL_TREE);
> +  if (is_shared_copy)
> +    {
> +      sprintf (libfunc_name, "__copy%s%sblk%s",
> +	       strict_mode ? "s" : "",
> +	       doprofcall ? "g" : "",
> +	       doprofcall ? "5" : "3");
> +    }
> +  else
> +    {
> +      get_lc_mode_name (mname, op_mode);
> +      sprintf (libfunc_name, "__put%s%s%s%s",
> +	       strict_mode ? "s" : "",
> +	       doprofcall ? "g" : "",
> +	       mname,
> +	       (op_mode == BLKmode)
> +	       ? (doprofcall ? "5" : "3")
> +	       : (doprofcall ? "4" : "2"));
> +    }
> +  libfunc = identifier_global_value (get_identifier (libfunc_name));
> +  if (!libfunc)
> +    internal_error ("UPC runtime function %s not found", libfunc_name);
> +  if (op_mode == BLKmode)
> +    {
> +      const tree size = tree_expr_size (src);
> +      tree src_addr;
> +      if (is_shared_copy)
> +	src_addr = upc_shared_addr_rep (loc, src);
> +      else
> +        src_addr = build_fold_addr_expr_loc (loc, src);
> +      lib_args = chainon (lib_args,
> +			  tree_cons (NULL_TREE, src_addr,
> +				     tree_cons (NULL_TREE, size, NULL_TREE)));
> +      if (doprofcall)
> +	lib_args = upc_gasp_add_src_args (lib_args, src_filename, src_line);
> +    }
> +  else
> +    {
> +      tree src_type = lang_hooks.types.type_for_mode (mode, 0);
> +      tree libfunc_arg_types = TYPE_ARG_TYPES (TREE_TYPE (libfunc));
> +      tree put_arg_type = TREE_VALUE (TREE_CHAIN (libfunc_arg_types));
> +      if (TYPE_PRECISION (put_arg_type) != TYPE_PRECISION (src_type))
> +	internal_error ("%s: UPC put operation argument precision mismatch",
> +			libfunc_name);
> +      /* Avoid warnings about implicit conversion between
> +         the actual parameter value's type, and the type of the
> +         runtime routine's parameter.  */
> +      if (!lang_hooks.types_compatible_p (src_type, TREE_TYPE (src)))
> +	src = build1 (AGGREGATE_TYPE_P (TREE_TYPE (src))
> +		      ? VIEW_CONVERT_EXPR : NOP_EXPR, src_type, src);
> +      lib_args = chainon (lib_args, tree_cons (NULL_TREE, src, NULL_TREE));
> +      if (doprofcall)
> +	lib_args = upc_gasp_add_src_args (lib_args, src_filename, src_line);
> +    }
> +  result = build_function_call (loc, libfunc, lib_args);
> +  if (want_value)
> +    result = build2 (COMPOUND_EXPR, TREE_TYPE (src), result, src);
> +  if (local_copy)
> +    result = build2 (COMPOUND_EXPR, TREE_TYPE (result),
> +		     src_tmp_init_expr, result);
> +  return result;
> +}
> +
> +/* Return a BIT_FIELD_REF of type TYPE to refer to BITSIZE bits of INNER
> +   starting at BITPOS.  The field is unsigned if UNSIGNEDP is nonzero.  */
> +
> +static tree
> +upc_make_bit_field_ref (tree inner, tree type, int bitsize, int bitpos)
> +{
> +  tree result;
> +  if (bitpos == 0)
> +    {
> +      tree size = TYPE_SIZE (TREE_TYPE (inner));
> +      if ((INTEGRAL_TYPE_P (TREE_TYPE (inner))
> +	   || POINTER_TYPE_P (TREE_TYPE (inner)))
> +	  && tree_fits_shwi_p (size)
> +	  && tree_to_shwi (size) == bitsize)
> +	return fold_convert (type, inner);
> +    }
> +  result = build3 (BIT_FIELD_REF, type, inner,
> +		   size_int (bitsize), bitsize_int (bitpos));
> +  return result;
> +}
> +
> +/* On entry, EXP points to a shared field reference
> +   or array reference.  Simplify it so that is in
> +   one of two forms:
> +   1) (INDIRECT_REF <pointer to shared object>)
> +   2) (BIT_FIELD_REF (INDIRECT_REF <pointer to shared object>) ...)
> +   The first form is returned for all shared field references
> +   except those that require access to bit fields within
> +   a storage unit.  */
> +
> +static tree
> +upc_simplify_shared_ref (location_t loc, tree exp)
> +{
> +  tree ref_type = TREE_TYPE (exp);
> +  tree base, base_addr, ref, t_offset;
> +  machine_mode mode = VOIDmode;
> +  HOST_WIDE_INT bitsize = 0;
> +  HOST_WIDE_INT bitpos = 0;
> +  int unsignedp = 0;
> +  int reversep = 0;
> +  int volatilep = 0;
> +  tree offset = NULL_TREE;
> +  base = get_inner_reference (exp, &bitsize, &bitpos, &offset,
> +			      &mode, &unsignedp, &reversep, &volatilep,
> +			      false);
> +  gcc_assert (SHARED_TYPE_P (TREE_TYPE (base)));
> +  base_addr = build_fold_addr_expr (base);
> +  if (bitpos)
> +    {
> +      t_offset = size_int (bitpos / BITS_PER_UNIT);
> +      if (offset)
> +	t_offset = fold (build_binary_op (loc, PLUS_EXPR,
> +                         offset, t_offset, 0));

Don't use fold ().  If you want a simplified tree dont' go
through build_binary_op but use fold_build2.  In this case
it looks you want to use size_binop anyway.

> +    }
> +  else
> +    t_offset = offset;
> +  {
> +    const tree base_addr_type = TREE_TYPE (base_addr);
> +    const enum tree_code cvt_op =
> +	lang_hooks.types_compatible_p (upc_char_pts_type_node, base_addr_type)
> +	? NOP_EXPR : CONVERT_EXPR;

NOP and CONVERT are the same.

> +    /* Convert the base address to (shared [] char *), which may
> +       reset the pointer's phase to zero.  This is the behavior
> +       that is required to reference a field in a structure and
> +       to meaningfully add an offset to the base address.  */
> +    base_addr = build1 (cvt_op, upc_char_pts_type_node, base_addr);
> +    if (t_offset)
> +      {
> +	/* Adjust the base address so that it points to the
> +	   simplified lvalue.  */
> +	base_addr = fold (build_binary_op (loc, PLUS_EXPR,
> +			  base_addr, t_offset, 0));
> +	base_addr = convert (base_addr_type, base_addr);
> +      }
> +  }
> +  /* We need to construct a pointer-to-shared type that
> +     will be used to point to the referenced value.  However,
> +     for a COMPONENT_REF, the original type will likely not have
> +     SHARED_TYPE_P() asserted, but rather, the expression node itself
> +     will have TREE_SHARED asserted.  We need to first propagate
> +     this information into a new shared type, which will in turn be
> +     used to build the required pointer-to-shared type.  Further,
> +     any pointer to a shared component must be constrained to have
> +     a blocking factor of zero.  */
> +  if (!SHARED_TYPE_P (ref_type))
> +    {
> +      const int shared_quals = TYPE_QUALS (TREE_TYPE (exp))
> +                               | TREE_QUALS (exp);
> +      gcc_assert (shared_quals & TYPE_QUAL_SHARED);
> +      ref_type = c_build_qualified_type_1 (ref_type, shared_quals,
> +                                           size_zero_node);
> +    }
> +  if (TREE_TYPE (TREE_TYPE (base_addr)) != ref_type)
> +    base_addr = convert (build_pointer_type (ref_type), base_addr);
> +  /* The simplified reference is an indirect ref., using
> +     the adjusted base_addr  */
> +  ref = build_fold_indirect_ref_loc (loc, base_addr);
> +  /* If this is a BIT_FIELD_REF then adjust its base address.  */
> +  if (TREE_CODE (exp) == BIT_FIELD_REF)
> +    ref = upc_make_bit_field_ref (ref, ref_type, bitsize, bitpos);
> +  return ref;
> +}
> +
> +/* Create and return a "shadow variable" that has the same type as VAR,
> +   but with all UPC shared qualifiers removed from the type.
> +   The assembler name of this shadow variable is the same
> +   as that of the original variable, VAR.  */
> +
> +static tree
> +create_unshared_var (location_t loc, const tree var)
> +{
> +  tree u_name, u_type, u;
> +  gcc_assert (var && TREE_CODE (var) == VAR_DECL);
> +  u_name = unshared_var_name (var);
> +  u_type = build_unshared_type (TREE_TYPE (var));
> +  u = build_decl (loc, VAR_DECL, u_name, u_type);
> +  TREE_USED (u) = 1;
> +  TREE_ADDRESSABLE (u) = 1;
> +  TREE_PUBLIC (u) = TREE_PUBLIC (var);
> +  TREE_STATIC (u) = TREE_STATIC (var);
> +  DECL_ARTIFICIAL (u) = 1;
> +  DECL_IGNORED_P (u) = 1;
> +  set_decl_section_name (u, DECL_SECTION_NAME (var));
> +  DECL_CONTEXT (u) = DECL_CONTEXT (var);
> +  /* Define it as 'external' so that no data is allocated.  */
> +  DECL_EXTERNAL (u) = 1;
> +  /* Alias the unshared variable to the shared variable.  */
> +  SET_DECL_ASSEMBLER_NAME (u, DECL_ASSEMBLER_NAME (var));
> +  /* Make sure the variable is referenced.  */
> +  mark_decl_referenced (var);
> +  return u;
> +}
> +
> +/* Return the "shadow variable" created for VAR that
> +   has the same type as VAR, but with the UPC shared
> +   qualifiers removed.  */
> +
> +static tree
> +lookup_unshared_var (const tree var)
> +{
> +  struct int_tree_map in;
> +  unsigned int uid;
> +  gcc_assert (var && TREE_CODE (var) == VAR_DECL);
> +  uid = DECL_UID (var);
> +  in.uid = uid;
> +  in.to = NULL_TREE;
> +  return unshared_vars_map->find_with_hash (in, uid).to;
> +}
> +
> +#define UNSHARE_PREFIX "_u_"
> +
> +/* Return an identifier that will be used to declare the "shadow variable"
> +   which has the same type as VAR, but with all UPC shared qualifiers
> +   removed from the type.  The identifier has the same name as
> +   that of VAR, prefixed with the string given by the
> +   value of `UNSHARE_PREFIX'.  */
> +
> +static tree
> +unshared_var_name (const tree var)
> +{
> +  const tree name = DECL_NAME (var);
> +  const size_t len = IDENTIFIER_LENGTH (name);
> +  char *tmp_name = (char *) alloca (len + sizeof (UNSHARE_PREFIX));
> +  strcpy (tmp_name, UNSHARE_PREFIX);
> +  strcat (tmp_name, IDENTIFIER_POINTER (name));
> +  return get_identifier (tmp_name);
> +}
> +
> +/* Register the mapping between the UPC shared variable, VAR,
> +   and its unshared counter-part, U_VAR.  "unshared" in
> +   this context means that the shadow variable U_VAR
> +   has the same type as VAR, with the UPC shared,
> +   strict, and relaxed qualifiers removed.  */
> +
> +static void
> +map_unshared_var (const tree var, const tree u_var)
> +{
> +  int_tree_map h;
> +  unsigned int uid;
> +  int_tree_map *loc;
> +  gcc_assert (var && TREE_CODE (var) == VAR_DECL);
> +  gcc_assert (u_var && TREE_CODE (u_var) == VAR_DECL);
> +  uid = DECL_UID (var);
> +  h.uid = uid;
> +  loc = unshared_vars_map->find_slot_with_hash (h, uid, INSERT);
> +  loc->uid = uid;
> +  loc->to = u_var;
> +}
> +
> +/* Return a tree node that evaluates to the address that the
> +   linker assigns to the UPC shared variable, VAR.  This is not
> +   the final location of the UPC shared variable.  The linker is
> +   used only to lay out a given UPC thread's contribution to the
> +   UPC shared global memory region.
> +
> +   The address expression returned will point to a "shadow
> +   variable" declaration that is created from the UPC shared
> +   variable declaration, VAR.  This shadow variable has the same
> +   type and other attributes as VAR, with the UPC shared type
> +   qualifiers removed.  */
> +
> +static tree
> +unshared_var_addr (location_t loc, const tree var)
> +{
> +  tree unshared_var, addr;
> +  unshared_var = lookup_unshared_var (var);
> +  if (!unshared_var)
> +    {
> +      unshared_var = create_unshared_var (loc, var);
> +      map_unshared_var (var, unshared_var);
> +    }
> +  addr = build_fold_addr_expr (unshared_var);
> +  TREE_CONSTANT (addr) = 1;
> +  TREE_READONLY (addr) = 1;
> +  return addr;
> +}
> +
> +/* Free the hash table used to map UPC VAR_DECL's
> +   into the "unshared" shadow variables that were created
> +   in order to establish the offset of a UPC shared
> +   variable with the special linker section that is
> +   created to collect the UPC shared variables.  */
> +
> +static void
> +upc_free_unshared_var_table (void)
> +{
> +  if (unshared_vars_map)
> +    {
> +      delete unshared_vars_map;
> +      unshared_vars_map = NULL;
> +    }
> +}
> +
> +/* Convert the shared variable reference VAR into a UPC pointer-to-shared
> +   value of the form {0, 0, &VAR}.  */
> +
> +static tree
> +upc_build_shared_var_addr (location_t loc, tree var)
> +{
> +  tree var_addr, val;
> +  gcc_assert (TREE_CODE (var) == VAR_DECL && TREE_SHARED (var));
> +  /* Refer to a shadow variable that has the same type as VAR, but
> +     with the shared qualifier removed.  */
> +  var_addr = unshared_var_addr (loc, var);
> +  val = upc_pts_build_value (loc, build_pointer_type (TREE_TYPE (var)),
> +                             var_addr, integer_zero_node, integer_zero_node);
> +  return val;
> +}
> +
> +/* Return the UPC shared address of the lvalue
> +   identified by EXP.  The type of the result is
> +   the UPC pointer-to-shared representation type.  */
> +
> +static tree
> +upc_shared_addr_rep (location_t loc, tree exp)
> +{
> +  tree addr = upc_shared_addr (loc, exp);
> +  /* Convert to internal UPC pointer-to-shared representation,
> +     possibly removing an unnecessary chain of VIEW_CONVERT_EXPR's.  */
> +  addr = fold (build1 (VIEW_CONVERT_EXPR, upc_pts_rep_type_node, addr));
> +  return addr;
> +}
> +
> +/* Return the UPC shared address of the lvalue
> +   identified by EXP.  The type of the result is
> +   the UPC pointer-to-shared representation type.  */
> +
> +static tree
> +upc_shared_addr (location_t loc, tree exp)
> +{
> +  tree ref = exp;
> +  const enum tree_code code = TREE_CODE (exp);
> +  tree addr;
> +  switch (code)
> +    {
> +    case VAR_DECL:
> +      addr = upc_build_shared_var_addr (loc, exp);
> +      break;
> +    case ARRAY_REF:
> +    case COMPONENT_REF:
> +      ref = upc_simplify_shared_ref (loc, exp);
> +      if (TREE_CODE (ref) == ERROR_MARK)
> +	return ref;
> +      addr = build_fold_addr_expr_loc (loc, ref);
> +      upc_genericize_walk (&addr, /* want_value */ 1);
> +      break;
> +    case INDIRECT_REF:
> +      /* Remove the indirection by taking the address and simplifying.  */
> +      addr = build_fold_addr_expr_loc (loc, ref);
> +      upc_genericize_walk (&addr, /* want_value */ 1);
> +      break;
> +    case BIT_FIELD_REF:
> +      error ("invalid & operation applied to a UPC shared bit field");
> +      return error_mark_node;
> +    default:
> +      gcc_unreachable ();
> +    }
> +  return addr;
> +}
> +
> +/* Rewrite a 'upc_forall' statement into a
> +   regular 'for' statement.  */
> +
> +static void
> +upc_genericize_forall_stmt (tree *expr_p ATTRIBUTE_UNUSED)
> +{
> +  /* Handled in c-parser.c.  */
> +  gcc_unreachable ();
> +}
> +
> +/* Rewrite a UPC synchronization statement (upc_wait, upc_notify,
> +   and upc_barrier) into a call to the runtime.  */
> +
> +static void
> +upc_genericize_sync_stmt (location_t loc, tree *stmt_p)
> +{
> +  /* The first operand is the synchronization operation, UPC_SYNC_OP:
> +     UPC_SYNC_NOTIFY_OP         1       Notify operation
> +     UPC_SYNC_WAIT_OP           2       Wait operation
> +     UPC_SYNC_BARRIER_OP        3       Barrier operation
> +     The second operand, UPC_SYNC_ID is the (optional) expression
> +     whose value specifies the barrier identifier which is checked
> +     by the various synchronization operations.  */
> +  tree stmt = *stmt_p;
> +  tree sync_op = UPC_SYNC_OP (stmt);
> +  tree sync_id = UPC_SYNC_ID (stmt);
> +  const int op = tree_to_shwi (sync_op);
> +  const char *libfunc_name = (char *) 0;
> +  int doprofcall = flag_upc_debug
> +                   || (flag_upc_instrument && get_upc_pupc_mode ());
> +  tree libfunc, lib_args;
> +  switch (op)
> +    {
> +    case UPC_SYNC_NOTIFY_OP:
> +      libfunc_name = doprofcall ? UPC_NOTIFYG_LIBCALL : UPC_NOTIFY_LIBCALL;
> +      break;
> +    case UPC_SYNC_WAIT_OP:
> +      libfunc_name = doprofcall ? UPC_WAITG_LIBCALL : UPC_WAIT_LIBCALL;
> +      break;
> +    case UPC_SYNC_BARRIER_OP:
> +      libfunc_name = doprofcall ? UPC_BARRIERG_LIBCALL : UPC_BARRIER_LIBCALL;
> +      break;
> +    default:
> +      gcc_unreachable ();
> +    }
> +  libfunc = identifier_global_value (get_identifier (libfunc_name));
> +  if (!libfunc)
> +    internal_error ("UPC runtime function %s not found", libfunc_name);
> +  if (!sync_id)
> +    sync_id = build_int_cst (NULL_TREE, INT_MIN);
> +  lib_args = tree_cons (NULL_TREE, sync_id, NULL_TREE);
> +  if (doprofcall)
> +    lib_args = upc_gasp_add_src_args (lib_args,
> +                                      LOCATION_FILE (input_location),
> +                                      LOCATION_LINE (input_location));
> +  *stmt_p = build_function_call (loc, libfunc, lib_args);
> +}
> +
> +/* Rewrite a reference to a UPC shared variable into a 'get' operation.  */
> +
> +static void
> +upc_genericize_shared_var_ref (location_t loc, tree *expr_p)
> +{
> +  tree src = *expr_p;
> +  *expr_p = upc_expand_get (loc, src, 0);
> +}
> +
> +/* Expand & of a UPC shared object into equivalent code.  */
> +
> +static void
> +upc_genericize_addr_expr (location_t loc, tree *expr_p)
> +{
> +  const tree op0 = TREE_OPERAND (*expr_p, 0);
> +  *expr_p = upc_shared_addr (loc, op0);
> +}
> +
> +/* Expand indirection through a UPC pointer-to-shared
> +   into a UPC get operation.  */
> +
> +static void
> +upc_genericize_indirect_ref (location_t loc, tree *expr_p)
> +{
> +  tree src = *expr_p;
> +  *expr_p = upc_expand_get (loc, src, 0);
> +}
> +
> +/* Expand .real and .imag applied to a UPC shared object.  */
> +
> +static void
> +upc_genericize_real_imag_ref (location_t loc ATTRIBUTE_UNUSED,
> +			      tree *expr_p ATTRIBUTE_UNUSED)
> +{
> +  error ("accesses to .real and .imag are not yet implemented");
> +  *expr_p = error_mark_node;
> +}
> +
> +/* Rewrite a[i] into *(a + i).  This code is derived from
> +   build_array_ref().  We could call build_array_ref()
> +   directly, and depend upon it to do this rewrite if
> +   the array is shared, but it is clearer to handle
> +   it explicitly here.  */
> +
> +static void
> +upc_genericize_array_ref (location_t loc, tree *expr_p)
> +{
> +  tree exp = *expr_p;
> +  tree array = TREE_OPERAND (exp, 0);
> +  tree index = TREE_OPERAND (exp, 1);
> +  tree ar = default_conversion (array);
> +  gcc_assert (TREE_CODE (exp) == ARRAY_REF);
> +  if (ar == error_mark_node)
> +    return;
> +  gcc_assert (TREE_CODE (TREE_TYPE (ar)) == POINTER_TYPE);
> +  gcc_assert (TREE_CODE (TREE_TYPE (TREE_TYPE (ar))) != FUNCTION_TYPE);
> +  *expr_p = build_indirect_ref (loc,
> +				build_binary_op (loc, PLUS_EXPR, ar, index,
> +						 0), RO_ARRAY_INDEXING);
> +  upc_genericize_indirect_ref (loc, expr_p);
> +}
> +
> +/* Handle conversions between UPC pointers-to-shared and
> +   local pointers, or between UPC pointers-to-shared which
> +   have differing block factors.  */
> +
> +static void
> +upc_genericize_pts_cvt (location_t loc, tree *expr_p)
> +{
> +  *expr_p = upc_pts_build_cvt (loc, *expr_p);
> +}
> +
> +/* Handle conversions from a UPC pointer-to-shared into
> +   an integer value.  */
> +
> +static void
> +upc_genericize_pts_to_int_cvt (location_t loc, tree *expr_p)
> +{
> +  tree pts, pts_arg, ref_type, upc_addrfield;
> +  tree *pts_p;
> +  int shared_quals;
> +  upc_addrfield = identifier_global_value (get_identifier ("upc_addrfield"));
> +  if (!upc_addrfield)
> +    internal_error ("UPC runtime function `upc_addrfield` not found");
> +  pts_p = &TREE_OPERAND (*expr_p, 0);
> +  pts = *pts_p;
> +  ref_type = TREE_TYPE (TREE_TYPE (pts));
> +  shared_quals = TYPE_QUALS (ref_type) | TREE_QUALS (pts);
> +  gcc_assert (shared_quals & TYPE_QUAL_SHARED);
> +  if ((shared_quals & TYPE_QUAL_CONST) != 0)
> +    {
> +      /* Drop 'const' qualifier to arg. type mis-match.  */
> +      shared_quals &= ~TYPE_QUAL_CONST;
> +      ref_type = c_build_qualified_type_1 (ref_type, shared_quals,
> +                                           size_zero_node);
> +      TREE_TYPE (pts) = build_pointer_type (ref_type);
> +    }
> +  pts_arg = tree_cons (NULL_TREE, pts, NULL_TREE);
> +  *pts_p = build_function_call (loc, upc_addrfield, pts_arg);
> +}
> +
> +/* Rewrite op0 CMP op1 into either a bitwise
> +   comparison of the UPC pointer-to-shared operands
> +   or by taking the difference, and comparing it
> +   to zero.  */
> +
> +static void
> +upc_genericize_pts_cond_expr (location_t loc, tree *expr_p)
> +{
> +  *expr_p = upc_pts_build_cond_expr (loc, *expr_p);
> +}
> +
> +/* Rewrite a reference to a bit field within a UPC shared struct/union.
> +   When implemented, the translated tree will need to fetch
> +   the container for this bit-field from UPC shared memory,
> +   and then isolate the bit field within the container.  */
> +
> +static void
> +upc_genericize_field_ref (location_t loc, tree *expr_p)
> +{
> +  tree ref = upc_simplify_shared_ref (loc, *expr_p);
> +  if (TREE_CODE (ref) == BIT_FIELD_REF)
> +    {
> +      error_at (loc, "accesses to UPC shared bit fields "
> +                     "are not yet implemented");
> +      ref = error_mark_node;
> +    }
> +  else
> +    ref = upc_expand_get (loc, ref, 0);
> +  *expr_p = ref;
> +}
> +
> +/* Expand the addition of UPC pointer-to-shared value and an integer.
> +   When the operation is subtraction, rewrite the expression (p - i)
> +   into (p + (-i)) and expand the sum.  The special handling of
> +   subtraction is required because addition/subtraction of UPC
> +   pointers-to-shared is a non-trivial operation, and it simpler
> +   to only implement addition.  */
> +
> +static void
> +upc_genericize_pts_arith_expr (location_t loc, tree *expr_p)
> +{
> +  tree exp = *expr_p;
> +  if (TREE_CODE (exp) == PLUS_EXPR || TREE_CODE (exp) == POINTER_PLUS_EXPR)
> +    {
> +      *expr_p = upc_pts_build_sum (loc, exp);
> +    }
> +  else if (TREE_CODE (exp) == MINUS_EXPR)
> +    {
> +      const tree type0 = TREE_TYPE (TREE_OPERAND (exp, 0));
> +      const tree type1 = TREE_TYPE (TREE_OPERAND (exp, 1));
> +      if ((TREE_CODE (type0) == POINTER_TYPE)
> +	  && (TREE_CODE (type1) == INTEGER_TYPE))
> +	{
> +	  /* Rewrite the expression p - i into p + (-i),
> +	     and expand the sum.  */
> +	  tree int_op = TREE_OPERAND (exp, 1);
> +	  if (TREE_CODE (int_op) == INTEGER_CST
> +	      && TREE_CODE (TREE_TYPE (int_op)) == POINTER_TYPE)
> +	    {
> +	      /* Earlier passes have altered the type of the integer
> +	         constant to be a UPC pointer-to-shared type.  This won't
> +	         play well when we try to negate it.  For now, convert
> +	         it back to a size type.  */
> +	      int_op = ssize_int (tree_to_shwi (int_op));
> +	    }
> +	  TREE_SET_CODE (exp, PLUS_EXPR);
> +	  /* Make sure that int_op is a signed type to
> +	     ensure negation works properly.  */
> +	  if (TYPE_UNSIGNED (TREE_TYPE (int_op)))
> +	    int_op = convert (ssizetype, int_op);
> +	  TREE_OPERAND (exp, 1) =
> +	    build_unary_op (loc, NEGATE_EXPR, int_op, 0);
> +	  *expr_p = upc_pts_build_sum (loc, exp);
> +	}
> +      else
> +	*expr_p = upc_pts_build_diff (loc, exp);
> +    }
> +  else
> +    gcc_unreachable ();
> +}
> +
> +/* Rewrite the increment/decrement of a UPC shared value into
> +   an equivalent assignment statement.  (Although some future
> +   implementations of the UPC runtime API might be able to
> +   implement these operations atomically, that is not currently
> +   defined in the runtime API.)  If WANT_VALUE is set, then
> +   generate a compound expression that yields the appropriate value.  */
> +
> +static void
> +upc_genericize_shared_inc_dec_expr (location_t loc, tree *expr_p,
> +				    int want_value)
> +{
> +  const tree exp = *expr_p;
> +  const enum tree_code code = TREE_CODE (exp);
> +  const tree op0 = TREE_OPERAND (exp, 0);
> +  const int is_inc_op = (code == POSTINCREMENT_EXPR
> +                         || code == PREINCREMENT_EXPR);
> +  const enum tree_code inc_dec_code = is_inc_op ? PLUS_EXPR : MINUS_EXPR;
> +  tree val, val_init_expr, inc_dec_expr, mod_expr;
> +  val = upc_copy_value_to_tmp_var (&val_init_expr, op0);
> +  inc_dec_expr = build_binary_op (loc, inc_dec_code,
> +				  val, integer_one_node, 0);
> +  mod_expr = build2 (MODIFY_EXPR, TREE_TYPE (val), op0, inc_dec_expr);
> +  if (want_value)
> +    {
> +      if (code == PREDECREMENT_EXPR || code == PREINCREMENT_EXPR)
> +	upc_genericize_modify_expr (loc, &mod_expr, 1);
> +      else
> +	{
> +	  upc_genericize_modify_expr (loc, &mod_expr, 0);
> +	  mod_expr = build2 (COMPOUND_EXPR, TREE_TYPE (val), mod_expr, val);
> +	}
> +    }
> +  else
> +    upc_genericize_modify_expr (loc, &mod_expr, 0);
> +  *expr_p = build2 (COMPOUND_EXPR, TREE_TYPE (mod_expr),
> +		    val_init_expr, mod_expr);
> +}
> +
> +/* Simplify assignments to generic pointer-to-shared objects,
> +   where an intermediate conversion appears on the right hand
> +   side of the assignment.  Conversions from non-generic
> +   pointer-to-shared to generic pointer-to-shared are preserved
> +   up to the point of the final assignment, because a conversion
> +   from generic pointer-to-shared to non-generic pointer-to-shared
> +   may reset the phase in some cases, and we can only determine
> +   that the conversion is unnecessary when we know the target
> +   of the assignment expression.  */
> +
> +static void
> +upc_strip_useless_generic_pts_cvt (tree *expr_p)
> +{
> +  while (TREE_CODE (*expr_p) == CONVERT_EXPR
> +	 && POINTER_TYPE_P (TREE_TYPE (*expr_p))
> +	 && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (*expr_p))))
> +    {
> +      *expr_p = TREE_OPERAND (*expr_p, 0);
> +    }
> +}
> +
> +/* Generify the MODIFY_EXPR node of the 'shared' value
> +   pointed to by EXPR_P.  If the target of the assignment
> +   is a UPC 'shared' reference, or an indirection via a UPC
> +   pointer-to-shared, the assignment statement is rewritten into
> +   a call to a runtime routine that does a remote 'put'. 
> +   If WANT_VALUE is set, then return a compound expression
> +   that evaluates to the value of the source operand.  */
> +
> +static void
> +upc_genericize_modify_expr (location_t loc, tree *expr_p, int want_value)
> +{
> +  const tree dest = TREE_OPERAND (*expr_p, 0);
> +  tree src = TREE_OPERAND (*expr_p, 1);
> +  if (TREE_SHARED (dest)
> +      || (TREE_TYPE (dest) && SHARED_TYPE_P (TREE_TYPE (dest))))
> +    {
> +      /* <shared dest> = <(shared|unshared) src> */
> +      *expr_p = upc_expand_put (loc, dest, src, want_value);
> +    }
> +  else if (TREE_SHARED (src)
> +	   || (TREE_TYPE (src) && SHARED_TYPE_P (TREE_TYPE (src))))
> +    {
> +      /* <unshared dest> = <shared src> */
> +      /* We could check for BLKmode and in
> +         that case perform a upc_memget() here.  */
> +      src = upc_expand_get (loc, src, want_value);
> +      TREE_OPERAND (*expr_p, 1) = src;
> +    }
> +}
> +
> +typedef struct walk_data_struct
> +{
> +  int want_value;
> +} walk_data_t;
> +typedef walk_data_t *walk_data_p;
> +
> +/* This routine is called to convert UPC specific constructs
> +   into GENERIC.  It is called from 'walk_tree' as it traverses
> +   the function body.
> +   
> +   The DATA parameter will point to a 'walk_data_t'
> +   structure, which presently has a single field,
> +   'want_value'.  If 'want_value' is non-zero, it
> +   indicates that the value of the expression should
> +   be returned.  */
> +
> +static tree
> +upc_genericize_expr (tree *expr_p, int *walk_subtrees, void *data)
> +{
> +  const walk_data_p wdata = (walk_data_p) data;
> +  const tree expr = *expr_p;
> +  const enum tree_code code = TREE_CODE (expr);
> +  const tree type = CODE_CONTAINS_STRUCT (code, TS_TYPED)
> +                    ? TREE_TYPE (expr) : NULL;
> +  const int want_value = wdata->want_value
> +                         && !(type && VOID_TYPE_P (type));
> +  const tree op0 = (TREE_CODE_LENGTH (code) >= 1)
> +                   ? TREE_OPERAND (expr, 0) : NULL_TREE;
> +  const tree type0 = (op0 != NULL_TREE) ? TREE_TYPE (op0) : NULL_TREE;
> +  tree op1 = (TREE_CODE_LENGTH (code) >= 2)
> +             ? TREE_OPERAND (expr, 1) : NULL_TREE;
> +  tree type1 = (op1 != NULL_TREE) ? TREE_TYPE (op1) : NULL_TREE;
> +  location_t saved_location = input_location;
> +  location_t loc;
> +  if (EXPR_HAS_LOCATION (expr))
> +    input_location = EXPR_LOCATION (expr);
> +  loc = input_location;
> +  switch (code)
> +    {
> +    case UPC_FORALL_STMT:
> +      upc_genericize_forall_stmt (expr_p);
> +      break;
> +
> +    case UPC_SYNC_STMT:
> +      upc_genericize_sync_stmt (loc, expr_p);
> +      break;
> +
> +    case ADDR_EXPR:
> +      if (POINTER_TYPE_P (type) && TREE_TYPE (type)
> +	  && SHARED_TYPE_P (TREE_TYPE (type)))
> +	upc_genericize_addr_expr (loc, expr_p);
> +      break;
> +
> +    case ARRAY_REF:
> +    case ARRAY_RANGE_REF:
> +      if (op0 && TREE_SHARED (op0))
> +	upc_genericize_array_ref (loc, expr_p);
> +      break;
> +
> +    case BIT_FIELD_REF:
> +    case COMPONENT_REF:
> +      if (op0 && TREE_SHARED (op0))
> +	upc_genericize_field_ref (loc, expr_p);
> +      break;
> +
> +    case INDIRECT_REF:
> +      if (type0 && (TREE_CODE (type0) == POINTER_TYPE)
> +	  && SHARED_TYPE_P (TREE_TYPE (type0)))
> +	upc_genericize_indirect_ref (loc, expr_p);
> +      break;
> +
> +    case REALPART_EXPR:
> +    case IMAGPART_EXPR:
> +      if (op0 && TREE_SHARED (op0))
> +	upc_genericize_real_imag_ref (loc, expr_p);
> +      break;
> +
> +    case VAR_DECL:
> +      if (type && SHARED_TYPE_P (type))
> +	upc_genericize_shared_var_ref (loc, expr_p);
> +      break;
> +
> +    case VIEW_CONVERT_EXPR:
> +      if (type && SHARED_TYPE_P (type))
> +	TREE_TYPE (expr) = build_unshared_type (type);
> +      gcc_assert (!TREE_SHARED (expr));
> +      break;
> +
> +    case NON_LVALUE_EXPR:
> +    case NOP_EXPR:
> +    case CONVERT_EXPR:
> +      /* Conversions to a UPC shared type aren't valid.
> +         The front-end will sometimes convert
> +         an expression operand to the type of another
> +         operand.  If that operand has UPC shared type,
> +         then the conversion target type is 'shared' qualified.
> +         We unshare the type in order to produce a
> +         valid tree.  */
> +      if (type && SHARED_TYPE_P (type))
> +	TREE_TYPE (expr) = build_unshared_type (type);
> +      if (PTS_CVT_OP_P (expr))
> +	upc_genericize_pts_cvt (loc, expr_p);
> +      else if (code == CONVERT_EXPR && TREE_CODE (type) == INTEGER_TYPE
> +	       && POINTER_TYPE_P (type0)
> +	       && SHARED_TYPE_P (TREE_TYPE (type0)))
> +	upc_genericize_pts_to_int_cvt (loc, expr_p);
> +      break;
> +
> +    case EQ_EXPR:
> +    case GE_EXPR:
> +    case GT_EXPR:
> +    case LE_EXPR:
> +    case LT_EXPR:
> +    case NE_EXPR:
> +      if ((type0 && (TREE_CODE (type0) == POINTER_TYPE)
> +	   && SHARED_TYPE_P (TREE_TYPE (type0)))
> +	  || (type1 && (TREE_CODE (type1) == POINTER_TYPE)
> +	      && SHARED_TYPE_P (TREE_TYPE (type1))))
> +	upc_genericize_pts_cond_expr (loc, expr_p);
> +      break;
> +
> +    case MINUS_EXPR:
> +    case PLUS_EXPR:
> +    case POINTER_PLUS_EXPR:
> +      if ((type0 && (TREE_CODE (type0) == POINTER_TYPE)
> +	   && SHARED_TYPE_P (TREE_TYPE (type0)))
> +	  || (type1 && (TREE_CODE (type1) == POINTER_TYPE)
> +	      && SHARED_TYPE_P (TREE_TYPE (type1))))
> +	upc_genericize_pts_arith_expr (loc, expr_p);
> +      break;
> +
> +    case MODIFY_EXPR:
> +    case INIT_EXPR:
> +      if (POINTER_TYPE_P (type0) && SHARED_TYPE_P (TREE_TYPE (type0))
> +	  && VOID_TYPE_P (TREE_TYPE (type0))
> +	  && TREE_CODE (op1) == CONVERT_EXPR
> +	  && POINTER_TYPE_P (type1) && VOID_TYPE_P (TREE_TYPE (type1)))
> +	{
> +	  upc_strip_useless_generic_pts_cvt (&TREE_OPERAND (expr, 1));
> +	  /* Recalculate OP1 and TYPE1 because TREE_OPERAND (expr, 1)
> +	     was rewritten, above.  */
> +	  op1 = TREE_OPERAND (expr, 1);
> +	  type1 = TREE_TYPE (op1);
> +	}
> +      if ((op0 && (TREE_SHARED (op0)
> +		   || (type0 && SHARED_TYPE_P (type0))))
> +	  || (op1 && (TREE_SHARED (op1)
> +		      || (type1 && SHARED_TYPE_P (type1)))))
> +	upc_genericize_modify_expr (loc, expr_p, want_value);
> +      break;
> +
> +    case POSTDECREMENT_EXPR:
> +    case POSTINCREMENT_EXPR:
> +    case PREDECREMENT_EXPR:
> +    case PREINCREMENT_EXPR:
> +      if ((op0 && TREE_SHARED (op0))
> +	  || (type0 && (SHARED_TYPE_P (type0)
> +			|| (POINTER_TYPE_P (type0)
> +			    && SHARED_TYPE_P (TREE_TYPE (type0))))))
> +	upc_genericize_shared_inc_dec_expr (loc, expr_p, want_value);
> +      break;
> +
> +    case INTEGER_CST:
> +      /* Integer constants can't be UPC 'shared' qualified.
> +         The front-end can create integer constants with shared
> +         type when changing the type to agree with that of another
> +         expression operand.
> +
> +         Unsharing an integer constant requires special handling
> +         because an internal hash table is kept on a type by type
> +         basis.  Thus, we can't rewrite TREE_TYPE() directly.
> +         We re-create the constant with its unshared type to
> +         ensure that the hash table is updated.  */
> +      if (type && SHARED_TYPE_P (type))
> +	{
> +	  const tree u_type = build_unshared_type (type);
> +	  *expr_p = wide_int_to_tree (u_type, expr);
> +	}
> +      gcc_assert (!TREE_SHARED (expr));
> +      break;
> +
> +    case REAL_CST:
> +    case COMPLEX_CST:
> +    case STRING_CST:
> +    case VECTOR_CST:
> +    case CONSTRUCTOR:
> +      /* A constant's type can't be UPC 'shared' qualified.
> +         The front-end will sometimes convert
> +         an expression operand to the type of another
> +         operand.  If that other operand has UPC shared type,
> +         then the converted constant's type will be shared.
> +         We unshare the type in order to produce a
> +         valid constant.  */
> +      if (type && SHARED_TYPE_P (type))
> +	TREE_TYPE (expr) = build_unshared_type (type);
> +      gcc_assert (!TREE_SHARED (expr));
> +      break;
> +
> +    case STATEMENT_LIST:
> +      upc_genericize_stmt_list (expr_p);
> +      *walk_subtrees = 0;
> +      break;
> +
> +    case COMPOUND_EXPR:
> +      upc_genericize_compound_expr (expr_p, want_value);
> +      *walk_subtrees = 0;
> +      break;
> +
> +    case COND_EXPR:
> +      upc_genericize_cond_expr (expr_p, want_value);
> +      *walk_subtrees = 0;
> +      break;
> +
> +    case DECL_EXPR:
> +      upc_genericize_decl_expr (expr_p);
> +      *walk_subtrees = 0;
> +      break;
> +
> +    default:
> +      gcc_assert (!TREE_SHARED (expr));
> +      break;
> +    }
> +
> +  /* Restore the input location.  */
> +  input_location = saved_location;
> +
> +  /* After evaluating the current node, assert the
> +     want_value flag so that all subtrees of this root node
> +     will be fully evaluated.  */
> +  if (!wdata->want_value)
> +    wdata->want_value = 1;
> +
> +  /* Continue tree traversal.  */
> +  return NULL_TREE;
> +}
> +
> +/* Convert a compound expression into GENERIC form.
> +   A compound expression contains two expressions to compute,
> +   one (the LHS) followed by the other (the RHS).
> +   The LHS value is ignored.  The RHS value is used.  */
> +
> +static void
> +upc_genericize_compound_expr (tree *expr_p, int want_value)
> +{
> +  tree *lhs_p = &TREE_OPERAND (*expr_p, 0);
> +  tree *rhs_p = &TREE_OPERAND (*expr_p, 1);
> +  upc_genericize_walk (lhs_p, 0);
> +  upc_genericize_walk (rhs_p, want_value);
> +}
> +
> +/* Convert a conditional expression into GENERIC form.
> +   A conditional expression contains three expressions
> +   and is of the form expression ( ... ? ... : ...  in C).
> +   The first operand is the condition, the second is
> +   the then-value and the third is the else-value.  */
> +
> +static void
> +upc_genericize_cond_expr (tree *expr_p, int want_value)
> +{
> +  tree *cond_p = &TREE_OPERAND (*expr_p, 0);
> +  tree *then_p = &TREE_OPERAND (*expr_p, 1);
> +  tree *else_p = &TREE_OPERAND (*expr_p, 2);
> +  upc_genericize_walk (cond_p, 1);
> +  if (*then_p)
> +    upc_genericize_walk (then_p, want_value);
> +  if (*else_p)
> +    upc_genericize_walk (else_p, want_value);
> +}
> +
> +/* Convert a declaration expression into GENERIC form.
> +   A declaration expression is used to represent a local declaration.
> +   The operand refers to the DECL associated with
> +   the given declaration statement.  */
> +
> +static void
> +upc_genericize_decl_expr (tree *expr_p)
> +{
> +  tree decl = DECL_EXPR_DECL (*expr_p);
> +  tree *decl_init_p = &DECL_INITIAL (decl);
> +  if (*decl_init_p)
> +    upc_genericize_walk (decl_init_p, 0);
> +}
> +
> +/* Convert the tree rooted at EXPR_P into GENERIC.
> +   WANT_VALUE is the initial value the flag that
> +   upc_genericize_expr() will query to determine
> +   whether the expression node should return a value.
> +   NOTE: EXPR_P can point to any kind of expression node.  */
> +
> +static void
> +upc_genericize_walk (tree *expr_p, int want_value)
> +{
> +  walk_data_t wdata;
> +  wdata.want_value = want_value;
> +  (void) walk_tree (expr_p, upc_genericize_expr, &wdata, NULL);
> +}
> +
> +/* Convert a statement list to GENERIC.  */
> +
> +static void
> +upc_genericize_stmt_list (tree *stmt_list_p)
> +{
> +  tree_stmt_iterator s = tsi_start (*stmt_list_p);
> +  while (!tsi_end_p (s))
> +    {
> +      tree *stmt_p = tsi_stmt_ptr (s);
> +      upc_genericize_walk (stmt_p, 0);
> +      tsi_next (&s);
> +    }
> +}
> +
> +/* Convert the function body identified by BODY_P into GENERIC.
> +   Traverse the function body by calling upc_genericize_walk().
> +   Initially assert WANT_VALUE as FALSE.  */
> +
> +static void
> +upc_genericize_body (tree *body_p, tree fndecl)
> +{
> +  location_t saved_location = input_location;
> +
> +  timevar_push (TV_TREE_UPC_GENERICIZE);
> +
> +  input_location = DECL_SOURCE_LOCATION (fndecl);
> +
> +  upc_genericize_walk (body_p, /* want_value */ 0);
> +
> +  timevar_pop (TV_TREE_UPC_GENERICIZE);
> +
> +  input_location = saved_location;
> +}
> +
> +/* Convert the tree representation of FNDECL, along with all nested
> +   functions defined within it, into the GENERIC form.  */
> +
> +static void
> +upc_genericize_function (tree fndecl)
> +{
> +  struct cgraph_node *cgn;
> +
> +  gcc_assert (DECL_SAVED_TREE (fndecl));
> +
> +  if (DECL_STRUCT_FUNCTION (fndecl))
> +    push_cfun (DECL_STRUCT_FUNCTION (fndecl));
> +  else
> +    push_struct_function (fndecl);
> +
> +  upc_genericize_body (&DECL_SAVED_TREE (fndecl), fndecl);
> +
> +  if (flag_upc_instrument_functions
> +      && !DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl)
> +      && !flag_instrument_functions_exclude_p (fndecl))
> +    {
> +      upc_instrument_func (fndecl);
> +    }
> +
> +  pop_cfun ();
> +
> +  cgn = cgraph_node::get_create (fndecl);
> +  for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
> +    upc_genericize_function (cgn->decl);
> +}
> +
> +/* If the accumulated UPC initialization statement list is
> +   not empty, then build (and define) the per-file UPC
> +   global initialization function.  */
> +
> +static void
> +upc_write_init_func (void)
> +{
> +  if (upc_init_stmt_list)
> +    {
> +      int pupc_mode = disable_pupc_mode ();
> +      lang_hooks.upc.build_init_func (upc_init_stmt_list);
> +      set_pupc_mode (pupc_mode);
> +      upc_init_stmt_list = NULL;
> +    }
> +}
> +
> +/* Convert the tree representation of FNDECL built by the UPC front-end
> +   into the GENERIC form.  Then call the "C" genericize hook.  */
> +
> +void
> +upc_genericize (tree fndecl)
> +{
> +  upc_genericize_function (fndecl);
> +}
> +
> +/* Return TRUE if either DECL's type is a UPC shared type, or if
> +   the value on the right-hand-side of the initialization has a
> +   type that is a UPC shared type.  Initializations that meet
> +   this criteria generally need to be actively initialized
> +   at runtime.  */
> +
> +int
> +upc_check_decl_init (tree decl, tree init)
> +{
> +  tree init_type;
> +  int is_shared_var_decl_init;
> +  int is_decl_init_with_shared_addr_refs;
> +  int is_upc_decl;
> +  if (!(decl && init && TREE_TYPE (decl) && TREE_TYPE (init)))
> +    return 0;
> +  if ((TREE_CODE (decl) == ERROR_MARK)
> +      || (TREE_CODE (TREE_TYPE (decl)) == ERROR_MARK)
> +      || (TREE_CODE (init) == ERROR_MARK)
> +      || (TREE_CODE (TREE_TYPE (init)) == ERROR_MARK))
> +    return 0;
> +  init_type = TREE_TYPE (init);
> +  is_shared_var_decl_init = (TREE_CODE (decl) == VAR_DECL)
> +    && TREE_TYPE (decl) && SHARED_TYPE_P (TREE_TYPE (decl));
> +  is_decl_init_with_shared_addr_refs = TREE_STATIC (decl)
> +    && upc_contains_pts_refs_p (init_type);
> +  is_upc_decl = (is_shared_var_decl_init
> +		 || is_decl_init_with_shared_addr_refs);
> +  return is_upc_decl;
> +}
> +
> +/* Add the initialization statement:
> +     DECL = INIT;
> +   onto a list, `upc_init_stmt_list', which collects
> +   initializations that must be made at runtime.
> +
> +   This runtime initialization necessary because, in general, UPC
> +   shared addresses are not known, or cannot be easily generated
> +   at compile-time.  */
> +
> +void
> +upc_decl_init (tree decl, tree init)
> +{
> +  tree init_stmt;
> +  if (TREE_CODE (init) == ERROR_MARK)
> +    return;
> +  if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
> +    {
> +      error ("initialization of UPC shared arrays "
> +	     "is currently not supported");
> +      return;
> +    }
> +  if (!upc_init_stmt_list)
> +    upc_init_stmt_list = alloc_stmt_list ();
> +  init_stmt = build2 (INIT_EXPR, void_type_node, decl, init);
> +  append_to_statement_list_force (init_stmt, &upc_init_stmt_list);
> +}
> +
> +/* Write out the UPC global initialization function, if required
> +   and call upc_genericize_finish() to free the hash table
> +   used to track the "shadow" variables that are created
> +   to generate addresses of UPC shared variables.
> +
> +   This function is called from c_common_parse_file(), just after
> +   parsing the main source file.  */
> +
> +void
> +upc_write_global_declarations (void)
> +{
> +  upc_write_init_func ();
> +  upc_genericize_finish ();
> +}
> +
> +/* Clean up resources used by the UPC genericize pass.  */
> +
> +void
> +upc_genericize_finish (void)
> +{
> +  upc_free_unshared_var_table ();
> +  upc_init_stmt_list = NULL;
> +}
> +
> +/* Initialize/allocate resources used by the UPC genericize pass.  */
> +
> +void
> +upc_genericize_init (void)
> +{
> +  unshared_vars_map = new int_tree_htab_type (10);
> +  upc_init_stmt_list = NULL;
> +}
> +
> +#include "gt-c-c-upc-low.h"
> Index: gcc/c/c-upc-low.h
> ===================================================================
> --- gcc/c/c-upc-low.h	(.../trunk)	(revision 0)
> +++ gcc/c/c-upc-low.h	(.../branches/gupc)	(revision 231080)
> @@ -0,0 +1,33 @@
> +/* c-upc-low.h: declarations for upc-low.c
> +   Copyright (C) 2006-2015 Free Software Foundation, Inc.
> +   Contributed by Gary Funck <gary@intrepid.com>
> +     and Nenad Vukicevic <nenad@intrepid.com>.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify
> +it under the terms of the GNU General Public License as published by
> +the Free Software Foundation; either version 3, or (at your option)
> +any later version.
> +
> +GCC is distributed in the hope that it will be useful,
> +but WITHOUT ANY WARRANTY; without even the implied warranty of
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +GNU General Public License for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#ifndef GCC_C_UPC_LOW_H
> +#define GCC_C_UPC_LOW_H 1
> +
> +extern void upc_genericize (tree);
> +extern void upc_genericize_init (void);
> +extern void upc_genericize_finish (void);
> +
> +extern int upc_check_decl_init (tree, tree);
> +extern void upc_decl_init (tree, tree);
> +extern void upc_write_global_declarations (void);
> +
> +#endif /* !GCC_C_UPC_LOW_H */
> Index: gcc/c/c-upc-pts-ops.c
> ===================================================================
> --- gcc/c/c-upc-pts-ops.c	(.../trunk)	(revision 0)
> +++ gcc/c/c-upc-pts-ops.c	(.../branches/gupc)	(revision 231080)
> @@ -0,0 +1,585 @@
> +/* c-upc-pts-ops.c: implement UPC pointer-to-shared-operations.
> +   Copyright (C) 2001-2015 Free Software Foundation, Inc.
> +   Contributed by Gary Funck <gary@intrepid.com>
> +     and Nenad Vukicevic <nenad@intrepid.com>.
> +   Based on original implementation
> +     by Jesse M. Draper <jdraper@super.org>
> +     and William W. Carlson <wwc@super.org>.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify
> +it under the terms of the GNU General Public License as published by
> +the Free Software Foundation; either version 3, or (at your option)
> +any later version.
> +
> +GCC is distributed in the hope that it will be useful,
> +but WITHOUT ANY WARRANTY; without even the implied warranty of
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +GNU General Public License for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "tm.h"
> +#include "tree.h"
> +#include "alias.h"
> +#include "fold-const.h"
> +#include "stringpool.h"
> +#include "c-tree.h"
> +#include "langhooks.h"
> +#include "gimplify.h"
> +#include "c-upc.h"
> +#include "c-upc-gasp.h"
> +#include "c-upc-pts-ops.h"
> +#include "c-upc-rts-names.h"
> +
> +/* Build the internal representation of UPC's pointer-to-shared type.  */
> +
> +void
> +upc_pts_init (void)
> +{
> +  tree shared_void_type, shared_char_type;
> +  lang_hooks.upc.pts_init_type ();
> +  shared_void_type = c_build_qualified_type_1 (void_type_node,
> +                                               TYPE_QUAL_SHARED,
> +					       NULL_TREE);
> +  upc_pts_type_node = build_pointer_type (shared_void_type);
> +  shared_char_type = c_build_qualified_type_1 (char_type_node,
> +                                               TYPE_QUAL_SHARED,
> +					       size_zero_node);
> +  upc_char_pts_type_node = build_pointer_type (shared_char_type);
> +  upc_null_pts_node = upc_pts_build_value (UNKNOWN_LOCATION,
> +                                                  upc_pts_type_node,
> +				                  integer_zero_node,
> +						  integer_zero_node,
> +				                  integer_zero_node);
> +}
> +
> +/* Called to expand a UPC specific constant into something the
> +   backend can handle.  Upon return a UPC pointer-to-shared will be
> +   seen as the representation type of a UPC pointer-to-shared, with
> +   individual (thread, phase, and virtual address) fields.  */
> +
> +tree
> +upc_pts_build_constant (location_t loc, tree c)
> +{
> +  tree result = c;
> +  if (upc_pts_is_valid_p (c))
> +    {
> +      const enum tree_code code = TREE_CODE (c);
> +      if (!((code == VIEW_CONVERT_EXPR || code == NOP_EXPR)
> +	    && (TREE_CODE (TREE_OPERAND (c, 0)) == CONSTRUCTOR)
> +	    && (TREE_TYPE (TREE_OPERAND (c, 0)) == upc_pts_rep_type_node)))
> +	{
> +	  const tree val = build1 (VIEW_CONVERT_EXPR, upc_pts_rep_type_node,
> +				   save_expr (c));
> +	  const tree p_t = TREE_TYPE (upc_phase_field_node);
> +	  const tree t_t = TREE_TYPE (upc_thread_field_node);
> +	  const tree v_t = TREE_TYPE (upc_vaddr_field_node);
> +	  const tree vaddr = build3 (COMPONENT_REF, v_t, val,
> +				     upc_vaddr_field_node, NULL_TREE);
> +	  const tree thread = build3 (COMPONENT_REF, t_t, val,
> +				      upc_thread_field_node, NULL_TREE);
> +	  const tree phase = build3 (COMPONENT_REF, p_t, val,
> +				     upc_phase_field_node, NULL_TREE);
> +	  result = upc_pts_build_value (loc, TREE_TYPE (c),
> +					       vaddr, thread, phase);
> +
> +	}
> +    }
> +  return result;
> +}
> +
> +/* Build a constructor of the form {phase, thread, vaddr}.  */
> +
> +tree
> +upc_pts_build_value (location_t loc ATTRIBUTE_UNUSED, tree type,
> +		     tree vaddr, tree thread, tree phase)
> +{
> +  tree elts, result;
> +  const int is_const = TREE_CONSTANT (vaddr)
> +    && TREE_CONSTANT (thread) && TREE_CONSTANT (phase);
> +  vaddr = fold_convert (TREE_TYPE (upc_vaddr_field_node), vaddr);
> +  thread = fold_convert (TREE_TYPE (upc_thread_field_node), thread);
> +  phase = fold_convert (TREE_TYPE (upc_phase_field_node), phase);
> +  elts = tree_cons (upc_phase_field_node, phase, NULL_TREE);
> +  elts = tree_cons (upc_thread_field_node, thread, elts);
> +  elts = tree_cons (upc_vaddr_field_node, vaddr, elts);
> +  result = build_constructor_from_list (upc_pts_rep_type_node, elts);
> +  TREE_CONSTANT (result) = is_const;
> +
> +  /* Wrap the constructor into the specified pointer to shared type.  */
> +  result = build1 (VIEW_CONVERT_EXPR, type, result);
> +  result = fold (result);
> +  TREE_CONSTANT (result) = is_const;
> +  /* Force all shared constant pointer values to memory.  */
> +  TREE_STATIC (result) = is_const;
> +  return result;
> +}
> +
> +/* Return TRUE if EXP is a null UPC pointer-to-shared.  */
> +
> +int
> +upc_pts_is_null_p (tree exp)
> +{
> +  int result = 0;
> +  if (exp && upc_pts_is_valid_p (exp))
> +    {
> +      tree value;
> +      for (value = exp;
> +	   TREE_CODE (value) == NOP_EXPR
> +	   || TREE_CODE (value) == CONVERT_EXPR
> +	   || TREE_CODE (value) == VIEW_CONVERT_EXPR
> +	   || TREE_CODE (value) == NON_LVALUE_EXPR;
> +	   value = TREE_OPERAND (value, 0)) /* loop */ ;
> +      if ((TREE_CODE (value) == CONSTRUCTOR)
> +	  && (TREE_TYPE (value) == upc_pts_rep_type_node)
> +	  && TREE_CONSTANT (value))
> +	{
> +	  vec<constructor_elt, va_gc> *c = CONSTRUCTOR_ELTS (value);
> +	  /* Check that all the fields are zero, independent
> +	     of whether vaddr comes first/last.  */
> +	  const tree phase_or_vaddr = (*c)[0].value;
> +	  const tree thread = (*c)[1].value;
> +	  const tree vaddr_or_phase = (*c)[2].value;
> +	  result = integer_zerop (phase_or_vaddr) && integer_zerop (thread)
> +	           && integer_zerop (vaddr_or_phase);
> +	}
> +    }
> +  return result;
> +}
> +
> +/* Given, EXP, whose type must be the UPC pointer-to-shared
> +   representation type, isolate the thread field,
> +   and return it.  Caller must insure that EXP is a
> +   stable reference, if required.  */
> +
> +tree
> +upc_pts_build_threadof (location_t loc ATTRIBUTE_UNUSED, tree exp)
> +{
> +  tree affinity;
> +  tree type = TREE_TYPE (upc_thread_field_node);
> +  gcc_assert (TREE_TYPE (exp) == upc_pts_rep_type_node);
> +  affinity = build3 (COMPONENT_REF, type, exp,
> +		     upc_thread_field_node, NULL_TREE);
> +  affinity = fold_convert (sizetype, affinity);
> +  return affinity;
> +}
> +
> +/* Rewrite EXP, an expression involving addition of an
> +   integer to a UPC pointer-to-shared, into representation-specific
> +   lower level operations.  */
> +
> +tree
> +upc_pts_build_sum (location_t loc, tree exp)
> +{
> +  const tree op0 = TREE_OPERAND (exp, 0);
> +  const tree op1 = TREE_OPERAND (exp, 1);
> +  const enum tree_code op0_code = TREE_CODE (TREE_TYPE (op0));
> +  const tree targ_type = TREE_TYPE (TREE_TYPE (exp));
> +  const tree elem_type = strip_array_types (targ_type);
> +  const tree elem_size = !VOID_TYPE_P (elem_type)
> +    ? size_in_bytes (elem_type) : integer_one_node;
> +  const tree block_factor = get_block_factor (elem_type);
> +  const int has_phase = !(integer_zerop (block_factor)
> +			  || integer_onep (block_factor));
> +  const tree elem_per_block = block_factor;
> +  const tree ptrop = (op0_code == POINTER_TYPE) ? op0 : op1;
> +  const tree intop = (op0_code == POINTER_TYPE) ? op1 : op0;
> +  const tree index = save_expr (intop);
> +  const tree ptrop_as_pts_rep = fold (build1 (VIEW_CONVERT_EXPR,
> +					      upc_pts_rep_type_node,
> +					      ptrop));
> +  const tree sptrop = save_expr (ptrop_as_pts_rep);
> +  const tree p_t = TREE_TYPE (upc_phase_field_node);
> +  const tree t_t = TREE_TYPE (upc_thread_field_node);
> +  const tree v_t = TREE_TYPE (upc_vaddr_field_node);
> +  tree n_threads = upc_num_threads ();
> +  tree old_phase, old_thread, old_vaddr;
> +  tree phase, thread, vaddr;
> +  tree tincr, t1, t2;
> +  tree result;
> +
> +  old_phase = build3 (COMPONENT_REF, p_t, sptrop,
> +		      upc_phase_field_node, NULL_TREE);
> +  old_thread = build3 (COMPONENT_REF, t_t, sptrop,
> +		       upc_thread_field_node, NULL_TREE);
> +  old_vaddr = build3 (COMPONENT_REF, v_t, sptrop,
> +		      upc_vaddr_field_node, NULL_TREE);
> +  thread = old_thread;
> +  phase = old_phase;
> +  if (VOID_TYPE_P (targ_type) || integer_zerop (block_factor))
> +    {
> +      vaddr = build_binary_op (loc, PLUS_EXPR, old_vaddr,
> +			       build_binary_op (loc, MULT_EXPR,
> +						index, elem_size, 0), 0);
> +    }
> +  else
> +    {
> +      /* Make sure n_threads is a signed integer to ensure
> +         that the FLOOR_MOD and FLOOR_DIV operations below are performed
> +         with signed operations.  */
> +      if (TYPE_UNSIGNED (TREE_TYPE (n_threads)))
> +	n_threads = convert (integer_type_node, n_threads);
> +      if (has_phase)
> +	{
> +	  tree nt_elems;
> +	  tree phase_diff;
> +	  old_phase = save_expr (old_phase);
> +	  /* tincr = old_thread * elem_per_block + old_phase + index; */
> +	  tincr = build_binary_op (loc, PLUS_EXPR,
> +		      build_binary_op (loc, PLUS_EXPR,
> +		          build_binary_op (loc, MULT_EXPR,
> +				           old_thread, elem_per_block, 0),
> +			  old_phase, 0),
> +		      index, 0);
> +	  if (TYPE_UNSIGNED (TREE_TYPE (tincr)))
> +	    tincr = convert (integer_type_node, tincr);
> +	  /* nt_elems = n_threads * elem_per_block; */
> +	  nt_elems = build_binary_op (loc, MULT_EXPR, n_threads,
> +				      elem_per_block, 0);
> +	  if (TYPE_UNSIGNED (TREE_TYPE (nt_elems)))
> +	    nt_elems = convert (integer_type_node, nt_elems);
> +	  /* floor_divmod (tincr, nt_elems, &t1, &t2);  */
> +	  t1 = build_binary_op (loc, FLOOR_DIV_EXPR, tincr, nt_elems, 0);
> +	  t2 = build_binary_op (loc, FLOOR_MOD_EXPR, tincr, nt_elems, 0);
> +	  t2 = save_expr (t2);
> +	  /* thread = t2 / elem_per_block; */
> +	  thread = build_binary_op (loc, TRUNC_DIV_EXPR, t2,
> +				    elem_per_block, 0);
> +	  /* phase = t2 % elem_per_block; */
> +	  phase = build_binary_op (loc, TRUNC_MOD_EXPR, t2,
> +				   elem_per_block, 0);
> +	  phase_diff =
> +	    build_binary_op (loc, MINUS_EXPR, phase, old_phase, 0);
> +	  /* vaddr = old_vaddr + (t1 * elem_per_block + phase_diff)
> +				 * elem_size; */
> +	  vaddr = build_binary_op (loc, PLUS_EXPR,
> +				   old_vaddr,
> +				   build_binary_op (loc, MULT_EXPR,
> +				       build_binary_op (loc, PLUS_EXPR,
> +				           build_binary_op (loc, MULT_EXPR,
> +						     t1, elem_per_block, 0),
> +					   phase_diff, 0),
> +				       elem_size, 0), 0);
> +	}
> +      else
> +	{
> +	  /* tincr = old_thread * elem_per_block + index; */
> +	  tincr = build_binary_op (loc, PLUS_EXPR,
> +				   build_binary_op (loc, MULT_EXPR,
> +						    old_thread,
> +						    elem_per_block, 0),
> +				   index, 0);
> +	  if (TYPE_UNSIGNED (TREE_TYPE (tincr)))
> +	    tincr = convert (integer_type_node, tincr);
> +	  /* floor_divmod (tincr, n_threads, &t1, &t2);  */
> +	  t1 = build_binary_op (loc, FLOOR_DIV_EXPR, tincr, n_threads, 0);
> +	  t2 = build_binary_op (loc, FLOOR_MOD_EXPR, tincr, n_threads, 0);
> +	  /* vaddr = old_vaddr + t1 * elem_size; */
> +	  vaddr = build_binary_op (loc, PLUS_EXPR, old_vaddr,
> +				   build_binary_op (loc, MULT_EXPR, t1,
> +						    elem_size, 0), 0);
> +	  /* thread = t2;  */
> +	  thread = t2;
> +	}
> +    }
> +  result =
> +    upc_pts_build_value (loc, TREE_TYPE (exp), vaddr, thread, phase);
> +  return result;
> +}
> +
> +/* Expand the expression EXP, which calculates the difference
> +   between two UPC pointers-to-shared.  */
> +
> +tree
> +upc_pts_build_diff (location_t loc, tree exp)
> +{
> +  tree op0 = TREE_OPERAND (exp, 0);
> +  tree op1 = TREE_OPERAND (exp, 1);
> +  const tree result_type = ptrdiff_type_node;
> +  const tree p_t = TREE_TYPE (upc_phase_field_node);
> +  const tree t_t = TREE_TYPE (upc_thread_field_node);
> +  const tree v_t = TREE_TYPE (upc_vaddr_field_node);
> +  const tree target_type = TREE_TYPE (TREE_TYPE (op0));
> +  const tree n_threads = upc_num_threads ();
> +  const tree elem_size = convert (ssizetype, size_in_bytes (target_type));
> +  const tree block_factor = get_block_factor (target_type);
> +  tree thread0, thread1, thread_diff;
> +  tree phase_diff;
> +  tree off0, off1, offset_diff, elem_diff;
> +  tree result;
> +
> +  /* The two pointers must both point to shared objects, and we
> +     have to perform the reverse of addition on UPC pointers-to-shared */
> +
> +  if ((SHARED_TYPE_P (target_type)
> +       && !SHARED_TYPE_P (TREE_TYPE (TREE_TYPE (op1))))
> +      || (SHARED_TYPE_P (TREE_TYPE (TREE_TYPE (op1)))
> +	  && !SHARED_TYPE_P (target_type)))
> +    {
> +      error ("attempt to take the difference of a UPC pointer-to-shared "
> +	 "and a local pointer");
> +      return error_mark_node;
> +    }
> +  op0 = save_expr (op0);
> +  op1 = save_expr (op1);
> +  op0 = build1 (VIEW_CONVERT_EXPR, upc_pts_rep_type_node, op0);
> +  op1 = build1 (VIEW_CONVERT_EXPR, upc_pts_rep_type_node, op1);
> +  off0 = build3 (COMPONENT_REF, v_t, op0, upc_vaddr_field_node, NULL_TREE);
> +  off1 = build3 (COMPONENT_REF, v_t, op1, upc_vaddr_field_node, NULL_TREE);
> +  /* Convert offset fields into ptrdiff_t types so that the
> +     result of the difference comes out as a signed type.  */
> +  off0 = convert (result_type, off0);
> +  off1 = convert (result_type, off1);
> +  offset_diff = build_binary_op (loc, MINUS_EXPR, off0, off1, 0);
> +  elem_diff =
> +    build_binary_op (loc, EXACT_DIV_EXPR, offset_diff, elem_size, 0);
> +  if (integer_zerop (block_factor))
> +    {
> +      return elem_diff;
> +    }
> +  thread0 = convert (ssizetype,
> +		     build3 (COMPONENT_REF, t_t, op0,
> +			     upc_thread_field_node, NULL_TREE));
> +  thread1 = convert (ssizetype,
> +		     build3 (COMPONENT_REF, t_t, op1,
> +			     upc_thread_field_node, NULL_TREE));
> +  thread_diff = build_binary_op (loc, MINUS_EXPR, thread0, thread1, 0);
> +  phase_diff = integer_zero_node;
> +  if (!tree_int_cst_equal (block_factor, integer_one_node))
> +    {
> +      tree phase0 = convert (ssizetype,
> +			     build3 (COMPONENT_REF, p_t, op0,
> +				     upc_phase_field_node, NULL_TREE));
> +      tree phase1 = convert (ssizetype,
> +			     build3 (COMPONENT_REF, p_t, op1,
> +				     upc_phase_field_node, NULL_TREE));
> +      phase_diff =
> +	save_expr (build_binary_op (loc, MINUS_EXPR, phase0, phase1, 0));
> +    }
> +  /* The expression below calculates the following:
> +     (elem_diff - phase_diff) * THREADS
> +     + (thread_diff * block_factor) + phase_diff; */
> +  result = build_binary_op (loc, PLUS_EXPR,
> +			    build_binary_op (loc, PLUS_EXPR,
> +			        build_binary_op (loc, MULT_EXPR,
> +				    build_binary_op (loc, MINUS_EXPR,
> +					           elem_diff, phase_diff, 0),
> +				    n_threads, 0),
> +			        build_binary_op (loc, MULT_EXPR,
> +						 thread_diff,
> +						 block_factor, 0), 0),
> +			    phase_diff, 0);
> +  result = fold_convert (result_type, result);
> +  return result;
> +}
> +
> +/* Handle conversions between UPC pointers-to-shared and
> +   local pointers, or between UPC pointers-to-shared which
> +   have differing block factors.  */
> +
> +tree
> +upc_pts_build_cvt (location_t loc, tree exp)
> +{
> +  const tree type = TREE_TYPE (exp);
> +  const tree p_t = ptr_type_node;
> +  const tree t_t = TREE_TYPE (upc_thread_field_node);
> +  const tree ptr = TREE_OPERAND (exp, 0);
> +  tree tt1, tt2, b1, b2;
> +  tree result = exp;
> +
> +  tt1 = TREE_TYPE (TREE_TYPE (exp));
> +  tt2 = TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)));
> +  b1 = get_block_factor (tt1);
> +  b2 = get_block_factor (tt2);
> +  if (SHARED_TYPE_P (tt1) != SHARED_TYPE_P (tt2))
> +    {
> +      if (SHARED_TYPE_P (tt1))
> +	{
> +	  /* Error: local -> shared */
> +	  result = error_mark_node;
> +	}
> +      else
> +	{
> +	  /* shared -> local */
> +          int doprofcall = flag_upc_debug
> +                           || (flag_upc_instrument && get_upc_pupc_mode ());
> +	  const char *libfunc_name =
> +	    doprofcall ? UPC_GETADDRG_LIBCALL : UPC_GETADDR_LIBCALL;
> +	  tree src = build1 (NOP_EXPR, upc_pts_rep_type_node,
> +			     TREE_OPERAND (exp, 0));
> +	  tree libfunc, lib_args, lib_call;
> +	  libfunc = identifier_global_value (get_identifier (libfunc_name));
> +	  if (!libfunc)
> +	    internal_error ("UPC runtime library function %s not found",
> +			    libfunc_name);
> +	  lib_args = tree_cons (NULL_TREE, src, NULL_TREE);
> +	  if (doprofcall)
> +	    lib_args =
> +	      upc_gasp_add_src_args (lib_args,
> +	                             LOCATION_FILE (input_location),
> +				     LOCATION_LINE (input_location));
> +	  lib_call = build_function_call (loc, libfunc, lib_args);
> +	  result = build1 (VIEW_CONVERT_EXPR, type, lib_call);
> +	}
> +    }
> +  else if ((SHARED_TYPE_P (tt1) && !VOID_TYPE_P (tt1))
> +	   && !(integer_zerop (b1) && integer_zerop (b2)))
> +    {
> +      /* below, we handle the case of conversions to non-generic
> +         shared types.  If the target is a generic type, we can
> +         safely use the source value directly.  */
> +      tree s1 = TYPE_SIZE (tt1);
> +      tree s2 = TYPE_SIZE (tt2);
> +      /* normalize block sizes, so that [0] => NULL */
> +      if (integer_zerop (b1))
> +	b1 = NULL;
> +      if (integer_zerop (b2))
> +	b2 = NULL;
> +      /* normalize type size so that 0 => NULL */
> +      if (s1 && integer_zerop (s1))
> +	s1 = NULL;
> +      if (s2 && integer_zerop (s2))
> +	s2 = NULL;
> +      /* If the source type is an array type, then bypass
> +         the check for equal type sizes.  This arises when
> +	 an array is implicitly converted to a pointer to
> +	 the element type.  */
> +      if ((TREE_CODE (tt1) != ARRAY_TYPE)
> +          && (TREE_CODE (tt2) == ARRAY_TYPE))
> +        {
> +          const tree elem_type1 = strip_array_types (tt1);
> +          const tree elem_type2 = strip_array_types (tt2);
> +	  if (TYPE_MAIN_VARIANT (elem_type1)
> +	      == TYPE_MAIN_VARIANT (elem_type2))
> +	    s2 = s1;
> +        }
> +      /* If the source type is a not a generic pointer to shared, and
> +         either its block size or type size differs from the target,
> +         then the result must have zero phase.  If the source type is
> +         a generic pointer to shared and the target type is a pointer
> +         to a shared type with either an indefinite block size, or
> +         a block size of one, then the resulting value must have a
> +         phase of zero.  */
> +      if ((!VOID_TYPE_P (tt2)
> +	   && !(tree_int_cst_equal (b1, b2) && tree_int_cst_equal (s1, s2)))
> +	  || (VOID_TYPE_P (tt2)
> +	      && ((b1 == NULL)
> +		  || tree_int_cst_equal (b1, integer_one_node))))
> +	{
> +	  const tree ptr_as_pts_rep = fold (build1 (VIEW_CONVERT_EXPR,
> +						    upc_pts_rep_type_node,
> +						    ptr));
> +	  const tree sptr = save_expr (ptr_as_pts_rep);
> +	  const tree ptr_with_zero_phase =
> +	    upc_pts_build_value (loc, type,
> +					build3 (COMPONENT_REF, p_t, sptr,
> +						upc_vaddr_field_node,
> +						NULL_TREE),
> +					build3 (COMPONENT_REF, t_t, sptr,
> +						upc_thread_field_node,
> +						NULL_TREE),
> +					integer_zero_node);
> +	  result = ptr_with_zero_phase;
> +	}
> +    }
> +  return result;
> +}
> +
> +
> +/* Expand the expression EXP, which is a comparison between two
> +   UPC pointers-to-shared.
> +
> +   Per 6.4.2p6:
> +   Two compatible pointers-to-shared which point to the same object
> +   (i.e.  having the same address and thread components) shall compare
> +   as equal according to == and !=, regardless of whether the phase
> +   components match.
> +
> +   Thus, for the equality comparison, the phase component of the
> +   pointers is omitted from the comparison.  In that case,
> +   rewrite the pointer-to-shared comparison operation into a
> +   field by field comparison the vaddr and thread fields
> +   of the UPC pointer-to-shared operands.
> +
> +   If the bit-wise comparison cannot be performed, then the difference
> +   between the pointers is compared to zero.  */
> +
> +tree
> +upc_pts_build_cond_expr (location_t loc, tree exp)
> +{
> +  tree result;
> +  const enum tree_code code = TREE_CODE (exp);
> +  const int is_eq_op = (code == EQ_EXPR || code == NE_EXPR);
> +  tree op0 = TREE_OPERAND (exp, 0);
> +  tree op1 = TREE_OPERAND (exp, 1);
> +  const tree type0 = TREE_TYPE (op0);
> +  const tree type1 = TREE_TYPE (op1);
> +  gcc_assert (POINTER_TYPE_P (type0));
> +  gcc_assert (POINTER_TYPE_P (type1));
> +  {
> +    const tree ttype0 = TREE_TYPE (type0);
> +    const tree ttype1 = TREE_TYPE (type1);
> +    const tree elem_type0 = strip_array_types (ttype0);
> +    const tree elem_type1 = strip_array_types (ttype1);
> +    gcc_assert (TREE_SHARED (elem_type0));
> +    gcc_assert (TREE_SHARED (elem_type1));
> +    /* For == and !=, per 6.4.2p6 only compare (vaddr, thread).  */ 
> +    if (is_eq_op)
> +      {
> +	const tree t_t = TREE_TYPE (upc_thread_field_node);
> +	const tree v_t = TREE_TYPE (upc_vaddr_field_node);
> +	const enum tree_code code0 = TREE_CODE (op0);
> +	const enum tree_code code1 = TREE_CODE (op1);
> +	const enum tree_code tcode = (code == EQ_EXPR)
> +	  ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR;
> +	if (code0 == VIEW_CONVERT_EXPR
> +	    && TREE_TYPE (TREE_OPERAND (op0, 0)) == upc_pts_rep_type_node)
> +	  op0 = TREE_OPERAND (op0, 0);
> +	else
> +	  op0 = build1 (VIEW_CONVERT_EXPR, upc_pts_rep_type_node, op0);
> +	if (code1 == VIEW_CONVERT_EXPR
> +	    && TREE_TYPE (TREE_OPERAND (op1, 0)) == upc_pts_rep_type_node)
> +	  op1 = TREE_OPERAND (op1, 0);
> +	else
> +	  op1 = build1 (VIEW_CONVERT_EXPR, upc_pts_rep_type_node, op1);
> +	op0 = save_expr (op0);
> +	op1 = save_expr (op1);
> +	{
> +	  const tree off0 = build3 (COMPONENT_REF, v_t, op0,
> +				    upc_vaddr_field_node, NULL_TREE);
> +	  const tree off1 = build3 (COMPONENT_REF, v_t, op1,
> +				    upc_vaddr_field_node, NULL_TREE);
> +	  const tree off_cmp = build_binary_op (loc, code, off0, off1, 0);
> +	  const tree thread0 = build3 (COMPONENT_REF, t_t, op0,
> +				       upc_thread_field_node, NULL_TREE);
> +	  const tree thread1 = build3 (COMPONENT_REF, t_t, op1,
> +				       upc_thread_field_node, NULL_TREE);
> +	  const tree thread_cmp =
> +	    build_binary_op (loc, code, thread0, thread1, 0);
> +	  result = build_binary_op (loc, tcode, off_cmp, thread_cmp, 0);
> +	  /* Remove possible C_MAYBE_EXPR operands.  */
> +	  result = c_fully_fold (result, 0, NULL);
> +	  result = gimple_boolify (result);
> +	  result = fold_convert (TREE_TYPE (exp), result);
> +	}
> +      }
> +    else
> +      {
> +	const tree ptr_diff =
> +	  build_binary_op (loc, MINUS_EXPR, op0, op1, 0);
> +	op0 = ptr_diff;
> +	op1 = build_int_cst (TREE_TYPE (op0), 0);
> +	TREE_OPERAND (exp, 0) = op0;
> +	TREE_OPERAND (exp, 1) = op1;
> +	result = exp;
> +      }
> +  }
> +  return result;
> +}
> Index: gcc/c/c-upc-pts-ops.h
> ===================================================================
> --- gcc/c/c-upc-pts-ops.h	(.../trunk)	(revision 0)
> +++ gcc/c/c-upc-pts-ops.h	(.../branches/gupc)	(revision 231080)
> @@ -0,0 +1,35 @@
> +/* Define UPC pointer-to-shared representation-independent operations
> +   Copyright (C) 2008-2015 Free Software Foundation, Inc.
> +   Contributed by Gary Funck <gary@intrepid.com>
> +     and Nenad Vukicevic <nenad@intrepid.com>.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify
> +it under the terms of the GNU General Public License as published by
> +the Free Software Foundation; either version 3, or (at your option)
> +any later version.
> +
> +GCC is distributed in the hope that it will be useful,
> +but WITHOUT ANY WARRANTY; without even the implied warranty of
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +GNU General Public License for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#ifndef GCC_C_UPC_PTS_OPS_H
> +#define GCC_C_UPC_PTS_OPS_H 1
> +
> +extern tree upc_pts_build_cond_expr (location_t, tree);
> +extern tree upc_pts_build_constant (location_t, tree);
> +extern tree upc_pts_build_cvt (location_t, tree);
> +extern tree upc_pts_build_diff (location_t, tree);
> +extern tree upc_pts_build_sum (location_t, tree);
> +extern tree upc_pts_build_threadof (location_t, tree);
> +extern tree upc_pts_build_value (location_t, tree, tree, tree, tree);
> +extern void upc_pts_init (void);
> +extern int upc_pts_is_null_p (tree);
> +
> +#endif /* !GCC_C_UPC_PTS_OPS_H */
> Index: gcc/c/c-upc-rts-names.h
> ===================================================================
> --- gcc/c/c-upc-rts-names.h	(.../trunk)	(revision 0)
> +++ gcc/c/c-upc-rts-names.h	(.../branches/gupc)	(revision 231080)
> @@ -0,0 +1,64 @@
> +/* Define compiler-visible UPC runtime entry points and variables.
> +   Copyright (C) 2004-2015 Free Software Foundation, Inc.
> +   Contributed by Gary Funck <gary@intrepid.com>
> +     and Nenad Vukicevic <nenad@intrepid.com>.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify
> +it under the terms of the GNU General Public License as published by
> +the Free Software Foundation; either version 3, or (at your option)
> +any later version.
> +
> +GCC is distributed in the hope that it will be useful,
> +but WITHOUT ANY WARRANTY; without even the implied warranty of
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +GNU General Public License for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#ifndef GCC_C_C_UPC_RTS_NAMES_H
> +#define GCC_C_C_UPC_RTS_NAMES_H 1
> +
> +/* Name of initialization routine that is called to initialize
> +   shared variables and calculate shared address.  Both of these
> +   operations must be performed at runtime before UPC's main
> +   program is called.  */
> +#define UPC_INIT_DECLS_FUNC "__upc_init_decls"
> +
> +/* Name of runtime variable that is used by the code generated
> +   for the 'upc_forall' statement to implement nested upc_forall
> +   semantics.  Per the language specification, a dynamically nested
> +   upc_forall statement with an affinity clause will operate
> +   as if "continue" had been supplied for the affinity clause.  */
> +#define UPC_FORALL_DEPTH_NAME "__upc_forall_depth"
> +
> +/* Name of the runtime variable holding the address of the beginning of
> +   the global shared region.  */
> +#define UPC_GLOBAL_BASE_NAME "__upc_global_base"
> +
> +/* Names of various UPC runtime library routines that implement various
> +   UPC statement constructs.  */
> +#define UPC_BARRIER_LIBCALL "__upc_barrier"
> +#define UPC_GETADDR_LIBCALL "__getaddr"
> +#define UPC_NOTIFY_LIBCALL "__upc_notify"
> +#define UPC_WAIT_LIBCALL "__upc_wait"
> +
> +/* Profiled/debugged runtime library routines  */
> +#define UPC_BARRIERG_LIBCALL "__upc_barrierg"
> +#define UPC_GETADDRG_LIBCALL "__getaddrg"
> +#define UPC_NOTIFYG_LIBCALL "__upc_notifyg"
> +#define UPC_NOTIFYG_LIBCALL "__upc_notifyg"
> +#define UPC_WAITG_LIBCALL "__upc_waitg"
> +
> +/* Runtime library function that records upc_forall begin/end
> +   when -fupc-instrument is asserted.  */
> +#define UPC_INSTRUMENT_FORALL "__upc_forallg"
> +
> +/* Runtime library function that records function entry/exit 
> +   when -fupc-instrument-functions is asserted.  */
> +#define UPC_INSTRUMENT_FUNC "__upc_funcg"
> +
> +#endif  /* !GCC_C_C_UPC_RTS_NAMES_H */
Gary Funck Dec. 5, 2015, 11:36 p.m. UTC | #2
On 12/01/15 12:42:48, Richard Biener wrote:
> On Mon, 30 Nov 2015, Gary Funck wrote:
> [...]
> > +  get_lc_mode_name (mname, (op_mode));
> > +  sprintf (libfunc_name, "__get%s%s%s%s",
> > +           strict_mode ? "s" : "",
> > +           doprofcall ? "g" : "",
> > +	   mname,
> > +	   (op_mode == BLKmode)
> > +	     ? (doprofcall ? "5" : "3")
> > +	     : (doprofcall ? "3" : "2"));
> > +  libfunc = identifier_global_value (get_identifier (libfunc_name));
> > +  if (!libfunc)
> > +    internal_error ("UPC runtime function %s not found", libfunc_name);
> 
> I think for all these you should use builtins.  You definitely shouldn't
> ICE here if it is an error to not include upc.h (or whatever is required
> to make above lookup succeed).

For UPC, although a reference via a pointer-to-shared will often
access data on another node, fairly often the reference will be
on node or will be local to the current process.  It is a worthwhile
optimization to inline the runtime call because the number of instructions
to test if a reference is on-node or local and to then load/store
directly to that location is small/short relative to the overhead of
making the call.  On some micro-benchmarks, inlining is 30% faster
for get/put accesses.

Inlining is implemented with a pre-include of "gcc-upc.h", which
in turn includes "gcc-upc-lib.h", which defines the API to
the libgupc runtime library.  At optimization levels greater than 0,
gcc-upc-lib.h will implement many UPC runtime procedures as
inline procedures.  This inlining can be disabled with -fupc-no-inline-lib.
The pre-include can be disabled with -fupc-no-pre-include, but
this is typically only done by certain tests.  The pre-include
will be enabled by default if -fupc is asserted.

Thus,

- We need to bring in the inlined runtime procedures via
  the pre-include.

- If we're compiling UPC, then the runtime header file
  will be pre-included, unless explicitly disabled via
  -fupc-no-pre-include (which is ill-advised for regular users).

It is effectively an internal error, if we can't find
the runtime procedures.

Regarding builtins, if we were to contemplate generating
code that makes this locality check and then issuing
a direct access for local/on-node accesses, it would
likely be impractical because different runtime libraries
will implement this locality check and local reference
differently.

- Gary
Gary Funck Dec. 5, 2015, 11:48 p.m. UTC | #3
On 12/01/15 12:42:48, Richard Biener wrote:
> On Mon, 30 Nov 2015, Gary Funck wrote:
> [...]
> > +  if (bitpos)
> > +    {
> > +      t_offset = size_int (bitpos / BITS_PER_UNIT);
> > +      if (offset)
> > +	t_offset = fold (build_binary_op (loc, PLUS_EXPR,
> > +                         offset, t_offset, 0));
> 
> Don't use fold ().  If you want a simplified tree don't go
> through build_binary_op but use fold_build2.  In this case
> it looks you want to use size_binop anyway.

OK

Regarding size_binop(), I'll need to review the code.
There are places that we need to retain sign and use
signed size types for example.

> > +    }
> > +  else
> > +    t_offset = offset;
> > +  {
> > +    const tree base_addr_type = TREE_TYPE (base_addr);
> > +    const enum tree_code cvt_op =
> > +	lang_hooks.types_compatible_p (upc_char_pts_type_node, base_addr_type)
> > +	? NOP_EXPR : CONVERT_EXPR;
> 
> NOP and CONVERT are the same.

I haven't followed every GCC changes/re-org closely, but my impression
is that there has been a move to make NOP and CONVERT the same.
Is that correct?

We retain CONVERT's between UPC pointer-to-shared that are not
equivalent and that require some special logic to inter-operate
or convert them.  The UPC lowering pass handles those special cases.
Those conversions are not NOP's.  For example, a floating point
to integer conversion isn't a no-op.

Could use some additional guidance here.
diff mbox

Patch

Index: gcc/c-family/c-upc-pts.h
===================================================================
--- gcc/c-family/c-upc-pts.h	(.../trunk)	(revision 0)
+++ gcc/c-family/c-upc-pts.h	(.../branches/gupc)	(revision 231080)
@@ -0,0 +1,40 @@ 
+/* Define UPC pointer-to-shared representation characteristics.
+   Copyright (C) 2008-2015 Free Software Foundation, Inc.
+   Contributed by Gary Funck <gary@intrepid.com>
+     and Nenad Vukicevic <nenad@intrepid.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_C_FAMILY_UPC_PTS_H
+#define GCC_C_FAMILY_UPC_PTS_H 1
+
+#define UPC_PTS_SIZE            (LONG_TYPE_SIZE + POINTER_SIZE)
+#define UPC_PTS_PHASE_SIZE      (LONG_TYPE_SIZE / 2)
+#define UPC_PTS_THREAD_SIZE     (LONG_TYPE_SIZE / 2)
+#define UPC_PTS_VADDR_SIZE      POINTER_SIZE
+#define UPC_PTS_PHASE_TYPE      ((LONG_TYPE_SIZE == 64) \
+				? "uint32_t" : "uint16_t")
+#define UPC_PTS_THREAD_TYPE     ((LONG_TYPE_SIZE == 64) \
+				? "uint32_t" : "uint16_t")
+#define UPC_PTS_VADDR_TYPE      "char *"
+
+#define UPC_MAX_THREADS (1 << (((UPC_PTS_THREAD_SIZE) < 30) \
+				 ? (UPC_PTS_THREAD_SIZE) : 30))
+#define UPC_MAX_BLOCK_SIZE ((1 << (((UPC_PTS_PHASE_SIZE) < 30) \
+				    ? (UPC_PTS_PHASE_SIZE) : 30)) - 1)
+
+#endif  /* !GCC_C_FAMILY_UPC_PTS_H */
Index: gcc/c/c-upc-low.c
===================================================================
--- gcc/c/c-upc-low.c	(.../trunk)	(revision 0)
+++ gcc/c/c-upc-low.c	(.../branches/gupc)	(revision 231080)
@@ -0,0 +1,1434 @@ 
+/* c-upc-low.c: UPC language specific tree lowering pass
+   Copyright (C) 2006-2015 Free Software Foundation, Inc.
+   Contributed by Gary Funck <gary@intrepid.com>
+     and Nenad Vukicevic <nenad@intrepid.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "alias.h"
+#include "fold-const.h"
+#include "stringpool.h"
+#include "hard-reg-set.h"
+#include "c-tree.h"
+#include "c-family/c-pragma.h"
+#include "output.h"
+#include "langhooks.h"
+#include "function.h"
+#include "tree-hasher.h"
+#include "is-a.h"
+#include "cgraph.h"
+#include "gimple-expr.h"
+#include "gimple-low.h"
+#include "gimplify.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "timevar.h"
+#include "tree-iterator.h"
+#include "c-upc-low.h"
+#include "c-upc.h"
+#include "c-upc-gasp.h"
+#include "c-upc-pts-ops.h"
+#include "c-upc-rts-names.h"
+
+static GTY (()) tree upc_init_stmt_list;
+
+static void get_lc_mode_name (char *, machine_mode);
+static tree upc_expand_get (location_t, tree, int);
+static tree upc_expand_put (location_t, tree, tree, int);
+static tree upc_create_tmp_var (tree);
+static tree upc_copy_value_to_tmp_var (tree *, tree);
+static tree upc_make_bit_field_ref (tree, tree, int, int);
+static tree upc_build_shared_var_addr (location_t, tree);
+static tree upc_shared_addr (location_t, tree);
+static tree upc_shared_addr_rep (location_t, tree);
+static tree upc_simplify_shared_ref (location_t, tree);
+static void upc_strip_useless_generic_pts_cvt (tree *);
+static void upc_write_init_func (void);
+
+/* Given a shared variable's VAR_DECL node, map to another
+   VAR_DECL that has a similar external symbol name, with
+   the "shared" qualifier removed from its type.  This
+   "shadow variable" is used to generate conventional
+   address constants when referring to a shared variable.  */
+static int_tree_htab_type *unshared_vars_map;
+
+static tree create_unshared_var (location_t, const tree);
+static tree lookup_unshared_var (const tree);
+static void map_unshared_var (const tree, const tree);
+static tree unshared_var_addr (location_t, const tree);
+static tree unshared_var_name (const tree);
+static void upc_free_unshared_var_table (void);
+
+static void upc_genericize_addr_expr (location_t, tree *);
+static void upc_genericize_array_ref (location_t, tree *);
+static void upc_genericize_compound_expr (tree *, int);
+static void upc_genericize_cond_expr (tree *, int);
+static void upc_genericize_decl_expr (tree *);
+static tree upc_genericize_expr (tree *, int *, void *);
+static void upc_genericize_function (tree);
+static void upc_genericize_field_ref (location_t, tree *);
+static void upc_genericize_forall_stmt (tree *);
+static void upc_genericize_indirect_ref (location_t, tree *);
+static void upc_genericize_modify_expr (location_t, tree *, int);
+static void upc_genericize_pts_arith_expr (location_t, tree *);
+static void upc_genericize_pts_cond_expr (location_t, tree *);
+static void upc_genericize_pts_cvt (location_t, tree *);
+static void upc_genericize_pts_to_int_cvt (location_t, tree *);
+static void upc_genericize_real_imag_ref (location_t, tree *);
+static void upc_genericize_shared_inc_dec_expr (location_t, tree *, int);
+static void upc_genericize_shared_var_ref (location_t, tree *);
+static void upc_genericize_walk (tree *, int);
+static void upc_genericize_stmt_list (tree *);
+static void upc_genericize_sync_stmt (location_t, tree *);
+
+/* Create a new temporary variable declaration of type TYPE.
+   Push the variable into the current function binding.  */
+
+static tree
+upc_create_tmp_var (tree type)
+{
+  tree tmp_var;
+  /* We don't allow types that are addressable or incomplete.  */
+  gcc_assert (!TREE_ADDRESSABLE (type) && COMPLETE_TYPE_P (type));
+  /* The temp. must not be shared qualified.  If it is, then 
+     remove the 'shared' qualifier.  */
+  if (SHARED_TYPE_P (type))
+    type = build_unshared_type (type);
+  tmp_var = create_tmp_var_raw (type, "UPC");
+  DECL_CONTEXT (tmp_var) = current_function_decl;
+  DECL_SEEN_IN_BIND_EXPR_P (tmp_var) = 1;
+  /* record_vars() will do what we want, but not if GIMPLE_DF is set.
+     (since we haven't gimplified yet, it should not be set).  */
+  gcc_assert (!cfun->gimple_df);
+  record_vars (tmp_var);
+  return tmp_var;
+}
+
+/* Create a temporary variable and initialize it to VAL.
+   The expression used to initialize the temporary value
+   is returned in *VAL_EXPR.  */
+
+static tree
+upc_copy_value_to_tmp_var (tree *val_expr, tree val)
+{
+  const tree type = TREE_TYPE (val);
+  const tree tmp_var = upc_create_tmp_var (type);
+  *val_expr = build2 (INIT_EXPR, type, tmp_var, val);
+  SET_EXPR_LOCATION (*val_expr, EXPR_LOC_OR_LOC (val, input_location));
+  return tmp_var;
+}
+
+static void
+get_lc_mode_name (char *mname, machine_mode mode)
+{
+  char *m = mname;
+  const char *m_upper = GET_MODE_NAME (mode);
+  while (*m_upper)
+    *m++ = TOLOWER (*m_upper++);
+  *m = '\0';
+}
+
+/* Generate a call to the runtime to implement a 'get' of a shared
+   object.  SRC is a reference to  a UPC shared value; it must
+   be addressable.  */
+
+static tree
+upc_expand_get (location_t loc, tree src, int want_stable_value)
+{
+  tree type = TREE_TYPE (src);
+  /* Drop the shared qualifier.  */
+  tree result_type = TYPE_MAIN_VARIANT (type);
+  int strict_mode = TYPE_STRICT (type)
+    || (!TYPE_RELAXED (type) && get_upc_consistency_mode ());
+  int doprofcall = flag_upc_debug
+                   || (flag_upc_instrument && get_upc_pupc_mode ());
+  machine_mode mode = TYPE_MODE (type);
+  machine_mode op_mode = (mode == TImode) ? BLKmode : mode;
+  expanded_location s = expand_location (loc);
+  const char *src_filename = s.file;
+  const int src_line = s.line;
+  char libfunc_name[16], mname[8];
+  tree src_addr, result, result_tmp, libfunc, lib_args, lib_call;
+  src_addr = upc_shared_addr_rep (loc, src);
+  gcc_assert (TREE_TYPE (src_addr) == upc_pts_rep_type_node);
+  get_lc_mode_name (mname, (op_mode));
+  sprintf (libfunc_name, "__get%s%s%s%s",
+           strict_mode ? "s" : "",
+           doprofcall ? "g" : "",
+	   mname,
+	   (op_mode == BLKmode)
+	     ? (doprofcall ? "5" : "3")
+	     : (doprofcall ? "3" : "2"));
+  libfunc = identifier_global_value (get_identifier (libfunc_name));
+  if (!libfunc)
+    internal_error ("UPC runtime function %s not found", libfunc_name);
+  if (op_mode == BLKmode)
+    {
+      tree size = size_in_bytes (result_type);
+      tree result_addr;
+      result_tmp = upc_create_tmp_var (result_type);
+      TREE_ADDRESSABLE (result_tmp) = 1;
+      result_addr = build_fold_addr_expr_loc (loc, result_tmp);
+      /* A DECL_EXPR is sometimes needed (for example when applying
+         sizeof() to a UPC shared VLA) to properly declare
+	 the type of the temp. variable used to hold the result
+	 of the expression.  */
+      result_addr = build2 (COMPOUND_EXPR, TREE_TYPE (result_addr),
+			    build1 (DECL_EXPR, TREE_TYPE (result_tmp),
+				    result_tmp),
+			    result_addr);
+      lib_args = tree_cons (NULL_TREE, result_addr,
+			    tree_cons (NULL_TREE, src_addr,
+				       tree_cons (NULL_TREE, size,
+						  NULL_TREE)));
+      if (doprofcall)
+	lib_args = upc_gasp_add_src_args (lib_args,
+					  src_filename, src_line);
+      lib_call = build_function_call (loc, libfunc, lib_args);
+      result = build2 (COMPOUND_EXPR, result_type, lib_call, result_tmp);
+    }
+  else
+    {
+      lib_args = tree_cons (NULL_TREE, src_addr, NULL_TREE);
+      if (doprofcall)
+	lib_args = upc_gasp_add_src_args (lib_args,
+					  src_filename, src_line);
+      lib_call = build_function_call (loc, libfunc, lib_args);
+      if (!lang_hooks.types_compatible_p (result_type, TREE_TYPE (lib_call)))
+	lib_call = build1 (NOP_EXPR, result_type, lib_call);
+      result = lib_call;
+      if (want_stable_value)
+        {
+	  tree result_tmp_init_expr;
+          result_tmp = upc_copy_value_to_tmp_var (&result_tmp_init_expr,
+	                                          result);
+          result = build2 (COMPOUND_EXPR, result_type,
+	                   result_tmp_init_expr, result_tmp);
+	}
+    }
+  return result;
+}
+
+/* Generate a call to the runtime to implement a 'put' into a shared
+   object.  DEST is a reference to the destination in UPC shared memory;
+   it must be addressable.  SRC is the value to be stored into the
+   destination.  If WANT_VALUE is set, then return a compound expression
+   which evaluates to the value of SRC.  */
+
+static tree
+upc_expand_put (location_t loc, tree dest, tree src, int want_value)
+{
+  tree type = TREE_TYPE (dest);
+  int strict_mode = TYPE_STRICT (type)
+    || (!TYPE_RELAXED (type) && get_upc_consistency_mode ());
+  int doprofcall = flag_upc_debug
+                   || (flag_upc_instrument && get_upc_pupc_mode ());
+  machine_mode mode = TYPE_MODE (type);
+  machine_mode op_mode = (mode == TImode) ? BLKmode : mode;
+  int is_src_shared = (TREE_SHARED (src)
+		       || SHARED_TYPE_P (TREE_TYPE (src)));
+  int local_copy = want_value
+    || (op_mode == BLKmode
+	&& !(is_src_shared && INDIRECT_REF_P (src))
+	&& (!is_gimple_addressable (src)
+	    || !is_gimple_variable (src)
+	    || needs_to_live_in_memory (src)));
+  int is_shared_copy = !local_copy && (op_mode == BLKmode) && is_src_shared;
+  char libfunc_name[16], mname[8];
+  expanded_location s = expand_location (loc);
+  const char *src_filename = s.file;
+  const int src_line = s.line;
+  tree dest_addr, libfunc, lib_args, src_tmp_init_expr, result;
+  dest_addr = upc_shared_addr_rep (loc, dest);
+  gcc_assert (TREE_TYPE (dest_addr) == upc_pts_rep_type_node);
+  if (local_copy)
+    src = upc_copy_value_to_tmp_var (&src_tmp_init_expr, src);
+  lib_args = tree_cons (NULL_TREE, dest_addr, NULL_TREE);
+  if (is_shared_copy)
+    {
+      sprintf (libfunc_name, "__copy%s%sblk%s",
+	       strict_mode ? "s" : "",
+	       doprofcall ? "g" : "",
+	       doprofcall ? "5" : "3");
+    }
+  else
+    {
+      get_lc_mode_name (mname, op_mode);
+      sprintf (libfunc_name, "__put%s%s%s%s",
+	       strict_mode ? "s" : "",
+	       doprofcall ? "g" : "",
+	       mname,
+	       (op_mode == BLKmode)
+	       ? (doprofcall ? "5" : "3")
+	       : (doprofcall ? "4" : "2"));
+    }
+  libfunc = identifier_global_value (get_identifier (libfunc_name));
+  if (!libfunc)
+    internal_error ("UPC runtime function %s not found", libfunc_name);
+  if (op_mode == BLKmode)
+    {
+      const tree size = tree_expr_size (src);
+      tree src_addr;
+      if (is_shared_copy)
+	src_addr = upc_shared_addr_rep (loc, src);
+      else
+        src_addr = build_fold_addr_expr_loc (loc, src);
+      lib_args = chainon (lib_args,
+			  tree_cons (NULL_TREE, src_addr,
+				     tree_cons (NULL_TREE, size, NULL_TREE)));
+      if (doprofcall)
+	lib_args = upc_gasp_add_src_args (lib_args, src_filename, src_line);
+    }
+  else
+    {
+      tree src_type = lang_hooks.types.type_for_mode (mode, 0);
+      tree libfunc_arg_types = TYPE_ARG_TYPES (TREE_TYPE (libfunc));
+      tree put_arg_type = TREE_VALUE (TREE_CHAIN (libfunc_arg_types));
+      if (TYPE_PRECISION (put_arg_type) != TYPE_PRECISION (src_type))
+	internal_error ("%s: UPC put operation argument precision mismatch",
+			libfunc_name);
+      /* Avoid warnings about implicit conversion between
+         the actual parameter value's type, and the type of the
+         runtime routine's parameter.  */
+      if (!lang_hooks.types_compatible_p (src_type, TREE_TYPE (src)))
+	src = build1 (AGGREGATE_TYPE_P (TREE_TYPE (src))
+		      ? VIEW_CONVERT_EXPR : NOP_EXPR, src_type, src);
+      lib_args = chainon (lib_args, tree_cons (NULL_TREE, src, NULL_TREE));
+      if (doprofcall)
+	lib_args = upc_gasp_add_src_args (lib_args, src_filename, src_line);
+    }
+  result = build_function_call (loc, libfunc, lib_args);
+  if (want_value)
+    result = build2 (COMPOUND_EXPR, TREE_TYPE (src), result, src);
+  if (local_copy)
+    result = build2 (COMPOUND_EXPR, TREE_TYPE (result),
+		     src_tmp_init_expr, result);
+  return result;
+}
+
+/* Return a BIT_FIELD_REF of type TYPE to refer to BITSIZE bits of INNER
+   starting at BITPOS.  The field is unsigned if UNSIGNEDP is nonzero.  */
+
+static tree
+upc_make_bit_field_ref (tree inner, tree type, int bitsize, int bitpos)
+{
+  tree result;
+  if (bitpos == 0)
+    {
+      tree size = TYPE_SIZE (TREE_TYPE (inner));
+      if ((INTEGRAL_TYPE_P (TREE_TYPE (inner))
+	   || POINTER_TYPE_P (TREE_TYPE (inner)))
+	  && tree_fits_shwi_p (size)
+	  && tree_to_shwi (size) == bitsize)
+	return fold_convert (type, inner);
+    }
+  result = build3 (BIT_FIELD_REF, type, inner,
+		   size_int (bitsize), bitsize_int (bitpos));
+  return result;
+}
+
+/* On entry, EXP points to a shared field reference
+   or array reference.  Simplify it so that is in
+   one of two forms:
+   1) (INDIRECT_REF <pointer to shared object>)
+   2) (BIT_FIELD_REF (INDIRECT_REF <pointer to shared object>) ...)
+   The first form is returned for all shared field references
+   except those that require access to bit fields within
+   a storage unit.  */
+
+static tree
+upc_simplify_shared_ref (location_t loc, tree exp)
+{
+  tree ref_type = TREE_TYPE (exp);
+  tree base, base_addr, ref, t_offset;
+  machine_mode mode = VOIDmode;
+  HOST_WIDE_INT bitsize = 0;
+  HOST_WIDE_INT bitpos = 0;
+  int unsignedp = 0;
+  int reversep = 0;
+  int volatilep = 0;
+  tree offset = NULL_TREE;
+  base = get_inner_reference (exp, &bitsize, &bitpos, &offset,
+			      &mode, &unsignedp, &reversep, &volatilep,
+			      false);
+  gcc_assert (SHARED_TYPE_P (TREE_TYPE (base)));
+  base_addr = build_fold_addr_expr (base);
+  if (bitpos)
+    {
+      t_offset = size_int (bitpos / BITS_PER_UNIT);
+      if (offset)
+	t_offset = fold (build_binary_op (loc, PLUS_EXPR,
+                         offset, t_offset, 0));
+    }
+  else
+    t_offset = offset;
+  {
+    const tree base_addr_type = TREE_TYPE (base_addr);
+    const enum tree_code cvt_op =
+	lang_hooks.types_compatible_p (upc_char_pts_type_node, base_addr_type)
+	? NOP_EXPR : CONVERT_EXPR;
+    /* Convert the base address to (shared [] char *), which may
+       reset the pointer's phase to zero.  This is the behavior
+       that is required to reference a field in a structure and
+       to meaningfully add an offset to the base address.  */
+    base_addr = build1 (cvt_op, upc_char_pts_type_node, base_addr);
+    if (t_offset)
+      {
+	/* Adjust the base address so that it points to the
+	   simplified lvalue.  */
+	base_addr = fold (build_binary_op (loc, PLUS_EXPR,
+			  base_addr, t_offset, 0));
+	base_addr = convert (base_addr_type, base_addr);
+      }
+  }
+  /* We need to construct a pointer-to-shared type that
+     will be used to point to the referenced value.  However,
+     for a COMPONENT_REF, the original type will likely not have
+     SHARED_TYPE_P() asserted, but rather, the expression node itself
+     will have TREE_SHARED asserted.  We need to first propagate
+     this information into a new shared type, which will in turn be
+     used to build the required pointer-to-shared type.  Further,
+     any pointer to a shared component must be constrained to have
+     a blocking factor of zero.  */
+  if (!SHARED_TYPE_P (ref_type))
+    {
+      const int shared_quals = TYPE_QUALS (TREE_TYPE (exp))
+                               | TREE_QUALS (exp);
+      gcc_assert (shared_quals & TYPE_QUAL_SHARED);
+      ref_type = c_build_qualified_type_1 (ref_type, shared_quals,
+                                           size_zero_node);
+    }
+  if (TREE_TYPE (TREE_TYPE (base_addr)) != ref_type)
+    base_addr = convert (build_pointer_type (ref_type), base_addr);
+  /* The simplified reference is an indirect ref., using
+     the adjusted base_addr  */
+  ref = build_fold_indirect_ref_loc (loc, base_addr);
+  /* If this is a BIT_FIELD_REF then adjust its base address.  */
+  if (TREE_CODE (exp) == BIT_FIELD_REF)
+    ref = upc_make_bit_field_ref (ref, ref_type, bitsize, bitpos);
+  return ref;
+}
+
+/* Create and return a "shadow variable" that has the same type as VAR,
+   but with all UPC shared qualifiers removed from the type.
+   The assembler name of this shadow variable is the same
+   as that of the original variable, VAR.  */
+
+static tree
+create_unshared_var (location_t loc, const tree var)
+{
+  tree u_name, u_type, u;
+  gcc_assert (var && TREE_CODE (var) == VAR_DECL);
+  u_name = unshared_var_name (var);
+  u_type = build_unshared_type (TREE_TYPE (var));
+  u = build_decl (loc, VAR_DECL, u_name, u_type);
+  TREE_USED (u) = 1;
+  TREE_ADDRESSABLE (u) = 1;
+  TREE_PUBLIC (u) = TREE_PUBLIC (var);
+  TREE_STATIC (u) = TREE_STATIC (var);
+  DECL_ARTIFICIAL (u) = 1;
+  DECL_IGNORED_P (u) = 1;
+  set_decl_section_name (u, DECL_SECTION_NAME (var));
+  DECL_CONTEXT (u) = DECL_CONTEXT (var);
+  /* Define it as 'external' so that no data is allocated.  */
+  DECL_EXTERNAL (u) = 1;
+  /* Alias the unshared variable to the shared variable.  */
+  SET_DECL_ASSEMBLER_NAME (u, DECL_ASSEMBLER_NAME (var));
+  /* Make sure the variable is referenced.  */
+  mark_decl_referenced (var);
+  return u;
+}
+
+/* Return the "shadow variable" created for VAR that
+   has the same type as VAR, but with the UPC shared
+   qualifiers removed.  */
+
+static tree
+lookup_unshared_var (const tree var)
+{
+  struct int_tree_map in;
+  unsigned int uid;
+  gcc_assert (var && TREE_CODE (var) == VAR_DECL);
+  uid = DECL_UID (var);
+  in.uid = uid;
+  in.to = NULL_TREE;
+  return unshared_vars_map->find_with_hash (in, uid).to;
+}
+
+#define UNSHARE_PREFIX "_u_"
+
+/* Return an identifier that will be used to declare the "shadow variable"
+   which has the same type as VAR, but with all UPC shared qualifiers
+   removed from the type.  The identifier has the same name as
+   that of VAR, prefixed with the string given by the
+   value of `UNSHARE_PREFIX'.  */
+
+static tree
+unshared_var_name (const tree var)
+{
+  const tree name = DECL_NAME (var);
+  const size_t len = IDENTIFIER_LENGTH (name);
+  char *tmp_name = (char *) alloca (len + sizeof (UNSHARE_PREFIX));
+  strcpy (tmp_name, UNSHARE_PREFIX);
+  strcat (tmp_name, IDENTIFIER_POINTER (name));
+  return get_identifier (tmp_name);
+}
+
+/* Register the mapping between the UPC shared variable, VAR,
+   and its unshared counter-part, U_VAR.  "unshared" in
+   this context means that the shadow variable U_VAR
+   has the same type as VAR, with the UPC shared,
+   strict, and relaxed qualifiers removed.  */
+
+static void
+map_unshared_var (const tree var, const tree u_var)
+{
+  int_tree_map h;
+  unsigned int uid;
+  int_tree_map *loc;
+  gcc_assert (var && TREE_CODE (var) == VAR_DECL);
+  gcc_assert (u_var && TREE_CODE (u_var) == VAR_DECL);
+  uid = DECL_UID (var);
+  h.uid = uid;
+  loc = unshared_vars_map->find_slot_with_hash (h, uid, INSERT);
+  loc->uid = uid;
+  loc->to = u_var;
+}
+
+/* Return a tree node that evaluates to the address that the
+   linker assigns to the UPC shared variable, VAR.  This is not
+   the final location of the UPC shared variable.  The linker is
+   used only to lay out a given UPC thread's contribution to the
+   UPC shared global memory region.
+
+   The address expression returned will point to a "shadow
+   variable" declaration that is created from the UPC shared
+   variable declaration, VAR.  This shadow variable has the same
+   type and other attributes as VAR, with the UPC shared type
+   qualifiers removed.  */
+
+static tree
+unshared_var_addr (location_t loc, const tree var)
+{
+  tree unshared_var, addr;
+  unshared_var = lookup_unshared_var (var);
+  if (!unshared_var)
+    {
+      unshared_var = create_unshared_var (loc, var);
+      map_unshared_var (var, unshared_var);
+    }
+  addr = build_fold_addr_expr (unshared_var);
+  TREE_CONSTANT (addr) = 1;
+  TREE_READONLY (addr) = 1;
+  return addr;
+}
+
+/* Free the hash table used to map UPC VAR_DECL's
+   into the "unshared" shadow variables that were created
+   in order to establish the offset of a UPC shared
+   variable with the special linker section that is
+   created to collect the UPC shared variables.  */
+
+static void
+upc_free_unshared_var_table (void)
+{
+  if (unshared_vars_map)
+    {
+      delete unshared_vars_map;
+      unshared_vars_map = NULL;
+    }
+}
+
+/* Convert the shared variable reference VAR into a UPC pointer-to-shared
+   value of the form {0, 0, &VAR}.  */
+
+static tree
+upc_build_shared_var_addr (location_t loc, tree var)
+{
+  tree var_addr, val;
+  gcc_assert (TREE_CODE (var) == VAR_DECL && TREE_SHARED (var));
+  /* Refer to a shadow variable that has the same type as VAR, but
+     with the shared qualifier removed.  */
+  var_addr = unshared_var_addr (loc, var);
+  val = upc_pts_build_value (loc, build_pointer_type (TREE_TYPE (var)),
+                             var_addr, integer_zero_node, integer_zero_node);
+  return val;
+}
+
+/* Return the UPC shared address of the lvalue
+   identified by EXP.  The type of the result is
+   the UPC pointer-to-shared representation type.  */
+
+static tree
+upc_shared_addr_rep (location_t loc, tree exp)
+{
+  tree addr = upc_shared_addr (loc, exp);
+  /* Convert to internal UPC pointer-to-shared representation,
+     possibly removing an unnecessary chain of VIEW_CONVERT_EXPR's.  */
+  addr = fold (build1 (VIEW_CONVERT_EXPR, upc_pts_rep_type_node, addr));
+  return addr;
+}
+
+/* Return the UPC shared address of the lvalue
+   identified by EXP.  The type of the result is
+   the UPC pointer-to-shared representation type.  */
+
+static tree
+upc_shared_addr (location_t loc, tree exp)
+{
+  tree ref = exp;
+  const enum tree_code code = TREE_CODE (exp);
+  tree addr;
+  switch (code)
+    {
+    case VAR_DECL:
+      addr = upc_build_shared_var_addr (loc, exp);
+      break;
+    case ARRAY_REF:
+    case COMPONENT_REF:
+      ref = upc_simplify_shared_ref (loc, exp);
+      if (TREE_CODE (ref) == ERROR_MARK)
+	return ref;
+      addr = build_fold_addr_expr_loc (loc, ref);
+      upc_genericize_walk (&addr, /* want_value */ 1);
+      break;
+    case INDIRECT_REF:
+      /* Remove the indirection by taking the address and simplifying.  */
+      addr = build_fold_addr_expr_loc (loc, ref);
+      upc_genericize_walk (&addr, /* want_value */ 1);
+      break;
+    case BIT_FIELD_REF:
+      error ("invalid & operation applied to a UPC shared bit field");
+      return error_mark_node;
+    default:
+      gcc_unreachable ();
+    }
+  return addr;
+}
+
+/* Rewrite a 'upc_forall' statement into a
+   regular 'for' statement.  */
+
+static void
+upc_genericize_forall_stmt (tree *expr_p ATTRIBUTE_UNUSED)
+{
+  /* Handled in c-parser.c.  */
+  gcc_unreachable ();
+}
+
+/* Rewrite a UPC synchronization statement (upc_wait, upc_notify,
+   and upc_barrier) into a call to the runtime.  */
+
+static void
+upc_genericize_sync_stmt (location_t loc, tree *stmt_p)
+{
+  /* The first operand is the synchronization operation, UPC_SYNC_OP:
+     UPC_SYNC_NOTIFY_OP         1       Notify operation
+     UPC_SYNC_WAIT_OP           2       Wait operation
+     UPC_SYNC_BARRIER_OP        3       Barrier operation
+     The second operand, UPC_SYNC_ID is the (optional) expression
+     whose value specifies the barrier identifier which is checked
+     by the various synchronization operations.  */
+  tree stmt = *stmt_p;
+  tree sync_op = UPC_SYNC_OP (stmt);
+  tree sync_id = UPC_SYNC_ID (stmt);
+  const int op = tree_to_shwi (sync_op);
+  const char *libfunc_name = (char *) 0;
+  int doprofcall = flag_upc_debug
+                   || (flag_upc_instrument && get_upc_pupc_mode ());
+  tree libfunc, lib_args;
+  switch (op)
+    {
+    case UPC_SYNC_NOTIFY_OP:
+      libfunc_name = doprofcall ? UPC_NOTIFYG_LIBCALL : UPC_NOTIFY_LIBCALL;
+      break;
+    case UPC_SYNC_WAIT_OP:
+      libfunc_name = doprofcall ? UPC_WAITG_LIBCALL : UPC_WAIT_LIBCALL;
+      break;
+    case UPC_SYNC_BARRIER_OP:
+      libfunc_name = doprofcall ? UPC_BARRIERG_LIBCALL : UPC_BARRIER_LIBCALL;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  libfunc = identifier_global_value (get_identifier (libfunc_name));
+  if (!libfunc)
+    internal_error ("UPC runtime function %s not found", libfunc_name);
+  if (!sync_id)
+    sync_id = build_int_cst (NULL_TREE, INT_MIN);
+  lib_args = tree_cons (NULL_TREE, sync_id, NULL_TREE);
+  if (doprofcall)
+    lib_args = upc_gasp_add_src_args (lib_args,
+                                      LOCATION_FILE (input_location),
+                                      LOCATION_LINE (input_location));
+  *stmt_p = build_function_call (loc, libfunc, lib_args);
+}
+
+/* Rewrite a reference to a UPC shared variable into a 'get' operation.  */
+
+static void
+upc_genericize_shared_var_ref (location_t loc, tree *expr_p)
+{
+  tree src = *expr_p;
+  *expr_p = upc_expand_get (loc, src, 0);
+}
+
+/* Expand & of a UPC shared object into equivalent code.  */
+
+static void
+upc_genericize_addr_expr (location_t loc, tree *expr_p)
+{
+  const tree op0 = TREE_OPERAND (*expr_p, 0);
+  *expr_p = upc_shared_addr (loc, op0);
+}
+
+/* Expand indirection through a UPC pointer-to-shared
+   into a UPC get operation.  */
+
+static void
+upc_genericize_indirect_ref (location_t loc, tree *expr_p)
+{
+  tree src = *expr_p;
+  *expr_p = upc_expand_get (loc, src, 0);
+}
+
+/* Expand .real and .imag applied to a UPC shared object.  */
+
+static void
+upc_genericize_real_imag_ref (location_t loc ATTRIBUTE_UNUSED,
+			      tree *expr_p ATTRIBUTE_UNUSED)
+{
+  error ("accesses to .real and .imag are not yet implemented");
+  *expr_p = error_mark_node;
+}
+
+/* Rewrite a[i] into *(a + i).  This code is derived from
+   build_array_ref().  We could call build_array_ref()
+   directly, and depend upon it to do this rewrite if
+   the array is shared, but it is clearer to handle
+   it explicitly here.  */
+
+static void
+upc_genericize_array_ref (location_t loc, tree *expr_p)
+{
+  tree exp = *expr_p;
+  tree array = TREE_OPERAND (exp, 0);
+  tree index = TREE_OPERAND (exp, 1);
+  tree ar = default_conversion (array);
+  gcc_assert (TREE_CODE (exp) == ARRAY_REF);
+  if (ar == error_mark_node)
+    return;
+  gcc_assert (TREE_CODE (TREE_TYPE (ar)) == POINTER_TYPE);
+  gcc_assert (TREE_CODE (TREE_TYPE (TREE_TYPE (ar))) != FUNCTION_TYPE);
+  *expr_p = build_indirect_ref (loc,
+				build_binary_op (loc, PLUS_EXPR, ar, index,
+						 0), RO_ARRAY_INDEXING);
+  upc_genericize_indirect_ref (loc, expr_p);
+}
+
+/* Handle conversions between UPC pointers-to-shared and
+   local pointers, or between UPC pointers-to-shared which
+   have differing block factors.  */
+
+static void
+upc_genericize_pts_cvt (location_t loc, tree *expr_p)
+{
+  *expr_p = upc_pts_build_cvt (loc, *expr_p);
+}
+
+/* Handle conversions from a UPC pointer-to-shared into
+   an integer value.  */
+
+static void
+upc_genericize_pts_to_int_cvt (location_t loc, tree *expr_p)
+{
+  tree pts, pts_arg, ref_type, upc_addrfield;
+  tree *pts_p;
+  int shared_quals;
+  upc_addrfield = identifier_global_value (get_identifier ("upc_addrfield"));
+  if (!upc_addrfield)
+    internal_error ("UPC runtime function `upc_addrfield` not found");
+  pts_p = &TREE_OPERAND (*expr_p, 0);
+  pts = *pts_p;
+  ref_type = TREE_TYPE (TREE_TYPE (pts));
+  shared_quals = TYPE_QUALS (ref_type) | TREE_QUALS (pts);
+  gcc_assert (shared_quals & TYPE_QUAL_SHARED);
+  if ((shared_quals & TYPE_QUAL_CONST) != 0)
+    {
+      /* Drop 'const' qualifier to arg. type mis-match.  */
+      shared_quals &= ~TYPE_QUAL_CONST;
+      ref_type = c_build_qualified_type_1 (ref_type, shared_quals,
+                                           size_zero_node);
+      TREE_TYPE (pts) = build_pointer_type (ref_type);
+    }
+  pts_arg = tree_cons (NULL_TREE, pts, NULL_TREE);
+  *pts_p = build_function_call (loc, upc_addrfield, pts_arg);
+}
+
+/* Rewrite op0 CMP op1 into either a bitwise
+   comparison of the UPC pointer-to-shared operands
+   or by taking the difference, and comparing it
+   to zero.  */
+
+static void
+upc_genericize_pts_cond_expr (location_t loc, tree *expr_p)
+{
+  *expr_p = upc_pts_build_cond_expr (loc, *expr_p);
+}
+
+/* Rewrite a reference to a bit field within a UPC shared struct/union.
+   When implemented, the translated tree will need to fetch
+   the container for this bit-field from UPC shared memory,
+   and then isolate the bit field within the container.  */
+
+static void
+upc_genericize_field_ref (location_t loc, tree *expr_p)
+{
+  tree ref = upc_simplify_shared_ref (loc, *expr_p);
+  if (TREE_CODE (ref) == BIT_FIELD_REF)
+    {
+      error_at (loc, "accesses to UPC shared bit fields "
+                     "are not yet implemented");
+      ref = error_mark_node;
+    }
+  else
+    ref = upc_expand_get (loc, ref, 0);
+  *expr_p = ref;
+}
+
+/* Expand the addition of UPC pointer-to-shared value and an integer.
+   When the operation is subtraction, rewrite the expression (p - i)
+   into (p + (-i)) and expand the sum.  The special handling of
+   subtraction is required because addition/subtraction of UPC
+   pointers-to-shared is a non-trivial operation, and it simpler
+   to only implement addition.  */
+
+static void
+upc_genericize_pts_arith_expr (location_t loc, tree *expr_p)
+{
+  tree exp = *expr_p;
+  if (TREE_CODE (exp) == PLUS_EXPR || TREE_CODE (exp) == POINTER_PLUS_EXPR)
+    {
+      *expr_p = upc_pts_build_sum (loc, exp);
+    }
+  else if (TREE_CODE (exp) == MINUS_EXPR)
+    {
+      const tree type0 = TREE_TYPE (TREE_OPERAND (exp, 0));
+      const tree type1 = TREE_TYPE (TREE_OPERAND (exp, 1));
+      if ((TREE_CODE (type0) == POINTER_TYPE)
+	  && (TREE_CODE (type1) == INTEGER_TYPE))
+	{
+	  /* Rewrite the expression p - i into p + (-i),
+	     and expand the sum.  */
+	  tree int_op = TREE_OPERAND (exp, 1);
+	  if (TREE_CODE (int_op) == INTEGER_CST
+	      && TREE_CODE (TREE_TYPE (int_op)) == POINTER_TYPE)
+	    {
+	      /* Earlier passes have altered the type of the integer
+	         constant to be a UPC pointer-to-shared type.  This won't
+	         play well when we try to negate it.  For now, convert
+	         it back to a size type.  */
+	      int_op = ssize_int (tree_to_shwi (int_op));
+	    }
+	  TREE_SET_CODE (exp, PLUS_EXPR);
+	  /* Make sure that int_op is a signed type to
+	     ensure negation works properly.  */
+	  if (TYPE_UNSIGNED (TREE_TYPE (int_op)))
+	    int_op = convert (ssizetype, int_op);
+	  TREE_OPERAND (exp, 1) =
+	    build_unary_op (loc, NEGATE_EXPR, int_op, 0);
+	  *expr_p = upc_pts_build_sum (loc, exp);
+	}
+      else
+	*expr_p = upc_pts_build_diff (loc, exp);
+    }
+  else
+    gcc_unreachable ();
+}
+
+/* Rewrite the increment/decrement of a UPC shared value into
+   an equivalent assignment statement.  (Although some future
+   implementations of the UPC runtime API might be able to
+   implement these operations atomically, that is not currently
+   defined in the runtime API.)  If WANT_VALUE is set, then
+   generate a compound expression that yields the appropriate value.  */
+
+static void
+upc_genericize_shared_inc_dec_expr (location_t loc, tree *expr_p,
+				    int want_value)
+{
+  const tree exp = *expr_p;
+  const enum tree_code code = TREE_CODE (exp);
+  const tree op0 = TREE_OPERAND (exp, 0);
+  const int is_inc_op = (code == POSTINCREMENT_EXPR
+                         || code == PREINCREMENT_EXPR);
+  const enum tree_code inc_dec_code = is_inc_op ? PLUS_EXPR : MINUS_EXPR;
+  tree val, val_init_expr, inc_dec_expr, mod_expr;
+  val = upc_copy_value_to_tmp_var (&val_init_expr, op0);
+  inc_dec_expr = build_binary_op (loc, inc_dec_code,
+				  val, integer_one_node, 0);
+  mod_expr = build2 (MODIFY_EXPR, TREE_TYPE (val), op0, inc_dec_expr);
+  if (want_value)
+    {
+      if (code == PREDECREMENT_EXPR || code == PREINCREMENT_EXPR)
+	upc_genericize_modify_expr (loc, &mod_expr, 1);
+      else
+	{
+	  upc_genericize_modify_expr (loc, &mod_expr, 0);
+	  mod_expr = build2 (COMPOUND_EXPR, TREE_TYPE (val), mod_expr, val);
+	}
+    }
+  else
+    upc_genericize_modify_expr (loc, &mod_expr, 0);
+  *expr_p = build2 (COMPOUND_EXPR, TREE_TYPE (mod_expr),
+		    val_init_expr, mod_expr);
+}
+
+/* Simplify assignments to generic pointer-to-shared objects,
+   where an intermediate conversion appears on the right hand
+   side of the assignment.  Conversions from non-generic
+   pointer-to-shared to generic pointer-to-shared are preserved
+   up to the point of the final assignment, because a conversion
+   from generic pointer-to-shared to non-generic pointer-to-shared
+   may reset the phase in some cases, and we can only determine
+   that the conversion is unnecessary when we know the target
+   of the assignment expression.  */
+
+static void
+upc_strip_useless_generic_pts_cvt (tree *expr_p)
+{
+  while (TREE_CODE (*expr_p) == CONVERT_EXPR
+	 && POINTER_TYPE_P (TREE_TYPE (*expr_p))
+	 && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (*expr_p))))
+    {
+      *expr_p = TREE_OPERAND (*expr_p, 0);
+    }
+}
+
+/* Generify the MODIFY_EXPR node of the 'shared' value
+   pointed to by EXPR_P.  If the target of the assignment
+   is a UPC 'shared' reference, or an indirection via a UPC
+   pointer-to-shared, the assignment statement is rewritten into
+   a call to a runtime routine that does a remote 'put'. 
+   If WANT_VALUE is set, then return a compound expression
+   that evaluates to the value of the source operand.  */
+
+static void
+upc_genericize_modify_expr (location_t loc, tree *expr_p, int want_value)
+{
+  const tree dest = TREE_OPERAND (*expr_p, 0);
+  tree src = TREE_OPERAND (*expr_p, 1);
+  if (TREE_SHARED (dest)
+      || (TREE_TYPE (dest) && SHARED_TYPE_P (TREE_TYPE (dest))))
+    {
+      /* <shared dest> = <(shared|unshared) src> */
+      *expr_p = upc_expand_put (loc, dest, src, want_value);
+    }
+  else if (TREE_SHARED (src)
+	   || (TREE_TYPE (src) && SHARED_TYPE_P (TREE_TYPE (src))))
+    {
+      /* <unshared dest> = <shared src> */
+      /* We could check for BLKmode and in
+         that case perform a upc_memget() here.  */
+      src = upc_expand_get (loc, src, want_value);
+      TREE_OPERAND (*expr_p, 1) = src;
+    }
+}
+
+typedef struct walk_data_struct
+{
+  int want_value;
+} walk_data_t;
+typedef walk_data_t *walk_data_p;
+
+/* This routine is called to convert UPC specific constructs
+   into GENERIC.  It is called from 'walk_tree' as it traverses
+   the function body.
+   
+   The DATA parameter will point to a 'walk_data_t'
+   structure, which presently has a single field,
+   'want_value'.  If 'want_value' is non-zero, it
+   indicates that the value of the expression should
+   be returned.  */
+
+static tree
+upc_genericize_expr (tree *expr_p, int *walk_subtrees, void *data)
+{
+  const walk_data_p wdata = (walk_data_p) data;
+  const tree expr = *expr_p;
+  const enum tree_code code = TREE_CODE (expr);
+  const tree type = CODE_CONTAINS_STRUCT (code, TS_TYPED)
+                    ? TREE_TYPE (expr) : NULL;
+  const int want_value = wdata->want_value
+                         && !(type && VOID_TYPE_P (type));
+  const tree op0 = (TREE_CODE_LENGTH (code) >= 1)
+                   ? TREE_OPERAND (expr, 0) : NULL_TREE;
+  const tree type0 = (op0 != NULL_TREE) ? TREE_TYPE (op0) : NULL_TREE;
+  tree op1 = (TREE_CODE_LENGTH (code) >= 2)
+             ? TREE_OPERAND (expr, 1) : NULL_TREE;
+  tree type1 = (op1 != NULL_TREE) ? TREE_TYPE (op1) : NULL_TREE;
+  location_t saved_location = input_location;
+  location_t loc;
+  if (EXPR_HAS_LOCATION (expr))
+    input_location = EXPR_LOCATION (expr);
+  loc = input_location;
+  switch (code)
+    {
+    case UPC_FORALL_STMT:
+      upc_genericize_forall_stmt (expr_p);
+      break;
+
+    case UPC_SYNC_STMT:
+      upc_genericize_sync_stmt (loc, expr_p);
+      break;
+
+    case ADDR_EXPR:
+      if (POINTER_TYPE_P (type) && TREE_TYPE (type)
+	  && SHARED_TYPE_P (TREE_TYPE (type)))
+	upc_genericize_addr_expr (loc, expr_p);
+      break;
+
+    case ARRAY_REF:
+    case ARRAY_RANGE_REF:
+      if (op0 && TREE_SHARED (op0))
+	upc_genericize_array_ref (loc, expr_p);
+      break;
+
+    case BIT_FIELD_REF:
+    case COMPONENT_REF:
+      if (op0 && TREE_SHARED (op0))
+	upc_genericize_field_ref (loc, expr_p);
+      break;
+
+    case INDIRECT_REF:
+      if (type0 && (TREE_CODE (type0) == POINTER_TYPE)
+	  && SHARED_TYPE_P (TREE_TYPE (type0)))
+	upc_genericize_indirect_ref (loc, expr_p);
+      break;
+
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+      if (op0 && TREE_SHARED (op0))
+	upc_genericize_real_imag_ref (loc, expr_p);
+      break;
+
+    case VAR_DECL:
+      if (type && SHARED_TYPE_P (type))
+	upc_genericize_shared_var_ref (loc, expr_p);
+      break;
+
+    case VIEW_CONVERT_EXPR:
+      if (type && SHARED_TYPE_P (type))
+	TREE_TYPE (expr) = build_unshared_type (type);
+      gcc_assert (!TREE_SHARED (expr));
+      break;
+
+    case NON_LVALUE_EXPR:
+    case NOP_EXPR:
+    case CONVERT_EXPR:
+      /* Conversions to a UPC shared type aren't valid.
+         The front-end will sometimes convert
+         an expression operand to the type of another
+         operand.  If that operand has UPC shared type,
+         then the conversion target type is 'shared' qualified.
+         We unshare the type in order to produce a
+         valid tree.  */
+      if (type && SHARED_TYPE_P (type))
+	TREE_TYPE (expr) = build_unshared_type (type);
+      if (PTS_CVT_OP_P (expr))
+	upc_genericize_pts_cvt (loc, expr_p);
+      else if (code == CONVERT_EXPR && TREE_CODE (type) == INTEGER_TYPE
+	       && POINTER_TYPE_P (type0)
+	       && SHARED_TYPE_P (TREE_TYPE (type0)))
+	upc_genericize_pts_to_int_cvt (loc, expr_p);
+      break;
+
+    case EQ_EXPR:
+    case GE_EXPR:
+    case GT_EXPR:
+    case LE_EXPR:
+    case LT_EXPR:
+    case NE_EXPR:
+      if ((type0 && (TREE_CODE (type0) == POINTER_TYPE)
+	   && SHARED_TYPE_P (TREE_TYPE (type0)))
+	  || (type1 && (TREE_CODE (type1) == POINTER_TYPE)
+	      && SHARED_TYPE_P (TREE_TYPE (type1))))
+	upc_genericize_pts_cond_expr (loc, expr_p);
+      break;
+
+    case MINUS_EXPR:
+    case PLUS_EXPR:
+    case POINTER_PLUS_EXPR:
+      if ((type0 && (TREE_CODE (type0) == POINTER_TYPE)
+	   && SHARED_TYPE_P (TREE_TYPE (type0)))
+	  || (type1 && (TREE_CODE (type1) == POINTER_TYPE)
+	      && SHARED_TYPE_P (TREE_TYPE (type1))))
+	upc_genericize_pts_arith_expr (loc, expr_p);
+      break;
+
+    case MODIFY_EXPR:
+    case INIT_EXPR:
+      if (POINTER_TYPE_P (type0) && SHARED_TYPE_P (TREE_TYPE (type0))
+	  && VOID_TYPE_P (TREE_TYPE (type0))
+	  && TREE_CODE (op1) == CONVERT_EXPR
+	  && POINTER_TYPE_P (type1) && VOID_TYPE_P (TREE_TYPE (type1)))
+	{
+	  upc_strip_useless_generic_pts_cvt (&TREE_OPERAND (expr, 1));
+	  /* Recalculate OP1 and TYPE1 because TREE_OPERAND (expr, 1)
+	     was rewritten, above.  */
+	  op1 = TREE_OPERAND (expr, 1);
+	  type1 = TREE_TYPE (op1);
+	}
+      if ((op0 && (TREE_SHARED (op0)
+		   || (type0 && SHARED_TYPE_P (type0))))
+	  || (op1 && (TREE_SHARED (op1)
+		      || (type1 && SHARED_TYPE_P (type1)))))
+	upc_genericize_modify_expr (loc, expr_p, want_value);
+      break;
+
+    case POSTDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+    case PREINCREMENT_EXPR:
+      if ((op0 && TREE_SHARED (op0))
+	  || (type0 && (SHARED_TYPE_P (type0)
+			|| (POINTER_TYPE_P (type0)
+			    && SHARED_TYPE_P (TREE_TYPE (type0))))))
+	upc_genericize_shared_inc_dec_expr (loc, expr_p, want_value);
+      break;
+
+    case INTEGER_CST:
+      /* Integer constants can't be UPC 'shared' qualified.
+         The front-end can create integer constants with shared
+         type when changing the type to agree with that of another
+         expression operand.
+
+         Unsharing an integer constant requires special handling
+         because an internal hash table is kept on a type by type
+         basis.  Thus, we can't rewrite TREE_TYPE() directly.
+         We re-create the constant with its unshared type to
+         ensure that the hash table is updated.  */
+      if (type && SHARED_TYPE_P (type))
+	{
+	  const tree u_type = build_unshared_type (type);
+	  *expr_p = wide_int_to_tree (u_type, expr);
+	}
+      gcc_assert (!TREE_SHARED (expr));
+      break;
+
+    case REAL_CST:
+    case COMPLEX_CST:
+    case STRING_CST:
+    case VECTOR_CST:
+    case CONSTRUCTOR:
+      /* A constant's type can't be UPC 'shared' qualified.
+         The front-end will sometimes convert
+         an expression operand to the type of another
+         operand.  If that other operand has UPC shared type,
+         then the converted constant's type will be shared.
+         We unshare the type in order to produce a
+         valid constant.  */
+      if (type && SHARED_TYPE_P (type))
+	TREE_TYPE (expr) = build_unshared_type (type);
+      gcc_assert (!TREE_SHARED (expr));
+      break;
+
+    case STATEMENT_LIST:
+      upc_genericize_stmt_list (expr_p);
+      *walk_subtrees = 0;
+      break;
+
+    case COMPOUND_EXPR:
+      upc_genericize_compound_expr (expr_p, want_value);
+      *walk_subtrees = 0;
+      break;
+
+    case COND_EXPR:
+      upc_genericize_cond_expr (expr_p, want_value);
+      *walk_subtrees = 0;
+      break;
+
+    case DECL_EXPR:
+      upc_genericize_decl_expr (expr_p);
+      *walk_subtrees = 0;
+      break;
+
+    default:
+      gcc_assert (!TREE_SHARED (expr));
+      break;
+    }
+
+  /* Restore the input location.  */
+  input_location = saved_location;
+
+  /* After evaluating the current node, assert the
+     want_value flag so that all subtrees of this root node
+     will be fully evaluated.  */
+  if (!wdata->want_value)
+    wdata->want_value = 1;
+
+  /* Continue tree traversal.  */
+  return NULL_TREE;
+}
+
+/* Convert a compound expression into GENERIC form.
+   A compound expression contains two expressions to compute,
+   one (the LHS) followed by the other (the RHS).
+   The LHS value is ignored.  The RHS value is used.  */
+
+static void
+upc_genericize_compound_expr (tree *expr_p, int want_value)
+{
+  tree *lhs_p = &TREE_OPERAND (*expr_p, 0);
+  tree *rhs_p = &TREE_OPERAND (*expr_p, 1);
+  upc_genericize_walk (lhs_p, 0);
+  upc_genericize_walk (rhs_p, want_value);
+}
+
+/* Convert a conditional expression into GENERIC form.
+   A conditional expression contains three expressions
+   and is of the form expression ( ... ? ... : ...  in C).
+   The first operand is the condition, the second is
+   the then-value and the third is the else-value.  */
+
+static void
+upc_genericize_cond_expr (tree *expr_p, int want_value)
+{
+  tree *cond_p = &TREE_OPERAND (*expr_p, 0);
+  tree *then_p = &TREE_OPERAND (*expr_p, 1);
+  tree *else_p = &TREE_OPERAND (*expr_p, 2);
+  upc_genericize_walk (cond_p, 1);
+  if (*then_p)
+    upc_genericize_walk (then_p, want_value);
+  if (*else_p)
+    upc_genericize_walk (else_p, want_value);
+}
+
+/* Convert a declaration expression into GENERIC form.
+   A declaration expression is used to represent a local declaration.
+   The operand refers to the DECL associated with
+   the given declaration statement.  */
+
+static void
+upc_genericize_decl_expr (tree *expr_p)
+{
+  tree decl = DECL_EXPR_DECL (*expr_p);
+  tree *decl_init_p = &DECL_INITIAL (decl);
+  if (*decl_init_p)
+    upc_genericize_walk (decl_init_p, 0);
+}
+
+/* Convert the tree rooted at EXPR_P into GENERIC.
+   WANT_VALUE is the initial value the flag that
+   upc_genericize_expr() will query to determine
+   whether the expression node should return a value.
+   NOTE: EXPR_P can point to any kind of expression node.  */
+
+static void
+upc_genericize_walk (tree *expr_p, int want_value)
+{
+  walk_data_t wdata;
+  wdata.want_value = want_value;
+  (void) walk_tree (expr_p, upc_genericize_expr, &wdata, NULL);
+}
+
+/* Convert a statement list to GENERIC.  */
+
+static void
+upc_genericize_stmt_list (tree *stmt_list_p)
+{
+  tree_stmt_iterator s = tsi_start (*stmt_list_p);
+  while (!tsi_end_p (s))
+    {
+      tree *stmt_p = tsi_stmt_ptr (s);
+      upc_genericize_walk (stmt_p, 0);
+      tsi_next (&s);
+    }
+}
+
+/* Convert the function body identified by BODY_P into GENERIC.
+   Traverse the function body by calling upc_genericize_walk().
+   Initially assert WANT_VALUE as FALSE.  */
+
+static void
+upc_genericize_body (tree *body_p, tree fndecl)
+{
+  location_t saved_location = input_location;
+
+  timevar_push (TV_TREE_UPC_GENERICIZE);
+
+  input_location = DECL_SOURCE_LOCATION (fndecl);
+
+  upc_genericize_walk (body_p, /* want_value */ 0);
+
+  timevar_pop (TV_TREE_UPC_GENERICIZE);
+
+  input_location = saved_location;
+}
+
+/* Convert the tree representation of FNDECL, along with all nested
+   functions defined within it, into the GENERIC form.  */
+
+static void
+upc_genericize_function (tree fndecl)
+{
+  struct cgraph_node *cgn;
+
+  gcc_assert (DECL_SAVED_TREE (fndecl));
+
+  if (DECL_STRUCT_FUNCTION (fndecl))
+    push_cfun (DECL_STRUCT_FUNCTION (fndecl));
+  else
+    push_struct_function (fndecl);
+
+  upc_genericize_body (&DECL_SAVED_TREE (fndecl), fndecl);
+
+  if (flag_upc_instrument_functions
+      && !DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl)
+      && !flag_instrument_functions_exclude_p (fndecl))
+    {
+      upc_instrument_func (fndecl);
+    }
+
+  pop_cfun ();
+
+  cgn = cgraph_node::get_create (fndecl);
+  for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
+    upc_genericize_function (cgn->decl);
+}
+
+/* If the accumulated UPC initialization statement list is
+   not empty, then build (and define) the per-file UPC
+   global initialization function.  */
+
+static void
+upc_write_init_func (void)
+{
+  if (upc_init_stmt_list)
+    {
+      int pupc_mode = disable_pupc_mode ();
+      lang_hooks.upc.build_init_func (upc_init_stmt_list);
+      set_pupc_mode (pupc_mode);
+      upc_init_stmt_list = NULL;
+    }
+}
+
+/* Convert the tree representation of FNDECL built by the UPC front-end
+   into the GENERIC form.  Then call the "C" genericize hook.  */
+
+void
+upc_genericize (tree fndecl)
+{
+  upc_genericize_function (fndecl);
+}
+
+/* Return TRUE if either DECL's type is a UPC shared type, or if
+   the value on the right-hand-side of the initialization has a
+   type that is a UPC shared type.  Initializations that meet
+   this criteria generally need to be actively initialized
+   at runtime.  */
+
+int
+upc_check_decl_init (tree decl, tree init)
+{
+  tree init_type;
+  int is_shared_var_decl_init;
+  int is_decl_init_with_shared_addr_refs;
+  int is_upc_decl;
+  if (!(decl && init && TREE_TYPE (decl) && TREE_TYPE (init)))
+    return 0;
+  if ((TREE_CODE (decl) == ERROR_MARK)
+      || (TREE_CODE (TREE_TYPE (decl)) == ERROR_MARK)
+      || (TREE_CODE (init) == ERROR_MARK)
+      || (TREE_CODE (TREE_TYPE (init)) == ERROR_MARK))
+    return 0;
+  init_type = TREE_TYPE (init);
+  is_shared_var_decl_init = (TREE_CODE (decl) == VAR_DECL)
+    && TREE_TYPE (decl) && SHARED_TYPE_P (TREE_TYPE (decl));
+  is_decl_init_with_shared_addr_refs = TREE_STATIC (decl)
+    && upc_contains_pts_refs_p (init_type);
+  is_upc_decl = (is_shared_var_decl_init
+		 || is_decl_init_with_shared_addr_refs);
+  return is_upc_decl;
+}
+
+/* Add the initialization statement:
+     DECL = INIT;
+   onto a list, `upc_init_stmt_list', which collects
+   initializations that must be made at runtime.
+
+   This runtime initialization necessary because, in general, UPC
+   shared addresses are not known, or cannot be easily generated
+   at compile-time.  */
+
+void
+upc_decl_init (tree decl, tree init)
+{
+  tree init_stmt;
+  if (TREE_CODE (init) == ERROR_MARK)
+    return;
+  if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
+    {
+      error ("initialization of UPC shared arrays "
+	     "is currently not supported");
+      return;
+    }
+  if (!upc_init_stmt_list)
+    upc_init_stmt_list = alloc_stmt_list ();
+  init_stmt = build2 (INIT_EXPR, void_type_node, decl, init);
+  append_to_statement_list_force (init_stmt, &upc_init_stmt_list);
+}
+
+/* Write out the UPC global initialization function, if required
+   and call upc_genericize_finish() to free the hash table
+   used to track the "shadow" variables that are created
+   to generate addresses of UPC shared variables.
+
+   This function is called from c_common_parse_file(), just after
+   parsing the main source file.  */
+
+void
+upc_write_global_declarations (void)
+{
+  upc_write_init_func ();
+  upc_genericize_finish ();
+}
+
+/* Clean up resources used by the UPC genericize pass.  */
+
+void
+upc_genericize_finish (void)
+{
+  upc_free_unshared_var_table ();
+  upc_init_stmt_list = NULL;
+}
+
+/* Initialize/allocate resources used by the UPC genericize pass.  */
+
+void
+upc_genericize_init (void)
+{
+  unshared_vars_map = new int_tree_htab_type (10);
+  upc_init_stmt_list = NULL;
+}
+
+#include "gt-c-c-upc-low.h"
Index: gcc/c/c-upc-low.h
===================================================================
--- gcc/c/c-upc-low.h	(.../trunk)	(revision 0)
+++ gcc/c/c-upc-low.h	(.../branches/gupc)	(revision 231080)
@@ -0,0 +1,33 @@ 
+/* c-upc-low.h: declarations for upc-low.c
+   Copyright (C) 2006-2015 Free Software Foundation, Inc.
+   Contributed by Gary Funck <gary@intrepid.com>
+     and Nenad Vukicevic <nenad@intrepid.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_C_UPC_LOW_H
+#define GCC_C_UPC_LOW_H 1
+
+extern void upc_genericize (tree);
+extern void upc_genericize_init (void);
+extern void upc_genericize_finish (void);
+
+extern int upc_check_decl_init (tree, tree);
+extern void upc_decl_init (tree, tree);
+extern void upc_write_global_declarations (void);
+
+#endif /* !GCC_C_UPC_LOW_H */
Index: gcc/c/c-upc-pts-ops.c
===================================================================
--- gcc/c/c-upc-pts-ops.c	(.../trunk)	(revision 0)
+++ gcc/c/c-upc-pts-ops.c	(.../branches/gupc)	(revision 231080)
@@ -0,0 +1,585 @@ 
+/* c-upc-pts-ops.c: implement UPC pointer-to-shared-operations.
+   Copyright (C) 2001-2015 Free Software Foundation, Inc.
+   Contributed by Gary Funck <gary@intrepid.com>
+     and Nenad Vukicevic <nenad@intrepid.com>.
+   Based on original implementation
+     by Jesse M. Draper <jdraper@super.org>
+     and William W. Carlson <wwc@super.org>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "alias.h"
+#include "fold-const.h"
+#include "stringpool.h"
+#include "c-tree.h"
+#include "langhooks.h"
+#include "gimplify.h"
+#include "c-upc.h"
+#include "c-upc-gasp.h"
+#include "c-upc-pts-ops.h"
+#include "c-upc-rts-names.h"
+
+/* Build the internal representation of UPC's pointer-to-shared type.  */
+
+void
+upc_pts_init (void)
+{
+  tree shared_void_type, shared_char_type;
+  lang_hooks.upc.pts_init_type ();
+  shared_void_type = c_build_qualified_type_1 (void_type_node,
+                                               TYPE_QUAL_SHARED,
+					       NULL_TREE);
+  upc_pts_type_node = build_pointer_type (shared_void_type);
+  shared_char_type = c_build_qualified_type_1 (char_type_node,
+                                               TYPE_QUAL_SHARED,
+					       size_zero_node);
+  upc_char_pts_type_node = build_pointer_type (shared_char_type);
+  upc_null_pts_node = upc_pts_build_value (UNKNOWN_LOCATION,
+                                                  upc_pts_type_node,
+				                  integer_zero_node,
+						  integer_zero_node,
+				                  integer_zero_node);
+}
+
+/* Called to expand a UPC specific constant into something the
+   backend can handle.  Upon return a UPC pointer-to-shared will be
+   seen as the representation type of a UPC pointer-to-shared, with
+   individual (thread, phase, and virtual address) fields.  */
+
+tree
+upc_pts_build_constant (location_t loc, tree c)
+{
+  tree result = c;
+  if (upc_pts_is_valid_p (c))
+    {
+      const enum tree_code code = TREE_CODE (c);
+      if (!((code == VIEW_CONVERT_EXPR || code == NOP_EXPR)
+	    && (TREE_CODE (TREE_OPERAND (c, 0)) == CONSTRUCTOR)
+	    && (TREE_TYPE (TREE_OPERAND (c, 0)) == upc_pts_rep_type_node)))
+	{
+	  const tree val = build1 (VIEW_CONVERT_EXPR, upc_pts_rep_type_node,
+				   save_expr (c));
+	  const tree p_t = TREE_TYPE (upc_phase_field_node);
+	  const tree t_t = TREE_TYPE (upc_thread_field_node);
+	  const tree v_t = TREE_TYPE (upc_vaddr_field_node);
+	  const tree vaddr = build3 (COMPONENT_REF, v_t, val,
+				     upc_vaddr_field_node, NULL_TREE);
+	  const tree thread = build3 (COMPONENT_REF, t_t, val,
+				      upc_thread_field_node, NULL_TREE);
+	  const tree phase = build3 (COMPONENT_REF, p_t, val,
+				     upc_phase_field_node, NULL_TREE);
+	  result = upc_pts_build_value (loc, TREE_TYPE (c),
+					       vaddr, thread, phase);
+
+	}
+    }
+  return result;
+}
+
+/* Build a constructor of the form {phase, thread, vaddr}.  */
+
+tree
+upc_pts_build_value (location_t loc ATTRIBUTE_UNUSED, tree type,
+		     tree vaddr, tree thread, tree phase)
+{
+  tree elts, result;
+  const int is_const = TREE_CONSTANT (vaddr)
+    && TREE_CONSTANT (thread) && TREE_CONSTANT (phase);
+  vaddr = fold_convert (TREE_TYPE (upc_vaddr_field_node), vaddr);
+  thread = fold_convert (TREE_TYPE (upc_thread_field_node), thread);
+  phase = fold_convert (TREE_TYPE (upc_phase_field_node), phase);
+  elts = tree_cons (upc_phase_field_node, phase, NULL_TREE);
+  elts = tree_cons (upc_thread_field_node, thread, elts);
+  elts = tree_cons (upc_vaddr_field_node, vaddr, elts);
+  result = build_constructor_from_list (upc_pts_rep_type_node, elts);
+  TREE_CONSTANT (result) = is_const;
+
+  /* Wrap the constructor into the specified pointer to shared type.  */
+  result = build1 (VIEW_CONVERT_EXPR, type, result);
+  result = fold (result);
+  TREE_CONSTANT (result) = is_const;
+  /* Force all shared constant pointer values to memory.  */
+  TREE_STATIC (result) = is_const;
+  return result;
+}
+
+/* Return TRUE if EXP is a null UPC pointer-to-shared.  */
+
+int
+upc_pts_is_null_p (tree exp)
+{
+  int result = 0;
+  if (exp && upc_pts_is_valid_p (exp))
+    {
+      tree value;
+      for (value = exp;
+	   TREE_CODE (value) == NOP_EXPR
+	   || TREE_CODE (value) == CONVERT_EXPR
+	   || TREE_CODE (value) == VIEW_CONVERT_EXPR
+	   || TREE_CODE (value) == NON_LVALUE_EXPR;
+	   value = TREE_OPERAND (value, 0)) /* loop */ ;
+      if ((TREE_CODE (value) == CONSTRUCTOR)
+	  && (TREE_TYPE (value) == upc_pts_rep_type_node)
+	  && TREE_CONSTANT (value))
+	{
+	  vec<constructor_elt, va_gc> *c = CONSTRUCTOR_ELTS (value);
+	  /* Check that all the fields are zero, independent
+	     of whether vaddr comes first/last.  */
+	  const tree phase_or_vaddr = (*c)[0].value;
+	  const tree thread = (*c)[1].value;
+	  const tree vaddr_or_phase = (*c)[2].value;
+	  result = integer_zerop (phase_or_vaddr) && integer_zerop (thread)
+	           && integer_zerop (vaddr_or_phase);
+	}
+    }
+  return result;
+}
+
+/* Given, EXP, whose type must be the UPC pointer-to-shared
+   representation type, isolate the thread field,
+   and return it.  Caller must insure that EXP is a
+   stable reference, if required.  */
+
+tree
+upc_pts_build_threadof (location_t loc ATTRIBUTE_UNUSED, tree exp)
+{
+  tree affinity;
+  tree type = TREE_TYPE (upc_thread_field_node);
+  gcc_assert (TREE_TYPE (exp) == upc_pts_rep_type_node);
+  affinity = build3 (COMPONENT_REF, type, exp,
+		     upc_thread_field_node, NULL_TREE);
+  affinity = fold_convert (sizetype, affinity);
+  return affinity;
+}
+
+/* Rewrite EXP, an expression involving addition of an
+   integer to a UPC pointer-to-shared, into representation-specific
+   lower level operations.  */
+
+tree
+upc_pts_build_sum (location_t loc, tree exp)
+{
+  const tree op0 = TREE_OPERAND (exp, 0);
+  const tree op1 = TREE_OPERAND (exp, 1);
+  const enum tree_code op0_code = TREE_CODE (TREE_TYPE (op0));
+  const tree targ_type = TREE_TYPE (TREE_TYPE (exp));
+  const tree elem_type = strip_array_types (targ_type);
+  const tree elem_size = !VOID_TYPE_P (elem_type)
+    ? size_in_bytes (elem_type) : integer_one_node;
+  const tree block_factor = get_block_factor (elem_type);
+  const int has_phase = !(integer_zerop (block_factor)
+			  || integer_onep (block_factor));
+  const tree elem_per_block = block_factor;
+  const tree ptrop = (op0_code == POINTER_TYPE) ? op0 : op1;
+  const tree intop = (op0_code == POINTER_TYPE) ? op1 : op0;
+  const tree index = save_expr (intop);
+  const tree ptrop_as_pts_rep = fold (build1 (VIEW_CONVERT_EXPR,
+					      upc_pts_rep_type_node,
+					      ptrop));
+  const tree sptrop = save_expr (ptrop_as_pts_rep);
+  const tree p_t = TREE_TYPE (upc_phase_field_node);
+  const tree t_t = TREE_TYPE (upc_thread_field_node);
+  const tree v_t = TREE_TYPE (upc_vaddr_field_node);
+  tree n_threads = upc_num_threads ();
+  tree old_phase, old_thread, old_vaddr;
+  tree phase, thread, vaddr;
+  tree tincr, t1, t2;
+  tree result;
+
+  old_phase = build3 (COMPONENT_REF, p_t, sptrop,
+		      upc_phase_field_node, NULL_TREE);
+  old_thread = build3 (COMPONENT_REF, t_t, sptrop,
+		       upc_thread_field_node, NULL_TREE);
+  old_vaddr = build3 (COMPONENT_REF, v_t, sptrop,
+		      upc_vaddr_field_node, NULL_TREE);
+  thread = old_thread;
+  phase = old_phase;
+  if (VOID_TYPE_P (targ_type) || integer_zerop (block_factor))
+    {
+      vaddr = build_binary_op (loc, PLUS_EXPR, old_vaddr,
+			       build_binary_op (loc, MULT_EXPR,
+						index, elem_size, 0), 0);
+    }
+  else
+    {
+      /* Make sure n_threads is a signed integer to ensure
+         that the FLOOR_MOD and FLOOR_DIV operations below are performed
+         with signed operations.  */
+      if (TYPE_UNSIGNED (TREE_TYPE (n_threads)))
+	n_threads = convert (integer_type_node, n_threads);
+      if (has_phase)
+	{
+	  tree nt_elems;
+	  tree phase_diff;
+	  old_phase = save_expr (old_phase);
+	  /* tincr = old_thread * elem_per_block + old_phase + index; */
+	  tincr = build_binary_op (loc, PLUS_EXPR,
+		      build_binary_op (loc, PLUS_EXPR,
+		          build_binary_op (loc, MULT_EXPR,
+				           old_thread, elem_per_block, 0),
+			  old_phase, 0),
+		      index, 0);
+	  if (TYPE_UNSIGNED (TREE_TYPE (tincr)))
+	    tincr = convert (integer_type_node, tincr);
+	  /* nt_elems = n_threads * elem_per_block; */
+	  nt_elems = build_binary_op (loc, MULT_EXPR, n_threads,
+				      elem_per_block, 0);
+	  if (TYPE_UNSIGNED (TREE_TYPE (nt_elems)))
+	    nt_elems = convert (integer_type_node, nt_elems);
+	  /* floor_divmod (tincr, nt_elems, &t1, &t2);  */
+	  t1 = build_binary_op (loc, FLOOR_DIV_EXPR, tincr, nt_elems, 0);
+	  t2 = build_binary_op (loc, FLOOR_MOD_EXPR, tincr, nt_elems, 0);
+	  t2 = save_expr (t2);
+	  /* thread = t2 / elem_per_block; */
+	  thread = build_binary_op (loc, TRUNC_DIV_EXPR, t2,
+				    elem_per_block, 0);
+	  /* phase = t2 % elem_per_block; */
+	  phase = build_binary_op (loc, TRUNC_MOD_EXPR, t2,
+				   elem_per_block, 0);
+	  phase_diff =
+	    build_binary_op (loc, MINUS_EXPR, phase, old_phase, 0);
+	  /* vaddr = old_vaddr + (t1 * elem_per_block + phase_diff)
+				 * elem_size; */
+	  vaddr = build_binary_op (loc, PLUS_EXPR,
+				   old_vaddr,
+				   build_binary_op (loc, MULT_EXPR,
+				       build_binary_op (loc, PLUS_EXPR,
+				           build_binary_op (loc, MULT_EXPR,
+						     t1, elem_per_block, 0),
+					   phase_diff, 0),
+				       elem_size, 0), 0);
+	}
+      else
+	{
+	  /* tincr = old_thread * elem_per_block + index; */
+	  tincr = build_binary_op (loc, PLUS_EXPR,
+				   build_binary_op (loc, MULT_EXPR,
+						    old_thread,
+						    elem_per_block, 0),
+				   index, 0);
+	  if (TYPE_UNSIGNED (TREE_TYPE (tincr)))
+	    tincr = convert (integer_type_node, tincr);
+	  /* floor_divmod (tincr, n_threads, &t1, &t2);  */
+	  t1 = build_binary_op (loc, FLOOR_DIV_EXPR, tincr, n_threads, 0);
+	  t2 = build_binary_op (loc, FLOOR_MOD_EXPR, tincr, n_threads, 0);
+	  /* vaddr = old_vaddr + t1 * elem_size; */
+	  vaddr = build_binary_op (loc, PLUS_EXPR, old_vaddr,
+				   build_binary_op (loc, MULT_EXPR, t1,
+						    elem_size, 0), 0);
+	  /* thread = t2;  */
+	  thread = t2;
+	}
+    }
+  result =
+    upc_pts_build_value (loc, TREE_TYPE (exp), vaddr, thread, phase);
+  return result;
+}
+
+/* Expand the expression EXP, which calculates the difference
+   between two UPC pointers-to-shared.  */
+
+tree
+upc_pts_build_diff (location_t loc, tree exp)
+{
+  tree op0 = TREE_OPERAND (exp, 0);
+  tree op1 = TREE_OPERAND (exp, 1);
+  const tree result_type = ptrdiff_type_node;
+  const tree p_t = TREE_TYPE (upc_phase_field_node);
+  const tree t_t = TREE_TYPE (upc_thread_field_node);
+  const tree v_t = TREE_TYPE (upc_vaddr_field_node);
+  const tree target_type = TREE_TYPE (TREE_TYPE (op0));
+  const tree n_threads = upc_num_threads ();
+  const tree elem_size = convert (ssizetype, size_in_bytes (target_type));
+  const tree block_factor = get_block_factor (target_type);
+  tree thread0, thread1, thread_diff;
+  tree phase_diff;
+  tree off0, off1, offset_diff, elem_diff;
+  tree result;
+
+  /* The two pointers must both point to shared objects, and we
+     have to perform the reverse of addition on UPC pointers-to-shared */
+
+  if ((SHARED_TYPE_P (target_type)
+       && !SHARED_TYPE_P (TREE_TYPE (TREE_TYPE (op1))))
+      || (SHARED_TYPE_P (TREE_TYPE (TREE_TYPE (op1)))
+	  && !SHARED_TYPE_P (target_type)))
+    {
+      error ("attempt to take the difference of a UPC pointer-to-shared "
+	 "and a local pointer");
+      return error_mark_node;
+    }
+  op0 = save_expr (op0);
+  op1 = save_expr (op1);
+  op0 = build1 (VIEW_CONVERT_EXPR, upc_pts_rep_type_node, op0);
+  op1 = build1 (VIEW_CONVERT_EXPR, upc_pts_rep_type_node, op1);
+  off0 = build3 (COMPONENT_REF, v_t, op0, upc_vaddr_field_node, NULL_TREE);
+  off1 = build3 (COMPONENT_REF, v_t, op1, upc_vaddr_field_node, NULL_TREE);
+  /* Convert offset fields into ptrdiff_t types so that the
+     result of the difference comes out as a signed type.  */
+  off0 = convert (result_type, off0);
+  off1 = convert (result_type, off1);
+  offset_diff = build_binary_op (loc, MINUS_EXPR, off0, off1, 0);
+  elem_diff =
+    build_binary_op (loc, EXACT_DIV_EXPR, offset_diff, elem_size, 0);
+  if (integer_zerop (block_factor))
+    {
+      return elem_diff;
+    }
+  thread0 = convert (ssizetype,
+		     build3 (COMPONENT_REF, t_t, op0,
+			     upc_thread_field_node, NULL_TREE));
+  thread1 = convert (ssizetype,
+		     build3 (COMPONENT_REF, t_t, op1,
+			     upc_thread_field_node, NULL_TREE));
+  thread_diff = build_binary_op (loc, MINUS_EXPR, thread0, thread1, 0);
+  phase_diff = integer_zero_node;
+  if (!tree_int_cst_equal (block_factor, integer_one_node))
+    {
+      tree phase0 = convert (ssizetype,
+			     build3 (COMPONENT_REF, p_t, op0,
+				     upc_phase_field_node, NULL_TREE));
+      tree phase1 = convert (ssizetype,
+			     build3 (COMPONENT_REF, p_t, op1,
+				     upc_phase_field_node, NULL_TREE));
+      phase_diff =
+	save_expr (build_binary_op (loc, MINUS_EXPR, phase0, phase1, 0));
+    }
+  /* The expression below calculates the following:
+     (elem_diff - phase_diff) * THREADS
+     + (thread_diff * block_factor) + phase_diff; */
+  result = build_binary_op (loc, PLUS_EXPR,
+			    build_binary_op (loc, PLUS_EXPR,
+			        build_binary_op (loc, MULT_EXPR,
+				    build_binary_op (loc, MINUS_EXPR,
+					           elem_diff, phase_diff, 0),
+				    n_threads, 0),
+			        build_binary_op (loc, MULT_EXPR,
+						 thread_diff,
+						 block_factor, 0), 0),
+			    phase_diff, 0);
+  result = fold_convert (result_type, result);
+  return result;
+}
+
+/* Handle conversions between UPC pointers-to-shared and
+   local pointers, or between UPC pointers-to-shared which
+   have differing block factors.  */
+
+tree
+upc_pts_build_cvt (location_t loc, tree exp)
+{
+  const tree type = TREE_TYPE (exp);
+  const tree p_t = ptr_type_node;
+  const tree t_t = TREE_TYPE (upc_thread_field_node);
+  const tree ptr = TREE_OPERAND (exp, 0);
+  tree tt1, tt2, b1, b2;
+  tree result = exp;
+
+  tt1 = TREE_TYPE (TREE_TYPE (exp));
+  tt2 = TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+  b1 = get_block_factor (tt1);
+  b2 = get_block_factor (tt2);
+  if (SHARED_TYPE_P (tt1) != SHARED_TYPE_P (tt2))
+    {
+      if (SHARED_TYPE_P (tt1))
+	{
+	  /* Error: local -> shared */
+	  result = error_mark_node;
+	}
+      else
+	{
+	  /* shared -> local */
+          int doprofcall = flag_upc_debug
+                           || (flag_upc_instrument && get_upc_pupc_mode ());
+	  const char *libfunc_name =
+	    doprofcall ? UPC_GETADDRG_LIBCALL : UPC_GETADDR_LIBCALL;
+	  tree src = build1 (NOP_EXPR, upc_pts_rep_type_node,
+			     TREE_OPERAND (exp, 0));
+	  tree libfunc, lib_args, lib_call;
+	  libfunc = identifier_global_value (get_identifier (libfunc_name));
+	  if (!libfunc)
+	    internal_error ("UPC runtime library function %s not found",
+			    libfunc_name);
+	  lib_args = tree_cons (NULL_TREE, src, NULL_TREE);
+	  if (doprofcall)
+	    lib_args =
+	      upc_gasp_add_src_args (lib_args,
+	                             LOCATION_FILE (input_location),
+				     LOCATION_LINE (input_location));
+	  lib_call = build_function_call (loc, libfunc, lib_args);
+	  result = build1 (VIEW_CONVERT_EXPR, type, lib_call);
+	}
+    }
+  else if ((SHARED_TYPE_P (tt1) && !VOID_TYPE_P (tt1))
+	   && !(integer_zerop (b1) && integer_zerop (b2)))
+    {
+      /* below, we handle the case of conversions to non-generic
+         shared types.  If the target is a generic type, we can
+         safely use the source value directly.  */
+      tree s1 = TYPE_SIZE (tt1);
+      tree s2 = TYPE_SIZE (tt2);
+      /* normalize block sizes, so that [0] => NULL */
+      if (integer_zerop (b1))
+	b1 = NULL;
+      if (integer_zerop (b2))
+	b2 = NULL;
+      /* normalize type size so that 0 => NULL */
+      if (s1 && integer_zerop (s1))
+	s1 = NULL;
+      if (s2 && integer_zerop (s2))
+	s2 = NULL;
+      /* If the source type is an array type, then bypass
+         the check for equal type sizes.  This arises when
+	 an array is implicitly converted to a pointer to
+	 the element type.  */
+      if ((TREE_CODE (tt1) != ARRAY_TYPE)
+          && (TREE_CODE (tt2) == ARRAY_TYPE))
+        {
+          const tree elem_type1 = strip_array_types (tt1);
+          const tree elem_type2 = strip_array_types (tt2);
+	  if (TYPE_MAIN_VARIANT (elem_type1)
+	      == TYPE_MAIN_VARIANT (elem_type2))
+	    s2 = s1;
+        }
+      /* If the source type is a not a generic pointer to shared, and
+         either its block size or type size differs from the target,
+         then the result must have zero phase.  If the source type is
+         a generic pointer to shared and the target type is a pointer
+         to a shared type with either an indefinite block size, or
+         a block size of one, then the resulting value must have a
+         phase of zero.  */
+      if ((!VOID_TYPE_P (tt2)
+	   && !(tree_int_cst_equal (b1, b2) && tree_int_cst_equal (s1, s2)))
+	  || (VOID_TYPE_P (tt2)
+	      && ((b1 == NULL)
+		  || tree_int_cst_equal (b1, integer_one_node))))
+	{
+	  const tree ptr_as_pts_rep = fold (build1 (VIEW_CONVERT_EXPR,
+						    upc_pts_rep_type_node,
+						    ptr));
+	  const tree sptr = save_expr (ptr_as_pts_rep);
+	  const tree ptr_with_zero_phase =
+	    upc_pts_build_value (loc, type,
+					build3 (COMPONENT_REF, p_t, sptr,
+						upc_vaddr_field_node,
+						NULL_TREE),
+					build3 (COMPONENT_REF, t_t, sptr,
+						upc_thread_field_node,
+						NULL_TREE),
+					integer_zero_node);
+	  result = ptr_with_zero_phase;
+	}
+    }
+  return result;
+}
+
+
+/* Expand the expression EXP, which is a comparison between two
+   UPC pointers-to-shared.
+
+   Per 6.4.2p6:
+   Two compatible pointers-to-shared which point to the same object
+   (i.e.  having the same address and thread components) shall compare
+   as equal according to == and !=, regardless of whether the phase
+   components match.
+
+   Thus, for the equality comparison, the phase component of the
+   pointers is omitted from the comparison.  In that case,
+   rewrite the pointer-to-shared comparison operation into a
+   field by field comparison the vaddr and thread fields
+   of the UPC pointer-to-shared operands.
+
+   If the bit-wise comparison cannot be performed, then the difference
+   between the pointers is compared to zero.  */
+
+tree
+upc_pts_build_cond_expr (location_t loc, tree exp)
+{
+  tree result;
+  const enum tree_code code = TREE_CODE (exp);
+  const int is_eq_op = (code == EQ_EXPR || code == NE_EXPR);
+  tree op0 = TREE_OPERAND (exp, 0);
+  tree op1 = TREE_OPERAND (exp, 1);
+  const tree type0 = TREE_TYPE (op0);
+  const tree type1 = TREE_TYPE (op1);
+  gcc_assert (POINTER_TYPE_P (type0));
+  gcc_assert (POINTER_TYPE_P (type1));
+  {
+    const tree ttype0 = TREE_TYPE (type0);
+    const tree ttype1 = TREE_TYPE (type1);
+    const tree elem_type0 = strip_array_types (ttype0);
+    const tree elem_type1 = strip_array_types (ttype1);
+    gcc_assert (TREE_SHARED (elem_type0));
+    gcc_assert (TREE_SHARED (elem_type1));
+    /* For == and !=, per 6.4.2p6 only compare (vaddr, thread).  */ 
+    if (is_eq_op)
+      {
+	const tree t_t = TREE_TYPE (upc_thread_field_node);
+	const tree v_t = TREE_TYPE (upc_vaddr_field_node);
+	const enum tree_code code0 = TREE_CODE (op0);
+	const enum tree_code code1 = TREE_CODE (op1);
+	const enum tree_code tcode = (code == EQ_EXPR)
+	  ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR;
+	if (code0 == VIEW_CONVERT_EXPR
+	    && TREE_TYPE (TREE_OPERAND (op0, 0)) == upc_pts_rep_type_node)
+	  op0 = TREE_OPERAND (op0, 0);
+	else
+	  op0 = build1 (VIEW_CONVERT_EXPR, upc_pts_rep_type_node, op0);
+	if (code1 == VIEW_CONVERT_EXPR
+	    && TREE_TYPE (TREE_OPERAND (op1, 0)) == upc_pts_rep_type_node)
+	  op1 = TREE_OPERAND (op1, 0);
+	else
+	  op1 = build1 (VIEW_CONVERT_EXPR, upc_pts_rep_type_node, op1);
+	op0 = save_expr (op0);
+	op1 = save_expr (op1);
+	{
+	  const tree off0 = build3 (COMPONENT_REF, v_t, op0,
+				    upc_vaddr_field_node, NULL_TREE);
+	  const tree off1 = build3 (COMPONENT_REF, v_t, op1,
+				    upc_vaddr_field_node, NULL_TREE);
+	  const tree off_cmp = build_binary_op (loc, code, off0, off1, 0);
+	  const tree thread0 = build3 (COMPONENT_REF, t_t, op0,
+				       upc_thread_field_node, NULL_TREE);
+	  const tree thread1 = build3 (COMPONENT_REF, t_t, op1,
+				       upc_thread_field_node, NULL_TREE);
+	  const tree thread_cmp =
+	    build_binary_op (loc, code, thread0, thread1, 0);
+	  result = build_binary_op (loc, tcode, off_cmp, thread_cmp, 0);
+	  /* Remove possible C_MAYBE_EXPR operands.  */
+	  result = c_fully_fold (result, 0, NULL);
+	  result = gimple_boolify (result);
+	  result = fold_convert (TREE_TYPE (exp), result);
+	}
+      }
+    else
+      {
+	const tree ptr_diff =
+	  build_binary_op (loc, MINUS_EXPR, op0, op1, 0);
+	op0 = ptr_diff;
+	op1 = build_int_cst (TREE_TYPE (op0), 0);
+	TREE_OPERAND (exp, 0) = op0;
+	TREE_OPERAND (exp, 1) = op1;
+	result = exp;
+      }
+  }
+  return result;
+}
Index: gcc/c/c-upc-pts-ops.h
===================================================================
--- gcc/c/c-upc-pts-ops.h	(.../trunk)	(revision 0)
+++ gcc/c/c-upc-pts-ops.h	(.../branches/gupc)	(revision 231080)
@@ -0,0 +1,35 @@ 
+/* Define UPC pointer-to-shared representation-independent operations
+   Copyright (C) 2008-2015 Free Software Foundation, Inc.
+   Contributed by Gary Funck <gary@intrepid.com>
+     and Nenad Vukicevic <nenad@intrepid.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_C_UPC_PTS_OPS_H
+#define GCC_C_UPC_PTS_OPS_H 1
+
+extern tree upc_pts_build_cond_expr (location_t, tree);
+extern tree upc_pts_build_constant (location_t, tree);
+extern tree upc_pts_build_cvt (location_t, tree);
+extern tree upc_pts_build_diff (location_t, tree);
+extern tree upc_pts_build_sum (location_t, tree);
+extern tree upc_pts_build_threadof (location_t, tree);
+extern tree upc_pts_build_value (location_t, tree, tree, tree, tree);
+extern void upc_pts_init (void);
+extern int upc_pts_is_null_p (tree);
+
+#endif /* !GCC_C_UPC_PTS_OPS_H */
Index: gcc/c/c-upc-rts-names.h
===================================================================
--- gcc/c/c-upc-rts-names.h	(.../trunk)	(revision 0)
+++ gcc/c/c-upc-rts-names.h	(.../branches/gupc)	(revision 231080)
@@ -0,0 +1,64 @@ 
+/* Define compiler-visible UPC runtime entry points and variables.
+   Copyright (C) 2004-2015 Free Software Foundation, Inc.
+   Contributed by Gary Funck <gary@intrepid.com>
+     and Nenad Vukicevic <nenad@intrepid.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_C_C_UPC_RTS_NAMES_H
+#define GCC_C_C_UPC_RTS_NAMES_H 1
+
+/* Name of initialization routine that is called to initialize
+   shared variables and calculate shared address.  Both of these
+   operations must be performed at runtime before UPC's main
+   program is called.  */
+#define UPC_INIT_DECLS_FUNC "__upc_init_decls"
+
+/* Name of runtime variable that is used by the code generated
+   for the 'upc_forall' statement to implement nested upc_forall
+   semantics.  Per the language specification, a dynamically nested
+   upc_forall statement with an affinity clause will operate
+   as if "continue" had been supplied for the affinity clause.  */
+#define UPC_FORALL_DEPTH_NAME "__upc_forall_depth"
+
+/* Name of the runtime variable holding the address of the beginning of
+   the global shared region.  */
+#define UPC_GLOBAL_BASE_NAME "__upc_global_base"
+
+/* Names of various UPC runtime library routines that implement various
+   UPC statement constructs.  */
+#define UPC_BARRIER_LIBCALL "__upc_barrier"
+#define UPC_GETADDR_LIBCALL "__getaddr"
+#define UPC_NOTIFY_LIBCALL "__upc_notify"
+#define UPC_WAIT_LIBCALL "__upc_wait"
+
+/* Profiled/debugged runtime library routines  */
+#define UPC_BARRIERG_LIBCALL "__upc_barrierg"
+#define UPC_GETADDRG_LIBCALL "__getaddrg"
+#define UPC_NOTIFYG_LIBCALL "__upc_notifyg"
+#define UPC_NOTIFYG_LIBCALL "__upc_notifyg"
+#define UPC_WAITG_LIBCALL "__upc_waitg"
+
+/* Runtime library function that records upc_forall begin/end
+   when -fupc-instrument is asserted.  */
+#define UPC_INSTRUMENT_FORALL "__upc_forallg"
+
+/* Runtime library function that records function entry/exit 
+   when -fupc-instrument-functions is asserted.  */
+#define UPC_INSTRUMENT_FUNC "__upc_funcg"
+
+#endif  /* !GCC_C_C_UPC_RTS_NAMES_H */