diff mbox

[UPC,02/22] tree-related changes

Message ID 20151201060231.GA31023@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
--------

UPC introduces a new qualifier, "shared", that indicates that the
qualified object is located in a global shared address space that is
accessible by all UPC threads.  Additional qualifiers ("strict" and
"relaxed") further specify the semantics of accesses to
UPC shared objects.

In UPC, a shared qualified array can further specify a "layout
qualifier" (blocking factor) that indicates how the shared data
is blocked and distributed.

The following example illustrates the use of the UPC "shared" qualifier
combined with a layout qualifier.

    #define BLKSIZE 5
    #define N_PER_THREAD (4 * BLKSIZE)
    shared [BLKSIZE] double A[N_PER_THREAD*THREADS];

Above the "[BLKSIZE]" construct is the UPC layout qualifier; this
specifies that the shared array, A, distributes its elements across
each thread in blocks of 5 elements.  If the program is run with two
threads, then A is distributed as shown below:

    Thread 0    Thread 1
    --------    ---------
    A[ 0.. 4]   A[ 5.. 9]
    A[10..14]   A[15..19]
    A[20..24]   A[25..29]
    A[30..34]   A[35..39]

Above, the elements shown for thread 0 are defined as having "affinity"
to thread 0.  Similarly, those elements shown for thread 1 have
affinity to thread 1.  In UPC, a pointer to a shared object can be
cast to a thread local pointer (a "C" pointer), when the designated
shared object has affinity to the referencing thread.

A UPC "pointer-to-shared" (PTS) is a pointer that references a UPC
shared object.  A UPC pointer-to-shared is a "fat" pointer with the
following logical fields:
   (virt_addr, thread, phase)

The virtual address (virt_addr) field is combined with the thread
number (thread) to derive the location of the referenced object
within the UPC shared address space.  The phase field is used
keep track of the current block offset for PTS's that have
blocking factor that is greater than one.

GUPC implements pointer-to-shared objects using a "struct" internal
representation.  Until recently, GUPC also supported a "packed"
representation, which is more space efficient, but limits the range of
various fields in the UPC pointer-to-shared representation.  We have
decided to support only the "struct" representation so that the
compiler uses a single ABI that supports the full range of addresses,
threads, and blocking factors.

GCC's internal tree representation is extended to record the UPC
"shared", "strict", "relaxed" qualifiers, and the layout qualifier.

Comments

Richard Biener Dec. 1, 2015, 11:26 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
> --------
> 
> UPC introduces a new qualifier, "shared", that indicates that the
> qualified object is located in a global shared address space that is
> accessible by all UPC threads.  Additional qualifiers ("strict" and
> "relaxed") further specify the semantics of accesses to
> UPC shared objects.
> 
> In UPC, a shared qualified array can further specify a "layout
> qualifier" (blocking factor) that indicates how the shared data
> is blocked and distributed.
> 
> The following example illustrates the use of the UPC "shared" qualifier
> combined with a layout qualifier.
> 
>     #define BLKSIZE 5
>     #define N_PER_THREAD (4 * BLKSIZE)
>     shared [BLKSIZE] double A[N_PER_THREAD*THREADS];
> 
> Above the "[BLKSIZE]" construct is the UPC layout qualifier; this
> specifies that the shared array, A, distributes its elements across
> each thread in blocks of 5 elements.  If the program is run with two
> threads, then A is distributed as shown below:
> 
>     Thread 0    Thread 1
>     --------    ---------
>     A[ 0.. 4]   A[ 5.. 9]
>     A[10..14]   A[15..19]
>     A[20..24]   A[25..29]
>     A[30..34]   A[35..39]
> 
> Above, the elements shown for thread 0 are defined as having "affinity"
> to thread 0.  Similarly, those elements shown for thread 1 have
> affinity to thread 1.  In UPC, a pointer to a shared object can be
> cast to a thread local pointer (a "C" pointer), when the designated
> shared object has affinity to the referencing thread.
> 
> A UPC "pointer-to-shared" (PTS) is a pointer that references a UPC
> shared object.  A UPC pointer-to-shared is a "fat" pointer with the
> following logical fields:
>    (virt_addr, thread, phase)
> 
> The virtual address (virt_addr) field is combined with the thread
> number (thread) to derive the location of the referenced object
> within the UPC shared address space.  The phase field is used
> keep track of the current block offset for PTS's that have
> blocking factor that is greater than one.
> 
> GUPC implements pointer-to-shared objects using a "struct" internal
> representation.  Until recently, GUPC also supported a "packed"
> representation, which is more space efficient, but limits the range of
> various fields in the UPC pointer-to-shared representation.  We have
> decided to support only the "struct" representation so that the
> compiler uses a single ABI that supports the full range of addresses,
> threads, and blocking factors.
> 
> GCC's internal tree representation is extended to record the UPC
> "shared", "strict", "relaxed" qualifiers, and the layout qualifier.
> 
> --- gcc/tree-core.h     (.../trunk)     (revision 228959)
> +++ gcc/tree-core.h     (.../branches/gupc)     (revision 229159)
> @@ -470,7 +470,11 @@ enum cv_qualifier {
>    TYPE_QUAL_CONST    = 0x1,
>    TYPE_QUAL_VOLATILE = 0x2,
>    TYPE_QUAL_RESTRICT = 0x4,
> -  TYPE_QUAL_ATOMIC   = 0x8
> +  TYPE_QUAL_ATOMIC   = 0x8,
> +  /* UPC qualifiers */
> +  TYPE_QUAL_SHARED   = 0x10,
> +  TYPE_QUAL_RELAXED  = 0x20,
> +  TYPE_QUAL_STRICT   = 0x40
>  };
> [...]
> @@ -857,9 +875,14 @@ struct GTY(()) tree_base {
>        unsigned user_align : 1;
>        unsigned nameless_flag : 1;
>        unsigned atomic_flag : 1;
> -      unsigned spare0 : 3;
> -
> -      unsigned spare1 : 8;
> +      unsigned shared_flag : 1;
> +      unsigned strict_flag : 1;
> +      unsigned relaxed_flag : 1;
> +
> +      unsigned threads_factor_flag : 1;
> +      unsigned block_factor_0 : 1;
> +      unsigned block_factor_x : 1;
> +      unsigned spare1 : 5;
> 
> A given type is a UPC shared type if its 'shared_flag' is set.
> However, for array types, the shared_flag of the *element type*
> must be checked.  Thus,
> 
>     /* Return TRUE if TYPE is a shared type.  For arrays,
>        the element type must be queried, because array types
>        are never qualified.  */
>     #define SHARED_TYPE_P(TYPE) \
>       ((TYPE) && TYPE_P (TYPE) \
>        && TYPE_SHARED ((TREE_CODE (TYPE) != ARRAY_TYPE \
>                         ? (TYPE) : strip_array_types (TYPE))))
> 
> By default, a type has a blocking factor of 1.  If the blocking factor is 0
> (known as "indefinite") then 'block_factor_0' is set. If the blocking
> factor is neither 0 nor 1, then 'block_factor_x' is set and the
> actual blocking factor is found in a 'tree map' hash table called
> 'block_factor_htab' which is managed in tree.c.
> 
> This use of a garbage collected hash table which maps tree nodes to
> a UPC blocking factor leads to a need to implement custom garbage
> collection logic for all tree nodes.  This custom garbage collection
> logic is implemented in gt_ggc_mx().  PCH support is implemented
> in gt_pch_nx().  This custom garbage collector is defined in tree-core.h
> as follows:
> 
> -struct GTY(()) tree_type_common {
> +struct GTY((user)) tree_type_common {
>    struct tree_common common;
>    tree size;
>    tree size_unit;
> [...]
>    tree pointer_to;
>    tree reference_to;
>    union tree_type_symtab {
> -    int GTY ((tag ("TYPE_SYMTAB_IS_ADDRESS"))) address;
> -    const char * GTY ((tag ("TYPE_SYMTAB_IS_POINTER"))) pointer;
> -    struct die_struct * GTY ((tag ("TYPE_SYMTAB_IS_DIE"))) die;
> -  } GTY ((desc ("debug_hooks->tree_type_symtab_field"))) symtab;
> +    int address;
> +    const char *pointer;
> +    struct die_struct *die;
> +  } symtab;
>    tree canonical;
>    tree next_variant;
> 
> Above, 'tree_type_symtab' has to be explicitly traversed by
> the garbage collection routine.
> 
> 2015-11-30  Gary Funck  <gary@intrepid.com>
> 
> 	gcc/
> 	* expr.c (tree_expr_size): Move to tree.c and make it an
> 	extern function.
> 	* print-tree.c (print_node): Print UPC "shared" qualifier
> 	and blocking factor (if present).  Indicate THREADS scaling,
> 	if present.
> 	* tree-core.h (cv_qualifier): Add UPC type qualifiers:
> 	TYPE_QUAL_SHARED, TYPE_QUAL_RELAXED, and TYPE_QUAL_STRICT.
> 	(tree_index): Add UPC tree indexes:
> 	TI_UPC_PTS_TYPE, TI_UPC_PTS_REP_TYPE, TI_UPC_CHAR_PTS_TYPE,
> 	TI_UPC_PHASE_FIELD, TI_UPC_THREAD_FIELD, TI_UPC_VADDR_FIELD,
> 	TI_UPC_NULL_PTS.
> 	(tree_base): Add UPC-specific flags:
> 	shared_flag, strict_flag, relaxed_flag, threads_factor_flag,
> 	block_factor_0, block_factor_x.
> 	(tree_type_common): Remove ggc tag type descriptions in
> 	tree_type_symtab fields to accommodate UPC-related garbage collection
> 	changes.
> 	(gt_ggc_mx, gt_pch_nx, gt_pch_nx): New prototypes.
> 	Add custom garbage collection and PCH support for tree_type_common.
> 	* tree-dump.c (dequeue_and_dump): Add qualifier tags for
> 	UPC language qualifier (shared, strict, relaxed).
> 	* tree-pretty-print.c (dump_upc_type_quals): Print UPC language
> 	qualifiers and blocking factor.
> 	(dump_generic_node): Call dump_upc_type_quals()
> 	if the type asserts the "shared" qualifier.
> 	Print UPC qualifiers if applied to a tree node.
> 	Print type name for the UPC pointer-to-shared representation type.
> 	* tree-sra.c (find_param_candidates):
> 	Exclude UPC pointer-to-shared types.
> 	* tree.c: #include "debug.h".  Needed for access to symtab
> 	definition in the tree node garbage collection logic.
> 	(tm_block_factor_hasher, block_factor_htab): New.
> 	Define a garbage-collected mapping from tree node to
> 	UPC blocking factor.
> 	(init_ttree): Call block_factor_lookup_init().
> 	(copy_node_stat): Call SET_TYPE_BLOCK_FACTOR if
> 	type has a UPC blocking factor.
> 	(tree_expr_size): Move from expr.c and make it an
> 	'extern' function.
> 	(stabilize_reference_1): Copy UPC qualifiers to result.
> 	(build1_stat): Copy shared qualifier from type node.
> 	(build1_stat, build2_stat): For unary and binary operations,
> 	remove UPC "shared" qualifiers from the result type.
> 	(build3_stat): For reference expressions, ensure that
> 	the result node preserves the UPC qualifiers applied to the
> 	first argument.
> 	(set_type_quals): Add a 'tree' argument for the
> 	UPC layout qualifier (blocking factor).  Set the blocking factor
> 	if the type asserts the "shared" qualifier.
> 	(check_qualified_type): Add a 'tree' argument for the
> 	UPC layout qualifier (blocking factor).  Include the blocking factor
> 	into the type check.
> 	(check_aligned_type): Include the blocking factor
> 	into the type check.
> 	(get_qualified_type_1): Rename get_qualified_type()
> 	to get_qualified_type_1() and add a blocking factor argument.
> 	A #define of get_qualified_type is added to tree.h;
> 	it will call get_qualified_type_1() with a null layout qualifier.
> 	(build_qualified_type): Adjust calls to
> 	get_qualified_type_1() and set_type_quals().
> 	(build_pointer_type): For UPC pointer-to-shared types
> 	ensure that the resulting pointer type is compatible with the
> 	UPC pointer-to-shared representation type.
> 	(build_atomic_base): Adjust call to set_type_quals().
> 	(build_opaque_vector_type):
> 	Adjust call to check_qualified_type().
> 	(tree_nop_conversion): Handle conversions involving
> 	UPC pointer-to-shared types.
> 	(gt_ggc_mx, gt_pch_nx, gt_pch_nx): Implement custom
> 	garbage collection logic, necessitated by the use of a garbage
> 	collected hash tree map used to look up UPC blocking factors.
> 	Contributed by Meador Inge <meadori@codesourcery.com>.
> 	(get_block_factor, build_unshared_type,
> 	block_factor_lookup, block_factor_insert,
> 	block_factor_lookup_init): New.
> 	* tree.h (SHARED_TYPE_P, PTS_CVT_OP_P, TREE_QUALS,
> 	TREE_SHARED, TREE_STRICT, TREE_RELAXED,
> 	TYPE_SHARED, TYPE_STRICT, TYPE_RELAXED, TYPE_HAS_THREADS_FACTOR,
> 	TREE_FUNC_QUALS, TYPE_HAS_BLOCK_FACTOR_0, TYPE_HAS_BLOCK_FACTOR_X,
> 	TYPE_HAS_BLOCK_FACTOR, SET_TYPE_BLOCK_FACTOR): New.
> 	(TYPE_QUALS, TYPE_QUALS_NO_ADDR_SPACE,
> 	TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC):
> 	Add UPC type qualifiers (shared, relaxed, strict).
> 	(block_factor_insert, block_factor_lookup,
> 	build_unshared_type, block_factor_lookup_init,
> 	get_block_factor): New.  Declare prototypes.
> 	(SSA_VAR_P): Exclude UPC shared types.
> 	(upc_pts_type_node, upc_pts_rep_type_node,
> 	upc_char_pts_type_node, upc_phase_field_node,
> 	upc_thread_field_node, upc_vaddr_field_node,
> 	upc_null_pts_node): New.  Define UPC-related global tree nodes.
> 	(check_qualified_type, get_qualified_type_1):
> 	Adjust prototypes.
> 	(get_qualified_type): Re-implement as a pre-processor macro
> 	that invokes get_qualified_type_1() with a null blocking factor.
> 	(tree_expr_size): New. Declare prototype for function
> 	moved from expr.c into tree.c.
> 
> Index: gcc/expr.c
> ===================================================================
> --- gcc/expr.c	(.../trunk)	(revision 231059)
> +++ gcc/expr.c	(.../branches/gupc)	(revision 231080)
> @@ -137,7 +137,6 @@ static void emit_single_push_insn (machi
>  #endif
>  static void do_tablejump (rtx, machine_mode, rtx, rtx, rtx, int);
>  static rtx const_vector_from_tree (tree);
> -static tree tree_expr_size (const_tree);
>  static HOST_WIDE_INT int_expr_size (tree);
>  
>  
> @@ -11566,18 +11565,6 @@ get_personality_function (tree decl)
>    return XEXP (DECL_RTL (personality), 0);
>  }
>  
> -/* Returns a tree for the size of EXP in bytes.  */
> -
> -static tree
> -tree_expr_size (const_tree exp)
> -{
> -  if (DECL_P (exp)
> -      && DECL_SIZE_UNIT (exp) != 0)
> -    return DECL_SIZE_UNIT (exp);
> -  else
> -    return size_in_bytes (TREE_TYPE (exp));
> -}
> -
>  /* Return an rtx for the size in bytes of the value of EXP.  */
>  
>  rtx
> Index: gcc/print-tree.c
> ===================================================================
> --- gcc/print-tree.c	(.../trunk)	(revision 231059)
> +++ gcc/print-tree.c	(.../branches/gupc)	(revision 231080)
> @@ -299,6 +299,8 @@ print_node (FILE *file, const char *pref
>      fputs (" readonly", file);
>    if (TYPE_P (node) && TYPE_ATOMIC (node))
>      fputs (" atomic", file);
> +  if (TREE_SHARED (node))
> +    fputs (" shared", file);
>    if (!TYPE_P (node) && TREE_CONSTANT (node))
>      fputs (" constant", file);
>    else if (TYPE_P (node) && TYPE_SIZES_GIMPLIFIED (node))
> @@ -607,6 +609,14 @@ print_node (FILE *file, const char *pref
>  
>        print_node (file, "size", TYPE_SIZE (node), indent + 4);
>        print_node (file, "unit size", TYPE_SIZE_UNIT (node), indent + 4);
> +      if (TYPE_SHARED (node))
> +        {
> +          if (TYPE_HAS_THREADS_FACTOR(node))
> +	    fputs (" THREADS factor", file);
> +	  if (TYPE_HAS_BLOCK_FACTOR (node))
> +	    print_node (file, "block factor",
> +	                TYPE_BLOCK_FACTOR (node), indent + 4);
> +        }
>        indent_to (file, indent + 3);
>  
>        if (TYPE_USER_ALIGN (node))
> Index: gcc/tree-core.h
> ===================================================================
> --- gcc/tree-core.h	(.../trunk)	(revision 231059)
> +++ gcc/tree-core.h	(.../branches/gupc)	(revision 231080)
> @@ -501,7 +501,11 @@ enum cv_qualifier {
>    TYPE_QUAL_CONST    = 0x1,
>    TYPE_QUAL_VOLATILE = 0x2,
>    TYPE_QUAL_RESTRICT = 0x4,
> -  TYPE_QUAL_ATOMIC   = 0x8
> +  TYPE_QUAL_ATOMIC   = 0x8,
> +  /* UPC qualifiers */
> +  TYPE_QUAL_SHARED   = 0x10,
> +  TYPE_QUAL_RELAXED  = 0x20,
> +  TYPE_QUAL_STRICT   = 0x40
>  };
>  
>  /* Standard named or nameless data types of the C compiler.  */
> @@ -578,6 +582,14 @@ enum tree_index {
>    TI_FILEPTR_TYPE,
>    TI_POINTER_SIZED_TYPE,
>  
> +  TI_UPC_PTS_TYPE,
> +  TI_UPC_PTS_REP_TYPE,
> +  TI_UPC_CHAR_PTS_TYPE,
> +  TI_UPC_PHASE_FIELD,
> +  TI_UPC_THREAD_FIELD,
> +  TI_UPC_VADDR_FIELD,
> +  TI_UPC_NULL_PTS,
> +
>    TI_POINTER_BOUNDS_TYPE,
>  
>    TI_DFLOAT32_TYPE,
> @@ -880,9 +892,14 @@ struct GTY(()) tree_base {
>        unsigned user_align : 1;
>        unsigned nameless_flag : 1;
>        unsigned atomic_flag : 1;
> -      unsigned spare0 : 3;
> -
> -      unsigned spare1 : 8;
> +      unsigned shared_flag : 1;
> +      unsigned strict_flag : 1;
> +      unsigned relaxed_flag : 1;
> +
> +      unsigned threads_factor_flag : 1;
> +      unsigned block_factor_0 : 1;
> +      unsigned block_factor_x : 1;
> +      unsigned spare1 : 5;
>  
>        /* This field is only used with TREE_TYPE nodes; the only reason it is
>  	 present in tree_base instead of tree_type is to save space.  The size
> @@ -1411,7 +1428,7 @@ struct GTY(()) tree_block {
>    struct die_struct *die;
>  };
>  
> -struct GTY(()) tree_type_common {
> +struct GTY((user)) tree_type_common {
>    struct tree_common common;
>    tree size;
>    tree size_unit;
> @@ -1441,10 +1458,10 @@ struct GTY(()) tree_type_common {
>    tree pointer_to;
>    tree reference_to;
>    union tree_type_symtab {
> -    int GTY ((tag ("TYPE_SYMTAB_IS_ADDRESS"))) address;
> -    const char * GTY ((tag ("TYPE_SYMTAB_IS_POINTER"))) pointer;
> -    struct die_struct * GTY ((tag ("TYPE_SYMTAB_IS_DIE"))) die;
> -  } GTY ((desc ("debug_hooks->tree_type_symtab_field"))) symtab;
> +    int address;
> +    const char *pointer;
> +    struct die_struct *die;
> +  } symtab;

Err, you don't have debug info for this?  What is address?

I do not like the explict GC of tree_type_common.

>    tree canonical;
>    tree next_variant;
>    tree main_variant;
> @@ -1452,6 +1469,11 @@ struct GTY(()) tree_type_common {
>    tree name;
>  };
>  
> +/* Garbage collection and PCH support for tree_type_common.  */
> +extern void gt_ggc_mx (tree_type_common *t);
> +extern void gt_pch_nx (tree_type_common *t);
> +extern void gt_pch_nx (tree_type_common *t, gt_pointer_operator, void *);
> +
>  struct GTY(()) tree_type_with_lang_specific {
>    struct tree_type_common common;
>    /* Points to a structure whose details depend on the language in use.  */
> Index: gcc/tree-dump.c
> ===================================================================
> --- gcc/tree-dump.c	(.../trunk)	(revision 231059)
> +++ gcc/tree-dump.c	(.../branches/gupc)	(revision 231080)
> @@ -387,10 +387,13 @@ dequeue_and_dump (dump_info_p di)
>  
>        if (quals != TYPE_UNQUALIFIED)
>  	{
> -	  fprintf (di->stream, "qual: %c%c%c     ",
> +	  fprintf (di->stream, "qual: %c%c%c%c%c%c  ",
>  		   (quals & TYPE_QUAL_CONST) ? 'c' : ' ',
>  		   (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ',
> -		   (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' ');
> +		   (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' ',
> +		   (quals & TYPE_QUAL_SHARED) ? 's' : ' ',
> +		   (quals & TYPE_QUAL_STRICT) ? 't' : ' ',
> +		   (quals & TYPE_QUAL_RELAXED) ? 'x' : ' ');
>  	  di->column += 14;
>  	}
>  
> Index: gcc/tree-pretty-print.c
> ===================================================================
> --- gcc/tree-pretty-print.c	(.../trunk)	(revision 231059)
> +++ gcc/tree-pretty-print.c	(.../branches/gupc)	(revision 231080)
> @@ -1105,6 +1105,25 @@ dump_block_node (pretty_printer *pp, tre
>  }
>  
>  
> +static void
> +dump_upc_type_quals (pretty_printer *buffer, tree type, int quals)

Functions need comments.

> +{
> +  gcc_assert (type && TYPE_CHECK (type));
> +  gcc_assert (quals & TYPE_QUAL_SHARED);
> +  if (quals & TYPE_QUAL_STRICT)
> +    pp_string (buffer, "strict ");
> +  if (quals & TYPE_QUAL_RELAXED)
> +    pp_string (buffer, "relaxed ");
> +  pp_string (buffer, "shared ");
> +  if (TYPE_HAS_BLOCK_FACTOR (type))
> +    {
> +      tree block_factor = TYPE_BLOCK_FACTOR (type);
> +      pp_string (buffer, "[");
> +      pp_wide_integer (buffer, TREE_INT_CST_LOW (block_factor));
> +      pp_string (buffer, "] ");
> +    }
> +}
> +
>  /* Dump the node NODE on the pretty_printer PP, SPC spaces of
>     indent.  FLAGS specifies details to show in the dump (see TDF_* in
>     dumpfile.h).  If IS_STMT is true, the object printed is considered
> @@ -1204,6 +1223,8 @@ dump_generic_node (pretty_printer *pp, t
>  	  pp_string (pp, "volatile ");
>  	else if (quals & TYPE_QUAL_RESTRICT)
>  	  pp_string (pp, "restrict ");
> +	else if (quals & TYPE_QUAL_SHARED)
> +          dump_upc_type_quals (pp, node, quals);
>  
>  	if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (node)))
>  	  {
> @@ -1346,6 +1367,14 @@ dump_generic_node (pretty_printer *pp, t
>  	    pp_string (pp, " volatile");
>  	  if (quals & TYPE_QUAL_RESTRICT)
>  	    pp_string (pp, " restrict");
> +          if (quals & TYPE_QUAL_SHARED)
> +	    {
> +	      if (quals & TYPE_QUAL_STRICT)
> +		pp_string (pp, " strict");
> +	      if (quals & TYPE_QUAL_RELAXED)
> +		pp_string (pp, " relaxed");
> +              pp_string (pp, " shared");
> +	    }
>  
>  	  if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (node)))
>  	    {
> @@ -1515,6 +1544,8 @@ dump_generic_node (pretty_printer *pp, t
>  	  pp_string (pp, "const ");
>  	if (quals & TYPE_QUAL_VOLATILE)
>  	  pp_string (pp, "volatile ");
> +	if (quals & TYPE_QUAL_SHARED)
> +          dump_upc_type_quals (pp, node, quals);
>  
>          /* Print the name of the structure.  */
>          if (TREE_CODE (node) == RECORD_TYPE)
> @@ -1522,7 +1553,12 @@ dump_generic_node (pretty_printer *pp, t
>          else if (TREE_CODE (node) == UNION_TYPE)
>  	  pp_string (pp, "union ");
>  
> -        if (TYPE_NAME (node))
> +	if (upc_pts_rep_type_node && node == upc_pts_rep_type_node)
> +	  /* Normally, builtin types will not be printed.
> +	     We short-circuit that check for the UPC "struct PTS"
> +	     representation type.  */
> +	  pp_string (pp, "upc_shared_ptr_t");
> +        else if (TYPE_NAME (node))
>  	  dump_generic_node (pp, TYPE_NAME (node), spc, flags, false);
>  	else if (!(flags & TDF_SLIM))
>  	  /* FIXME: If we eliminate the 'else' above and attempt
> Index: gcc/tree-sra.c
> ===================================================================
> --- gcc/tree-sra.c	(.../trunk)	(revision 231059)
> +++ gcc/tree-sra.c	(.../branches/gupc)	(revision 231080)
> @@ -3882,6 +3882,7 @@ find_param_candidates (void)
>  
>  	  if (TREE_CODE (type) == FUNCTION_TYPE
>  	      || TYPE_VOLATILE (type)
> +	      || SHARED_TYPE_P (type)

UPC_SHARED_TYPE_P ()

>  	      || (TREE_CODE (type) == ARRAY_TYPE
>  		  && TYPE_NONALIASED_COMPONENT (type))
>  	      || !is_gimple_reg (parm)
> Index: gcc/tree.c
> ===================================================================
> --- gcc/tree.c	(.../trunk)	(revision 231059)
> +++ gcc/tree.c	(.../branches/gupc)	(revision 231080)
> @@ -58,6 +58,7 @@ along with GCC; see the file COPYING3.
>  #include "langhooks-def.h"
>  #include "tree-diagnostic.h"
>  #include "except.h"
> +#include "debug.h"
>  #include "builtins.h"
>  #include "print-tree.h"
>  #include "ipa-utils.h"
> @@ -243,7 +244,23 @@ struct tree_vec_map_cache_hasher : ggc_c
>  static GTY ((cache))
>       hash_table<tree_vec_map_cache_hasher> *debug_args_for_decl;
>  
> -static void set_type_quals (tree, int);
> +struct tm_block_factor_hasher : ggc_cache_ptr_hash<tree_map>
> +{
> +  static hashval_t hash (tree_map *m) { return tree_map_hash (m); }
> +  static bool equal (tree_map *a, tree_map *b) { return tree_map_eq (a, b); }
> +
> +  static int
> +  keep_cache_entry (tree_map *&e)
> +  {
> +    return ggc_marked_p (e->base.from);
> +  }
> +};
> +
> +/* Hash table for block factor lookups when the block factor
> +   is not 0 (the indefinite block factor) or 1 (the default).  */
> +static GTY((cache)) hash_table<tm_block_factor_hasher> *block_factor_htab;
> +
> +static void set_type_quals (tree, int, tree);
>  static void print_type_hash_statistics (void);
>  static void print_debug_expr_statistics (void);
>  static void print_value_expr_statistics (void);
> @@ -639,6 +656,9 @@ init_ttree (void)
>    type_hash_table
>      = hash_table<type_cache_hasher>::create_ggc (TYPE_HASH_INITIAL_SIZE);
>  
> +  /* Initialize hash table used to manage blocking factors.  */
> +  block_factor_lookup_init ();
> +
>    debug_expr_for_decl
>      = hash_table<tree_decl_map_cache_hasher>::create_ggc (512);
>  
> @@ -1197,6 +1217,9 @@ copy_node_stat (tree node MEM_STAT_DECL)
>  	  TYPE_CACHED_VALUES_P (t) = 0;
>  	  TYPE_CACHED_VALUES (t) = NULL_TREE;
>  	}
> +
> +      if (TYPE_HAS_BLOCK_FACTOR (node))
> +        SET_TYPE_BLOCK_FACTOR (t, TYPE_BLOCK_FACTOR (node));
>      }
>      else if (code == TARGET_OPTION_NODE)
>        {
> @@ -2932,6 +2955,18 @@ size_in_bytes (const_tree type)
>    return t;
>  }
>  
> +/* Returns a tree for the size of EXP in bytes.  */
> +
> +tree
> +tree_expr_size (const_tree exp)
> +{
> +  if (DECL_P (exp)
> +      && DECL_SIZE_UNIT (exp) != 0)
> +    return DECL_SIZE_UNIT (exp);
> +  else
> +    return size_in_bytes (TREE_TYPE (exp));
> +}
> +
>  /* Return the size of TYPE (in bytes) as a wide integer
>     or return -1 if the size can vary or is larger than an integer.  */
>  
> @@ -4155,6 +4190,9 @@ stabilize_reference_1 (tree e)
>    TREE_READONLY (result) = TREE_READONLY (e);
>    TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (e);
>    TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e);
> +  TREE_SHARED (result)  = TREE_SHARED (e);
> +  TREE_STRICT (result)  = TREE_STRICT (e);
> +  TREE_RELAXED (result) = TREE_RELAXED (e);
>  
>    return result;
>  }
> @@ -4238,6 +4276,9 @@ stabilize_reference (tree ref)
>    TREE_READONLY (result) = TREE_READONLY (ref);
>    TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (ref);
>    TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (ref);
> +  TREE_SHARED (result)  = TREE_SHARED (ref);
> +  TREE_STRICT (result)  = TREE_STRICT (ref);
> +  TREE_RELAXED (result) = TREE_RELAXED (ref);
>  
>    return result;
>  }
> @@ -4381,6 +4422,7 @@ build1_stat (enum tree_code code, tree t
>        /* Whether a dereference is readonly has nothing to do with whether
>  	 its operand is readonly.  */
>        TREE_READONLY (t) = 0;
> +      TREE_SHARED (t) = SHARED_TYPE_P (type);

This is frontend logic and should reside in FEs.

>        break;
>  
>      case ADDR_EXPR:
> @@ -4396,6 +4438,12 @@ build1_stat (enum tree_code code, tree t
>        if (TREE_CODE_CLASS (code) == tcc_reference
>  	  && node && TREE_THIS_VOLATILE (node))
>  	TREE_THIS_VOLATILE (t) = 1;
> +      /* Drop the "shared" type qualifier for
> +         expressions involving shared objects.  */ 
> +      if (TREE_CODE_CLASS (code) == tcc_unary
> +	  && node && !TYPE_P (node)
> +	  && SHARED_TYPE_P (type))
> +	TREE_TYPE (t) = build_unshared_type (type);

Likewise.

>        break;
>      }
>  
> @@ -4439,6 +4487,10 @@ build2_stat (enum tree_code code, tree t
>  		&& ptrofftype_p (TREE_TYPE (arg1)));
>  
>    t = make_node_stat (code PASS_MEM_STAT);
> +
> +  /* Remove shared type qualifiers from the result type.  */
> +  if (SHARED_TYPE_P (tt))
> +    tt = build_unshared_type (tt);

Likewise.

>    TREE_TYPE (t) = tt;
>  
>    /* Below, we automatically set TREE_SIDE_EFFECTS and TREE_READONLY for the
> @@ -4516,6 +4568,14 @@ build3_stat (enum tree_code code, tree t
>    TREE_THIS_VOLATILE (t)
>      = (TREE_CODE_CLASS (code) == tcc_reference
>         && arg0 && TREE_THIS_VOLATILE (arg0));
> +  TREE_SHARED (t)
> +    = (TREE_CODE_CLASS (code) == tcc_reference
> +       && arg0 && TREE_SHARED (arg0));
> +  if (TREE_SHARED (t))
> +    {
> +      TREE_STRICT (t)  = TREE_STRICT (arg0);
> +      TREE_RELAXED (t) = TREE_RELAXED (arg0);
> +    }
>  

Likewise.

>    return t;
>  }
> @@ -6464,16 +6524,22 @@ handle_dll_attribute (tree * pnode, tree
>  #endif /* TARGET_DLLIMPORT_DECL_ATTRIBUTES  */
>  
>  /* Set the type qualifiers for TYPE to TYPE_QUALS, which is a bitmask
> -   of the various TYPE_QUAL values.  */
> +   of the various TYPE_QUAL values.  Also, set the blocking factor,
> +   which is either null or a reference to an integral constant.  */
>  
>  static void
> -set_type_quals (tree type, int type_quals)
> +set_type_quals (tree type, int type_quals, tree block_factor)
>  {
>    TYPE_READONLY (type) = (type_quals & TYPE_QUAL_CONST) != 0;
>    TYPE_VOLATILE (type) = (type_quals & TYPE_QUAL_VOLATILE) != 0;
>    TYPE_RESTRICT (type) = (type_quals & TYPE_QUAL_RESTRICT) != 0;
>    TYPE_ATOMIC (type) = (type_quals & TYPE_QUAL_ATOMIC) != 0;
>    TYPE_ADDR_SPACE (type) = DECODE_QUAL_ADDR_SPACE (type_quals);
> +  TYPE_SHARED (type) = (type_quals & TYPE_QUAL_SHARED) != 0;
> +  TYPE_STRICT (type) = (type_quals & TYPE_QUAL_STRICT) != 0;
> +  TYPE_RELAXED (type) = (type_quals & TYPE_QUAL_RELAXED) != 0;
> +  if (TYPE_SHARED (type))
> +    SET_TYPE_BLOCK_FACTOR (type, block_factor);
>  }
>  
>  /* Returns true iff unqualified CAND and BASE are equivalent.  */
> @@ -6490,12 +6556,15 @@ check_base_type (const_tree cand, const_
>  				   TYPE_ATTRIBUTES (base)));
>  }
>  
> -/* Returns true iff CAND is equivalent to BASE with TYPE_QUALS.  */
> +/* Returns true iff CAND is equivalent to BASE with TYPE_QUALS
> +   and BLOCK_FACTOR.  */
>  
>  bool
> -check_qualified_type (const_tree cand, const_tree base, int type_quals)
> +check_qualified_type (const_tree cand, const_tree base,
> +                      int type_quals, tree block_factor)
>  {
>    return (TYPE_QUALS (cand) == type_quals
> +	  && TYPE_BLOCK_FACTOR (cand) == block_factor
>  	  && check_base_type (cand, base));
>  }
>  
> @@ -6505,6 +6574,7 @@ static bool
>  check_aligned_type (const_tree cand, const_tree base, unsigned int align)
>  {
>    return (TYPE_QUALS (cand) == TYPE_QUALS (base)
> +	  && TYPE_BLOCK_FACTOR (cand) == TYPE_BLOCK_FACTOR (base)
>  	  && TYPE_NAME (cand) == TYPE_NAME (base)
>  	  /* Apparently this is needed for Objective-C.  */
>  	  && TYPE_CONTEXT (cand) == TYPE_CONTEXT (base)
> @@ -6557,11 +6627,11 @@ find_atomic_core_type (tree type)
>  }
>  
>  /* Return a version of the TYPE, qualified as indicated by the
> -   TYPE_QUALS, if one exists.  If no qualified version exists yet,
> -   return NULL_TREE.  */
> +   TYPE_QUALS, and BLOCK_FACTOR if one exists.
> +   If no qualified version exists yet, return NULL_TREE.  */
>  
>  tree
> -get_qualified_type (tree type, int type_quals)
> +get_qualified_type_1 (tree type, int type_quals, tree block_factor)
>  {
>    tree t;
>  
> @@ -6572,28 +6642,28 @@ get_qualified_type (tree type, int type_
>       like the one we need to have.  If so, use that existing one.  We must
>       preserve the TYPE_NAME, since there is code that depends on this.  */
>    for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
> -    if (check_qualified_type (t, type, type_quals))
> +    if (check_qualified_type (t, type, type_quals, block_factor))
>        return t;
>  
>    return NULL_TREE;
>  }
>  
> -/* Like get_qualified_type, but creates the type if it does not
> +/* Like get_qualified_type_1, but creates the type if it does not
>     exist.  This function never returns NULL_TREE.  */
>  
>  tree
> -build_qualified_type (tree type, int type_quals)
> +build_qualified_type_1 (tree type, int type_quals, tree block_factor)
>  {
>    tree t;
>  
>    /* See if we already have the appropriate qualified variant.  */
> -  t = get_qualified_type (type, type_quals);
> +  t = get_qualified_type_1 (type, type_quals, block_factor);
>  
>    /* If not, build it.  */
>    if (!t)
>      {
>        t = build_variant_type_copy (type);
> -      set_type_quals (t, type_quals);
> +      set_type_quals (t, type_quals, block_factor);
>  
>        if (((type_quals & TYPE_QUAL_ATOMIC) == TYPE_QUAL_ATOMIC))
>  	{
> @@ -7934,6 +8004,16 @@ build_pointer_type (tree to_type)
>    addr_space_t as = to_type == error_mark_node? ADDR_SPACE_GENERIC
>  					      : TYPE_ADDR_SPACE (to_type);
>    machine_mode pointer_mode = targetm.addr_space.pointer_mode (as);
> +  if (SHARED_TYPE_P (to_type))
> +    {
> +      tree upc_pts_type;
> +      pointer_mode = TYPE_MODE (upc_pts_rep_type_node);
> +      upc_pts_type = build_pointer_type_for_mode (to_type, pointer_mode,
> +                                                  false);
> +      TYPE_USER_ALIGN (upc_pts_type) = TYPE_USER_ALIGN (upc_pts_rep_type_node);
> +      TYPE_ALIGN (upc_pts_type) = TYPE_ALIGN (upc_pts_rep_type_node);
> +      return upc_pts_type;
> +    }
>    return build_pointer_type_for_mode (to_type, pointer_mode, false);
>  }
>  
> @@ -9991,7 +10071,7 @@ build_atomic_base (tree type, unsigned i
>      return t;
>    
>    t = build_variant_type_copy (type);
> -  set_type_quals (t, TYPE_QUAL_ATOMIC);
> +  set_type_quals (t, TYPE_QUAL_ATOMIC, NULL_TREE);
>  
>    if (align)
>      TYPE_ALIGN (t) = align;
> @@ -10724,7 +10804,7 @@ build_opaque_vector_type (tree innertype
>    cand = TYPE_NEXT_VARIANT (t);
>    if (cand
>        && TYPE_VECTOR_OPAQUE (cand)
> -      && check_qualified_type (cand, t, TYPE_QUALS (t)))
> +      && check_qualified_type (cand, t, TYPE_QUALS (t), NULL_TREE))
>      return cand;
>    /* Othewise build a variant type and make sure to queue it after
>       the non-opaque type.  */
> @@ -12205,6 +12285,7 @@ static inline bool
>  tree_nop_conversion (const_tree exp)
>  {
>    tree outer_type, inner_type;
> +  int outer_is_pts_p, inner_is_pts_p;
>  
>    if (!CONVERT_EXPR_P (exp)
>        && TREE_CODE (exp) != NON_LVALUE_EXPR)
> @@ -12218,6 +12299,22 @@ tree_nop_conversion (const_tree exp)
>    if (!inner_type)
>      return false;
>  
> +  outer_is_pts_p = (POINTER_TYPE_P (outer_type)
> +                    && SHARED_TYPE_P (TREE_TYPE (outer_type)));
> +  inner_is_pts_p = (POINTER_TYPE_P (inner_type)
> +                    && SHARED_TYPE_P (TREE_TYPE (inner_type)));
> +
> +  /* Pointer-to-shared types have special
> +     equivalence rules that must be checked.  */
> +  if (outer_is_pts_p && inner_is_pts_p
> +      && lang_hooks.types_compatible_p)
> +    return lang_hooks.types_compatible_p (outer_type, inner_type);

Sorry, but that can't fly with LTO.  I wonder why you didn't
use address-spaces for whatever UPC needs for pointers.

> +
> +  /* Pointer-to-shared types are not interchangeable
> +     with integral types.  */
> +  if (outer_is_pts_p || inner_is_pts_p)
> +    return false;
> +
>    return tree_nop_conversion_p (outer_type, inner_type);
>  }
>  
> @@ -12731,6 +12828,121 @@ block_may_fallthru (const_tree block)
>      }
>  }
>  
> +/* Garbage collection support for tree_type_common.  */
> +
> +extern void gt_ggc_mx (tree&);
> +extern void gt_ggc_mx_die_struct (void *);
> +
> +void gt_ggc_mx (tree_type_common *tt)
> +{
> +  tree t = (tree) tt;
> +  tree block_factor = TYPE_BLOCK_FACTOR (t);
> +
> +  gt_ggc_mx (tt->common.typed.type);
> +  gt_ggc_mx (tt->common.chain);
> +  gt_ggc_mx (tt->size);
> +  gt_ggc_mx (tt->size_unit);
> +  gt_ggc_mx (tt->attributes);
> +  gt_ggc_mx (tt->pointer_to);
> +  gt_ggc_mx (tt->reference_to);
> +  switch (debug_hooks->tree_type_symtab_field)
> +    {
> +    case TYPE_SYMTAB_IS_ADDRESS:
> +      break;
> +    case TYPE_SYMTAB_IS_POINTER:
> +      gt_ggc_m_S (tt->symtab.pointer);
> +      break;
> +    case TYPE_SYMTAB_IS_DIE:
> +      gt_ggc_mx_die_struct (tt->symtab.die);
> +      break;
> +    default:
> +      break;
> +    }
> +  gt_ggc_mx (tt->name);
> +  gt_ggc_mx (tt->next_variant);
> +  gt_ggc_mx (tt->main_variant);
> +  gt_ggc_mx (tt->context);
> +  gt_ggc_mx (tt->canonical);
> +
> +  if (TYPE_HAS_BLOCK_FACTOR_X (t))
> +    gt_ggc_mx (block_factor);
> +}
> +
> +/* PCH support for tree_type_common.  */
> +
> +extern void gt_pch_nx (tree&);
> +extern void gt_ggc_nx_die_struct (void *);
> +
> +void gt_pch_nx (tree_type_common *tt)
> +{
> +  tree t = (tree) tt;
> +  tree block_factor = TYPE_BLOCK_FACTOR (t);
> +
> +  gt_pch_nx (tt->common.typed.type);
> +  gt_pch_nx (tt->common.chain);
> +  gt_pch_nx (tt->size);
> +  gt_pch_nx (tt->size_unit);
> +  gt_pch_nx (tt->attributes);
> +  gt_pch_nx (tt->pointer_to);
> +  gt_pch_nx (tt->reference_to);
> +  switch (debug_hooks->tree_type_symtab_field)
> +    {
> +    case TYPE_SYMTAB_IS_ADDRESS:
> +      break;
> +    case TYPE_SYMTAB_IS_POINTER:
> +      gt_pch_n_S (tt->symtab.pointer);
> +      break;
> +    case TYPE_SYMTAB_IS_DIE:
> +      gt_pch_nx_die_struct (tt->symtab.die);
> +      break;
> +    default:
> +      break;
> +    }
> +  gt_pch_nx (tt->name);
> +  gt_pch_nx (tt->next_variant);
> +  gt_pch_nx (tt->main_variant);
> +  gt_pch_nx (tt->context);
> +  gt_pch_nx (tt->canonical);
> +
> +  if (TYPE_HAS_BLOCK_FACTOR_X (t))
> +    gt_pch_nx (block_factor);
> +}
> +
> +void gt_pch_nx (tree_type_common *tt, gt_pointer_operator op, void *cookie)
> +{
> +  tree t = (tree) tt;
> +  tree block_factor = TYPE_BLOCK_FACTOR (t);
> +
> +  op (&(tt->common.typed.type), cookie);
> +  op (&(tt->common.chain), cookie);
> +  op (&(tt->size), cookie);
> +  op (&(tt->size_unit), cookie);
> +  op (&(tt->attributes), cookie);
> +  op (&(tt->pointer_to), cookie);
> +  op (&(tt->reference_to), cookie);
> +  switch (debug_hooks->tree_type_symtab_field)
> +    {
> +    case TYPE_SYMTAB_IS_ADDRESS:
> +      break;
> +    case TYPE_SYMTAB_IS_POINTER:
> +      op (&(tt->symtab.pointer), cookie);
> +      break;
> +    case TYPE_SYMTAB_IS_DIE:
> +      op (&(tt->symtab.die), cookie);
> +      break;
> +    default:
> +      break;
> +    }
> +  op (&(tt->name), cookie);
> +  op (&(tt->next_variant), cookie);
> +  op (&(tt->main_variant), cookie);
> +  op (&(tt->context), cookie);
> +  op (&(tt->canonical), cookie);
> +
> +  if (TYPE_HAS_BLOCK_FACTOR_X (t))
> +    op (&(block_factor), cookie);
> +}
> +
>  /* True if we are using EH to handle cleanups.  */
>  static bool using_eh_for_cleanups_flag = false;
>  
> @@ -13901,6 +14113,103 @@ nonnull_arg_p (const_tree arg)
>    return false;
>  }
>  
> +/* Return the blocking factor of the shared type, TYPE.
> +   If the blocking factor is NULL, then return the default blocking
> +   factor of 1.  */
> +
> +tree
> +get_block_factor (const tree type)
> +{
> +  tree block_factor = size_one_node;
> +  const tree elt_type = strip_array_types (type);
> +  if (elt_type && (TREE_CODE (elt_type) != ERROR_MARK)
> +      && TYPE_HAS_BLOCK_FACTOR (elt_type))
> +    block_factor = TYPE_BLOCK_FACTOR (elt_type);
> +  return block_factor;
> +}
> +
> +/* Return a variant of TYPE, where the shared, strict, and relaxed
> +   qualifiers have been removed.  */
> +
> +tree
> +build_unshared_type (tree type)

Too generic names.  I'd prefer if these routines were in a upc.c
file rather than in tree.c.  Likewise for the block hash I suppose.

> +{
> +  tree u_type = type;
> +  if (TREE_CODE (type) == ARRAY_TYPE)
> +    {
> +      const tree elem_type = TREE_TYPE(type);
> +      const tree u_elem_type = build_unshared_type (elem_type);
> +      if (u_elem_type != elem_type)
> +        {
> +          for (u_type = TYPE_MAIN_VARIANT (type);
> +               u_type && TREE_TYPE(u_type) != u_elem_type;
> +               u_type = TYPE_NEXT_VARIANT (u_type)) /* loop */;
> +          if (!u_type)
> +            {
> +              u_type = build_variant_type_copy (type);
> +              TREE_TYPE (u_type) = u_elem_type;
> +            }
> +        }
> +    }
> +  else
> +    {
> +      const int quals = TYPE_QUALS (type);
> +      const int u_quals = quals & ~(TYPE_QUAL_SHARED
> +                                    | TYPE_QUAL_RELAXED
> +                                    | TYPE_QUAL_STRICT);
> +      u_type = build_qualified_type (type, u_quals);
> +    }
> +  return u_type;
> +}
> +
> +/* Lookup the block size of TYPE, and return it if we find one.  */
> +
> +tree
> +block_factor_lookup (const_tree type)
> +{
> +  struct tree_map in;
> +  union
> +    {
> +      const_tree ct;
> +      tree t;
> +    } ct_to_t;
> +  ct_to_t.ct = type;
> +  /* Drop the const qualifier, avoid the warning.  */
> +  in.base.from = ct_to_t.t;
> +  in.hash = TYPE_HASH (in.base.from);
> +  struct tree_map **loc = block_factor_htab->
> +                            find_slot_with_hash (&in, in.hash, NO_INSERT);
> +  gcc_assert (loc != NULL);
> +  struct tree_map *h = *loc;
> +  if (h)
> +    return h->to;
> +  return NULL_TREE;
> +}
> +
> +/* Insert a mapping TYPE->BLOCK_FACTOR in the block factor hashtable.  */
> +
> +void
> +block_factor_insert (tree type, tree block_factor)
> +{
> +
> +  gcc_assert (type && TYPE_P (type));
> +  gcc_assert (block_factor && INTEGRAL_TYPE_P (TREE_TYPE (block_factor)));
> +  gcc_assert (!(integer_zerop (block_factor) || integer_onep (block_factor)));
> +  tree_map *h = ggc_alloc<tree_map> ();
> +  h->base.from = type;
> +  h->hash = TYPE_HASH (type);
> +  h->to = block_factor;
> +  tree_map **loc = block_factor_htab->
> +                     find_slot_with_hash (h, h->hash, INSERT);
> +  *loc = h;
> +}
> +
> +void
> +block_factor_lookup_init (void)
> +{
> +  block_factor_htab = hash_table<tm_block_factor_hasher>::create_ggc (17);
> +}
> +
>  /* Given location LOC, strip away any packed range information
>     or ad-hoc information.  */
>  
> Index: gcc/tree.h
> ===================================================================
> --- gcc/tree.h	(.../trunk)	(revision 231059)
> +++ gcc/tree.h	(.../branches/gupc)	(revision 231080)
> @@ -636,6 +636,24 @@ extern void omp_clause_range_check_faile
>  #define FUNC_OR_METHOD_TYPE_P(NODE) \
>    (TREE_CODE (NODE) == FUNCTION_TYPE || TREE_CODE (NODE) == METHOD_TYPE)
>  
> +/* Return TRUE if TYPE is a shared type.  For arrays,
> +   the element type must be queried, because array types
> +   are never qualified.  */
> +#define SHARED_TYPE_P(TYPE) \
> +  ((TYPE) && TYPE_P (TYPE) \
> +   && TYPE_SHARED ((TREE_CODE (TYPE) != ARRAY_TYPE \
> +                    ? (TYPE) : strip_array_types (TYPE))))
> +
> +/* Return TRUE if EXP is a conversion operation involving
> +   pointers-to-shared.  If either of the types involved
> +   in the conversion is a pointer-to-shared type, return TRUE.  */
> +#define PTS_CVT_OP_P(EXP) \
> +  ((EXP) && ((POINTER_TYPE_P (TREE_TYPE (EXP)) \
> +              && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (EXP, 0)))) \
> +              && (SHARED_TYPE_P (TREE_TYPE (TREE_TYPE (EXP))) \
> +                  || SHARED_TYPE_P (TREE_TYPE ( \
> +	                TREE_TYPE (TREE_OPERAND (EXP, 0)))))))
> +
>  /* Define many boolean fields that all tree nodes have.  */
>  
>  /* In VAR_DECL, PARM_DECL and RESULT_DECL nodes, nonzero means address
> @@ -812,6 +830,14 @@ extern void omp_clause_range_check_faile
>  #define DECL_UNSIGNED(NODE) \
>    (DECL_COMMON_CHECK (NODE)->base.u.bits.unsigned_flag)
>  
> +/* Convert tree flags to type qualifiers.  */
> +#define TREE_QUALS(NODE)				\
> +  ((TREE_READONLY(NODE) * TYPE_QUAL_CONST) |		\
> +   (TREE_THIS_VOLATILE(NODE) * TYPE_QUAL_VOLATILE) |	\
> +   (TREE_SHARED(NODE) * TYPE_QUAL_SHARED) |		\
> +   (TREE_STRICT(NODE) * TYPE_QUAL_STRICT) |		\
> +   (TREE_RELAXED(NODE) * TYPE_QUAL_RELAXED))
> +
>  /* In integral and pointer types, means an unsigned type.  */
>  #define TYPE_UNSIGNED(NODE) (TYPE_CHECK (NODE)->base.u.bits.unsigned_flag)
>  
> @@ -941,6 +967,11 @@ extern void omp_clause_range_check_faile
>  #define IDENTIFIER_TRANSPARENT_ALIAS(NODE) \
>    (IDENTIFIER_NODE_CHECK (NODE)->base.deprecated_flag)
>  
> +/* Shared, strict, and relaxed common tree flags */
> +#define TREE_SHARED(NODE) ((NODE)->base.u.bits.shared_flag)
> +#define TREE_STRICT(NODE) ((NODE)->base.u.bits.strict_flag)
> +#define TREE_RELAXED(NODE) ((NODE)->base.u.bits.relaxed_flag)
> +
>  /* In an aggregate type, indicates that the scalar fields of the type are
>     stored in reverse order from the target order.  This effectively
>     toggles BYTES_BIG_ENDIAN and WORDS_BIG_ENDIAN within the type.  */
> @@ -1887,6 +1918,21 @@ extern machine_mode element_mode (const_
>     the term.  */
>  #define TYPE_RESTRICT(NODE) (TYPE_CHECK (NODE)->type_common.restrict_flag)
>  
> +/* If nonzero, this type is `shared'-qualified, in the UPC dialect */
> +#define TYPE_SHARED(NODE) (TYPE_CHECK (NODE)->base.u.bits.shared_flag)
> +
> +/* If nonzero, this type is `strict'-qualified, in the UPC dialect  */
> +#define TYPE_STRICT(NODE) (TYPE_CHECK (NODE)->base.u.bits.strict_flag)
> +
> +/* If nonzero, this type is `relaxed'-qualified, in the UPC dialect  */
> +#define TYPE_RELAXED(NODE) \
> +  (TYPE_CHECK (NODE)->base.u.bits.relaxed_flag)
> +
> +/* Record that we are processing a UPC shared array declaration
> +   or type definition that refers to THREADS in its array dimension.*/
> +#define TYPE_HAS_THREADS_FACTOR(NODE) \
> +  (TYPE_CHECK (NODE)->base.u.bits.threads_factor_flag)
> +
>  /* If nonzero, type's name shouldn't be emitted into debug info.  */
>  #define TYPE_NAMELESS(NODE) (TYPE_CHECK (NODE)->base.u.bits.nameless_flag)
>  
> @@ -1911,13 +1957,24 @@ extern machine_mode element_mode (const_
>  	  | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE)		\
>  	  | (TYPE_ATOMIC (NODE) * TYPE_QUAL_ATOMIC)		\
>  	  | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT)		\
> +	  | (TYPE_SHARED (NODE) * TYPE_QUAL_SHARED)		\
> +	  | (TYPE_STRICT (NODE) * TYPE_QUAL_STRICT)		\
> +	  | (TYPE_RELAXED (NODE) * TYPE_QUAL_RELAXED)		\
>  	  | (ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (NODE)))))
>  
> +/* The set of qualifiers pertinent to a FUNCTION_DECL node.  */
> +#define TREE_FUNC_QUALS(NODE)				\
> +  ((TREE_READONLY (NODE) * TYPE_QUAL_CONST)		\
> +   | (TREE_THIS_VOLATILE (NODE) * TYPE_QUAL_VOLATILE))
> +
>  /* The same as TYPE_QUALS without the address space qualifications.  */
>  #define TYPE_QUALS_NO_ADDR_SPACE(NODE)				\
>    ((int) ((TYPE_READONLY (NODE) * TYPE_QUAL_CONST)		\
>  	  | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE)		\
>  	  | (TYPE_ATOMIC (NODE) * TYPE_QUAL_ATOMIC)		\
> +	  | (TYPE_SHARED (NODE) * TYPE_QUAL_SHARED)		\
> +	  | (TYPE_STRICT (NODE) * TYPE_QUAL_STRICT)		\
> +	  | (TYPE_RELAXED (NODE) * TYPE_QUAL_RELAXED)		\
>  	  | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT)))
>  
>  /* The same as TYPE_QUALS without the address space and atomic 
> @@ -1925,8 +1982,72 @@ extern machine_mode element_mode (const_
>  #define TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC(NODE)		\
>    ((int) ((TYPE_READONLY (NODE) * TYPE_QUAL_CONST)		\
>  	  | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE)		\
> +          | (TYPE_SHARED (NODE) * TYPE_QUAL_SHARED)		\
> +          | (TYPE_STRICT (NODE) * TYPE_QUAL_STRICT)		\
> +          | (TYPE_RELAXED (NODE) * TYPE_QUAL_RELAXED)		\
>  	  | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT)))
>  
> +/* Non-zero if the blocking factor is 0.  */
> +#define TYPE_HAS_BLOCK_FACTOR_0(NODE)  \
> +  TYPE_CHECK (NODE)->base.u.bits.block_factor_0
> +
> +/* Non-zero if the blocking factor is greater than 1.
> +   In this case, the blocking factor value is stored in a hash table.  */
> +#define TYPE_HAS_BLOCK_FACTOR_X(NODE) \
> +  TYPE_CHECK (NODE)->base.u.bits.block_factor_x
> +
> +/* Non-zero if the blocking factor is not equal to 1 (the default).  */
> +#define TYPE_HAS_BLOCK_FACTOR(NODE) \
> +  (TYPE_SHARED(NODE) \
> +   && (TYPE_HAS_BLOCK_FACTOR_0 (NODE) \
> +       || TYPE_HAS_BLOCK_FACTOR_X (NODE)))
> +
> +/* Return the blocking factor of the type given by NODE..
> +   The default block factor is one.  The additional flag bits
> +   over-ride the default.  */
> +#define TYPE_BLOCK_FACTOR(NODE) \
> +  (TYPE_SHARED (NODE) \
> +    ? (TYPE_HAS_BLOCK_FACTOR_0 (NODE) ? size_zero_node \
> +      : TYPE_HAS_BLOCK_FACTOR_X (NODE) ? block_factor_lookup (NODE) \
> +      : NULL_TREE) \
> +    : NULL_TREE)
> +
> +/* Set the block factor in the type described by NODE.
> +   For a zero blocking factor set TYPE_BLOCK_FACTOR_0 (NODE). 
> +   For a blocking factor greater than 1, insert the value
> +   into a hash table indexed by NODE, and then set the
> +   flag TYPE_BLOCK_FACTOR_X (NODE).  */
> +#define SET_TYPE_BLOCK_FACTOR(NODE, VAL) \
> +  do { \
> +    if (TYPE_SHARED (NODE)) \
> +      { \
> +	TYPE_HAS_BLOCK_FACTOR_0 (NODE) = 0; \
> +	TYPE_HAS_BLOCK_FACTOR_X (NODE) = 0; \
> +	if (VAL) \
> +	  { \
> +	    gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (VAL))); \
> +	    if (!integer_onep (VAL)) \
> +	      { \
> +		if (integer_zerop (VAL)) \
> +		  TYPE_HAS_BLOCK_FACTOR_0 (NODE) = 1; \
> +		else \
> +		  { \
> +		    TYPE_HAS_BLOCK_FACTOR_X (NODE) = 1; \
> +		    block_factor_insert (NODE, VAL); \
> +		  } \
> +	      } \
> +          } \
> +      } \
> +    else \
> +      gcc_assert (!VAL); \
> +  } while (0)
> +

Use a function please.  No such unwiedlingly large macros.

> +extern void block_factor_insert (tree, tree);
> +extern tree block_factor_lookup (const_tree);
> +extern tree build_unshared_type (tree);
> +extern void block_factor_lookup_init (void);
> +extern tree get_block_factor (const tree);
> +
>  /* These flags are available for each language front end to use internally.  */
>  #define TYPE_LANG_FLAG_0(NODE) (TYPE_CHECK (NODE)->type_common.lang_flag_0)
>  #define TYPE_LANG_FLAG_1(NODE) (TYPE_CHECK (NODE)->type_common.lang_flag_1)
> @@ -2176,7 +2297,7 @@ extern machine_mode element_mode (const_
>  /* Nonzero if DECL represents an SSA name or a variable that can possibly
>     have an associated SSA name.  */
>  #define SSA_VAR_P(DECL)							\
> -	(TREE_CODE (DECL) == VAR_DECL					\
> +	((TREE_CODE (DECL) == VAR_DECL && !TREE_SHARED (DECL))          \
>  	 || TREE_CODE (DECL) == PARM_DECL				\
>  	 || TREE_CODE (DECL) == RESULT_DECL				\
>  	 || TREE_CODE (DECL) == SSA_NAME)
> @@ -3611,6 +3732,17 @@ tree_operand_check_code (const_tree __t,
>  #define boolean_false_node		global_trees[TI_BOOLEAN_FALSE]
>  #define boolean_true_node		global_trees[TI_BOOLEAN_TRUE]
>  
> +/* The UPC type `void *'.  */
> +#define upc_pts_type_node	global_trees[TI_UPC_PTS_TYPE]
> +
> +/* UPC pointer to shared qualified object representation */
> +#define upc_pts_rep_type_node	global_trees[TI_UPC_PTS_REP_TYPE]
> +#define upc_char_pts_type_node	global_trees[TI_UPC_CHAR_PTS_TYPE]
> +#define upc_phase_field_node	global_trees[TI_UPC_PHASE_FIELD]
> +#define upc_thread_field_node	global_trees[TI_UPC_THREAD_FIELD]
> +#define upc_vaddr_field_node	global_trees[TI_UPC_VADDR_FIELD]
> +#define upc_null_pts_node	global_trees[TI_UPC_NULL_PTS]
> +

Ugh.  Please no further global tree nodes.  Do you really need all of
them in middle-end code?

Richard.

>  /* The decimal floating point types. */
>  #define dfloat32_type_node              global_trees[TI_DFLOAT32_TYPE]
>  #define dfloat64_type_node              global_trees[TI_DFLOAT64_TYPE]
> @@ -4151,20 +4283,25 @@ extern tree handle_dll_attribute (tree *
>  extern bool check_base_type (const_tree cand, const_tree base);
>  
>  /* Check whether CAND is suitable to be returned from get_qualified_type
> -   (BASE, TYPE_QUALS).  */
> +   (BASE, TYPE_QUALS, BLOCK_FACTOR).  */
>  
> -extern bool check_qualified_type (const_tree, const_tree, int);
> +extern bool check_qualified_type (const_tree cand, const_tree base,
> +				  int type_quals, tree block_factor);
>  
>  /* Return a version of the TYPE, qualified as indicated by the
> -   TYPE_QUALS, if one exists.  If no qualified version exists yet,
> -   return NULL_TREE.  */
> +   TYPE_QUALS and BLOCK_FACTOR, if one exists.
> +   If no qualified version exists yet, return NULL_TREE.  */
>  
> -extern tree get_qualified_type (tree, int);
> +extern tree get_qualified_type_1 (tree type, int type_quals, tree block_factor);
> +#define get_qualified_type(TYPE, QUALS) \
> +          get_qualified_type_1 (TYPE, QUALS, 0)
>  
>  /* Like get_qualified_type, but creates the type if it does not
>     exist.  This function never returns NULL_TREE.  */
>  
> -extern tree build_qualified_type (tree, int);
> +extern tree build_qualified_type_1 (tree type, int type_quals, tree block_factor);
> +#define build_qualified_type(TYPE, QUALS) \
> +   build_qualified_type_1 (TYPE, QUALS, 0)
>  
>  /* Create a variant of type T with alignment ALIGN.  */
>  
> @@ -4195,6 +4332,7 @@ extern tree type_hash_canon (unsigned in
>  extern tree convert (tree, tree);
>  extern unsigned int expr_align (const_tree);
>  extern tree size_in_bytes (const_tree);
> +extern tree tree_expr_size (const_tree);
>  extern HOST_WIDE_INT int_size_in_bytes (const_tree);
>  extern HOST_WIDE_INT max_int_size_in_bytes (const_tree);
>  extern tree bit_position (const_tree);
>
Gary Funck Dec. 2, 2015, 6:43 p.m. UTC | #2
On 12/01/15 12:26:32, Richard Biener wrote:
> On Mon, 30 Nov 2015, Gary Funck wrote:
> > -struct GTY(()) tree_type_common {
> > +struct GTY((user)) tree_type_common {
> >    struct tree_common common;
> >    tree size;
> >    tree size_unit;
> > @@ -1441,10 +1458,10 @@ struct GTY(()) tree_type_common {
> >    tree pointer_to;
> >    tree reference_to;
> >    union tree_type_symtab {
> > -    int GTY ((tag ("TYPE_SYMTAB_IS_ADDRESS"))) address;
> > -    const char * GTY ((tag ("TYPE_SYMTAB_IS_POINTER"))) pointer;
> > -    struct die_struct * GTY ((tag ("TYPE_SYMTAB_IS_DIE"))) die;
> > -  } GTY ((desc ("debug_hooks->tree_type_symtab_field"))) symtab;
> > +    int address;
> > +    const char *pointer;
> > +    struct die_struct *die;
> > +  } symtab;
>
> Err, you don't have debug info for this?  What is address?

Not sure what you mean.  The 'die' field is retained.
Is there something in the semantics of "GTY(( ((tag "
that relates to debug information?

> I do not like the explict GC of tree_type_common.

I'm not a fan either.

The gist is that we needed a map from tree nodes to tree nodes
to record the "layout qualifier" for layout qualifiers with
a value greater than one.  But when the garbage collector ran
over the hash table that maps integer constants to tree nodes,
it didn't know that the constant was being referenced by the
layout qualifier tree map.

We described the issue here:
https://gcc.gnu.org/ml/gcc-patches/2011-10/msg00800.html

The conclusion that we reached is that when tree nodes
were walked, we needed to check if there was a
tree node -> integer constant mapping, the integer constant map
(used to make tree nodes used to hold CST's unique)
needed to be marked to keep the CST mapping from going away.

This led to the conclusion that a custom GC routine was
needed for tree nodes.  Maybe that conclusion is wrong or
there is a better way to do things?

> > ===================================================================
> > --- gcc/tree-pretty-print.c	(.../trunk)	(revision 231059)
> > +++ gcc/tree-pretty-print.c	(.../branches/gupc)	(revision 231080)
> > @@ -1105,6 +1105,25 @@ dump_block_node (pretty_printer *pp, tre
> >  }
> >  
> >  
> > +static void
> > +dump_upc_type_quals (pretty_printer *buffer, tree type, int quals)
>
> Functions need comments.

OK.  Missed that one.  Will check on others.

> > Index: gcc/tree-sra.c
> > ===================================================================
> > --- gcc/tree-sra.c	(.../trunk)	(revision 231059)
> > +++ gcc/tree-sra.c	(.../branches/gupc)	(revision 231080)
> > @@ -3882,6 +3882,7 @@ find_param_candidates (void)
> >  
> >  	  if (TREE_CODE (type) == FUNCTION_TYPE
> >  	      || TYPE_VOLATILE (type)
> > +	      || SHARED_TYPE_P (type)
> 
> UPC_SHARED_TYPE_P ()

OK. As I mentioned in a previous reply, originally we prefixed
all "UPC" specific tree node fields and functions with UPC_ or upc_,
but as we transitioned away from UPC as a separate language
(ala ObjC) and made compilation conditional upon -fupc, an
observation was made off list that since the base tree nodes
are generic that naming UPC-related fields with "UPC" prefixes
didn't make sense, so we removed those prefixes.  There might
be a middle ground, however, whee UPC_SHARED_TYPE_P() is preferred
to SHARED_TYPE_P() because as you/others have mentioned,
the term "shared" gets used in a lot of contexts.

> > @@ -4381,6 +4422,7 @@ build1_stat (enum tree_code code, tree t
> >        /* Whether a dereference is readonly has nothing to do with whether
> >  	 its operand is readonly.  */
> >        TREE_READONLY (t) = 0;
> > +      TREE_SHARED (t) = SHARED_TYPE_P (type);
> 
> This is frontend logic and should reside in FEs.

[... several other similar actions taken contingent
upon SHARED_TYPE_P() elided ...]

OK, will take a look.

> > +  outer_is_pts_p = (POINTER_TYPE_P (outer_type)
> > +                    && SHARED_TYPE_P (TREE_TYPE (outer_type)));
> > +  inner_is_pts_p = (POINTER_TYPE_P (inner_type)
> > +                    && SHARED_TYPE_P (TREE_TYPE (inner_type)));
> > +
> > +  /* Pointer-to-shared types have special
> > +     equivalence rules that must be checked.  */
> > +  if (outer_is_pts_p && inner_is_pts_p
> > +      && lang_hooks.types_compatible_p)
> > +    return lang_hooks.types_compatible_p (outer_type, inner_type);
> 
> Sorry, but that can't fly with LTO.

Can you elaborate?  I'm not familiar with LTO or its requirements.

> I wonder why you didn't use address-spaces for whatever
> UPC needs for pointers.

Background: UPC pointers have special language defined rules
for address arithmetic.  In the simplest case, adding 1 to a UPC
pointer-to-shared increments the thread part of the pointer, until
it exceeds the number of threads in the program, at that point,
the "virtual address" (often an offset into the program's global
shared region) is incremented by the size of the element type.
Since UPC pointers have a thread field and block offset (phase)
field, they're 2x the size of a regular "C" pointer.

When we started working on UPC, GCC didn't have address space support,
and from what I can tell from watching commits,
address space support has improved over time.

Is it the case now that I could define a pointer to a special
(reserved for UPC) address space that can have a mode that is, say,
2x the size of a regular pointer mode?  That would help.
That would help in the cases where we need the compiler to
use a different underlying mode for UPC pointers-to-shared.

We would also still need to make sure that the parts of the
compiler that think that pointers are interchangeable with
integers doesn't do that with UPC pointers-to-shared.

> > +/* Return a variant of TYPE, where the shared, strict, and relaxed
> > +   qualifiers have been removed.  */
> > +
> > +tree
> > +build_unshared_type (tree type)
> 
> Too generic names.  I'd prefer if these routines were in a upc.c
> file rather than in tree.c.  Likewise for the block hash I suppose.

As discussed previously, we used to prefix all UPC-related functions
and types with UPC_ or upc_.  It would be easy to bring that back.

However, not sure how that squares with the off-list feedback
that we received: If we add fields to the base tree type,
they should not have language specific names in them.

> > +/* Set the block factor in the type described by NODE.
> > +   For a zero blocking factor set TYPE_BLOCK_FACTOR_0 (NODE). 
> > +   For a blocking factor greater than 1, insert the value
> > +   into a hash table indexed by NODE, and then set the
> > +   flag TYPE_BLOCK_FACTOR_X (NODE).  */
> > +#define SET_TYPE_BLOCK_FACTOR(NODE, VAL) \
> > [...]
> 
> Use a function please.  No such unwiedlingly large macros.

OK.  Are static inline's OK here?

> > +/* UPC pointer to shared qualified object representation */
> > +#define upc_pts_rep_type_node	global_trees[TI_UPC_PTS_REP_TYPE]
> > +#define upc_char_pts_type_node	global_trees[TI_UPC_CHAR_PTS_TYPE]
> > +#define upc_phase_field_node	global_trees[TI_UPC_PHASE_FIELD]
> > +#define upc_thread_field_node	global_trees[TI_UPC_THREAD_FIELD]
> > +#define upc_vaddr_field_node	global_trees[TI_UPC_VADDR_FIELD]
> > +#define upc_null_pts_node	global_trees[TI_UPC_NULL_PTS]
> > +
> 
> Ugh.  Please no further global tree nodes.
> Do you really need all of them in middle-end code?

Apart from tree.[ch], here is where those fields are referenced.

c/c-parser.c
c/c-typeck.c
c/c-upc.c
c/c-upc-lang.c
c/c-upc-low.c
c/c-upc-pts-ops.c
c-family/c-common.c
config/i386/i386.c
config/rs6000/rs6000.c
convert.c
function.c
tree-pretty-print.c

Where do you draw the line between front-end and middle-end?
Is everything after c_genericize() considered middle-end?

We definitely need those global tree nodes up through upc_genericize(),
which is called just before c_genericize().  We might be able to
do away with upc_phase_field_node, upc_thread_field_node,
and upc_vaddr_field_node and find them in upc_pts_rep_type_node,
which is struct with those fields.

In config/i386/i386.c, we only need the mode of the internal
representation of a UPC pointer-to-shared type.

  if (type != NULL_TREE && POINTER_TYPE_P (type))
    {
      if (SHARED_TYPE_P (TREE_TYPE (type)))
        {
          *punsignedp = 1;
          return TYPE_MODE (upc_pts_rep_type_node);
        }
      *punsignedp = POINTERS_EXTEND_UNSIGNED;
      return word_mode;
    }

In config/rs6000/rs6000.c, we need to know if the UPC pointer-to-shared
internal representation is an aggregate type.


  /* TRUE if TYPE is a UPC pointer-to-shared type
     and its underlying representation is an aggregate.  */
  bool upc_struct_pts_p = (POINTER_TYPE_P (type)
                             && SHARED_TYPE_P (TREE_TYPE (type)))
                           && AGGREGATE_TYPE_P (upc_pts_rep_type_node);
  /* If TYPE is a UPC struct PTS type, handle it as an aggregate type.  */
  bool aggregate_p = AGGREGATE_TYPE_P (type)
                     || upc_struct_pts_p;

Until recently, we supported two internal representation types,
packed and struct.  The packed representation was an int64
but couldn't express the full range for threads, virtual address,
and block offset.  So we decided to go only with 'struct'.
That makes the test for AGGREGATE_TYPE_P (upc_pts_rep_type_node)
redundant above, but left it there because we felt that it had
some descriptive value.

Looks like both of those target dependent references to
upc_pts_rep_type_node could go away if they need to.

thanks,
- Gary
Richard Biener Dec. 3, 2015, 11:07 a.m. UTC | #3
On Wed, 2 Dec 2015, Gary Funck wrote:

> On 12/01/15 12:26:32, Richard Biener wrote:
> > On Mon, 30 Nov 2015, Gary Funck wrote:
> > > -struct GTY(()) tree_type_common {
> > > +struct GTY((user)) tree_type_common {
> > >    struct tree_common common;
> > >    tree size;
> > >    tree size_unit;
> > > @@ -1441,10 +1458,10 @@ struct GTY(()) tree_type_common {
> > >    tree pointer_to;
> > >    tree reference_to;
> > >    union tree_type_symtab {
> > > -    int GTY ((tag ("TYPE_SYMTAB_IS_ADDRESS"))) address;
> > > -    const char * GTY ((tag ("TYPE_SYMTAB_IS_POINTER"))) pointer;
> > > -    struct die_struct * GTY ((tag ("TYPE_SYMTAB_IS_DIE"))) die;
> > > -  } GTY ((desc ("debug_hooks->tree_type_symtab_field"))) symtab;
> > > +    int address;
> > > +    const char *pointer;
> > > +    struct die_struct *die;
> > > +  } symtab;
> >
> > Err, you don't have debug info for this?  What is address?
> 
> Not sure what you mean.  The 'die' field is retained.
> Is there something in the semantics of "GTY(( ((tag "
> that relates to debug information?

Ah, sorry.  I misread the diff.

> > I do not like the explict GC of tree_type_common.
> 
> I'm not a fan either.
> 
> The gist is that we needed a map from tree nodes to tree nodes
> to record the "layout qualifier" for layout qualifiers with
> a value greater than one.  But when the garbage collector ran
> over the hash table that maps integer constants to tree nodes,
> it didn't know that the constant was being referenced by the
> layout qualifier tree map.
> 
> We described the issue here:
> https://gcc.gnu.org/ml/gcc-patches/2011-10/msg00800.html
> 
> The conclusion that we reached is that when tree nodes
> were walked, we needed to check if there was a
> tree node -> integer constant mapping, the integer constant map
> (used to make tree nodes used to hold CST's unique)
> needed to be marked to keep the CST mapping from going away.
> 
> This led to the conclusion that a custom GC routine was
> needed for tree nodes.  Maybe that conclusion is wrong or
> there is a better way to do things?

It should simply work as long as the hash-map is properly marked
as GC root.  It might _not_ work (reliably) if the hash-map is
also a "cache" by itself.  But it eventually works now given some
fixes went into the area of collecting/marking caches.

> > > ===================================================================
> > > --- gcc/tree-pretty-print.c	(.../trunk)	(revision 231059)
> > > +++ gcc/tree-pretty-print.c	(.../branches/gupc)	(revision 231080)
> > > @@ -1105,6 +1105,25 @@ dump_block_node (pretty_printer *pp, tre
> > >  }
> > >  
> > >  
> > > +static void
> > > +dump_upc_type_quals (pretty_printer *buffer, tree type, int quals)
> >
> > Functions need comments.
> 
> OK.  Missed that one.  Will check on others.
> 
> > > Index: gcc/tree-sra.c
> > > ===================================================================
> > > --- gcc/tree-sra.c	(.../trunk)	(revision 231059)
> > > +++ gcc/tree-sra.c	(.../branches/gupc)	(revision 231080)
> > > @@ -3882,6 +3882,7 @@ find_param_candidates (void)
> > >  
> > >  	  if (TREE_CODE (type) == FUNCTION_TYPE
> > >  	      || TYPE_VOLATILE (type)
> > > +	      || SHARED_TYPE_P (type)
> > 
> > UPC_SHARED_TYPE_P ()
> 
> OK. As I mentioned in a previous reply, originally we prefixed
> all "UPC" specific tree node fields and functions with UPC_ or upc_,
> but as we transitioned away from UPC as a separate language
> (ala ObjC) and made compilation conditional upon -fupc, an
> observation was made off list that since the base tree nodes
> are generic that naming UPC-related fields with "UPC" prefixes
> didn't make sense, so we removed those prefixes.  There might
> be a middle ground, however, whee UPC_SHARED_TYPE_P() is preferred
> to SHARED_TYPE_P() because as you/others have mentioned,
> the term "shared" gets used in a lot of contexts.

Yes, specifically for predicates/functions used in the middle-end.

> > > @@ -4381,6 +4422,7 @@ build1_stat (enum tree_code code, tree t
> > >        /* Whether a dereference is readonly has nothing to do with whether
> > >  	 its operand is readonly.  */
> > >        TREE_READONLY (t) = 0;
> > > +      TREE_SHARED (t) = SHARED_TYPE_P (type);
> > 
> > This is frontend logic and should reside in FEs.
> 
> [... several other similar actions taken contingent
> upon SHARED_TYPE_P() elided ...]
> 
> OK, will take a look.
> 
> > > +  outer_is_pts_p = (POINTER_TYPE_P (outer_type)
> > > +                    && SHARED_TYPE_P (TREE_TYPE (outer_type)));
> > > +  inner_is_pts_p = (POINTER_TYPE_P (inner_type)
> > > +                    && SHARED_TYPE_P (TREE_TYPE (inner_type)));
> > > +
> > > +  /* Pointer-to-shared types have special
> > > +     equivalence rules that must be checked.  */
> > > +  if (outer_is_pts_p && inner_is_pts_p
> > > +      && lang_hooks.types_compatible_p)
> > > +    return lang_hooks.types_compatible_p (outer_type, inner_type);
> > 
> > Sorry, but that can't fly with LTO.
> 
> Can you elaborate?  I'm not familiar with LTO or its requirements.

With LTO the langhooks from the frontends are no longer available
so you'd need to implement the same logic in the LTO "frontend"
which means it wouldn't need a langhook at all because all information
would be contained in the middle-end representations.

> > I wonder why you didn't use address-spaces for whatever
> > UPC needs for pointers.
> 
> Background: UPC pointers have special language defined rules
> for address arithmetic.  In the simplest case, adding 1 to a UPC
> pointer-to-shared increments the thread part of the pointer, until
> it exceeds the number of threads in the program, at that point,
> the "virtual address" (often an offset into the program's global
> shared region) is incremented by the size of the element type.
> Since UPC pointers have a thread field and block offset (phase)
> field, they're 2x the size of a regular "C" pointer.
> 
> When we started working on UPC, GCC didn't have address space support,
> and from what I can tell from watching commits,
> address space support has improved over time.
> 
> Is it the case now that I could define a pointer to a special
> (reserved for UPC) address space that can have a mode that is, say,
> 2x the size of a regular pointer mode?  That would help.
> That would help in the cases where we need the compiler to
> use a different underlying mode for UPC pointers-to-shared.
> 
> We would also still need to make sure that the parts of the
> compiler that think that pointers are interchangeable with
> integers doesn't do that with UPC pointers-to-shared.

I'm not very familiar with address-spaces but at least they
can be used to distinguish different pointer kinds (and prevent
conversions).  Not sure if it would allow different behavior
for a simple plus.

Note that I belive you should lower your "pointer" representation
when you lower the rest (I suppose you lower this now only during
RTL generation?)

> > > +/* Return a variant of TYPE, where the shared, strict, and relaxed
> > > +   qualifiers have been removed.  */
> > > +
> > > +tree
> > > +build_unshared_type (tree type)
> > 
> > Too generic names.  I'd prefer if these routines were in a upc.c
> > file rather than in tree.c.  Likewise for the block hash I suppose.
> 
> As discussed previously, we used to prefix all UPC-related functions
> and types with UPC_ or upc_.  It would be easy to bring that back.
> 
> However, not sure how that squares with the off-list feedback
> that we received: If we add fields to the base tree type,
> they should not have language specific names in them.
> 
> > > +/* Set the block factor in the type described by NODE.
> > > +   For a zero blocking factor set TYPE_BLOCK_FACTOR_0 (NODE). 
> > > +   For a blocking factor greater than 1, insert the value
> > > +   into a hash table indexed by NODE, and then set the
> > > +   flag TYPE_BLOCK_FACTOR_X (NODE).  */
> > > +#define SET_TYPE_BLOCK_FACTOR(NODE, VAL) \
> > > [...]
> > 
> > Use a function please.  No such unwiedlingly large macros.
> 
> OK.  Are static inline's OK here?

Implementations in non-headers are prefered, but yes.

> > > +/* UPC pointer to shared qualified object representation */
> > > +#define upc_pts_rep_type_node	global_trees[TI_UPC_PTS_REP_TYPE]
> > > +#define upc_char_pts_type_node	global_trees[TI_UPC_CHAR_PTS_TYPE]
> > > +#define upc_phase_field_node	global_trees[TI_UPC_PHASE_FIELD]
> > > +#define upc_thread_field_node	global_trees[TI_UPC_THREAD_FIELD]
> > > +#define upc_vaddr_field_node	global_trees[TI_UPC_VADDR_FIELD]
> > > +#define upc_null_pts_node	global_trees[TI_UPC_NULL_PTS]
> > > +
> > 
> > Ugh.  Please no further global tree nodes.
> > Do you really need all of them in middle-end code?
> 
> Apart from tree.[ch], here is where those fields are referenced.
> 
> c/c-parser.c
> c/c-typeck.c
> c/c-upc.c
> c/c-upc-lang.c
> c/c-upc-low.c
> c/c-upc-pts-ops.c
> c-family/c-common.c
> config/i386/i386.c
> config/rs6000/rs6000.c
> convert.c
> function.c
> tree-pretty-print.c
> 
> Where do you draw the line between front-end and middle-end?
> Is everything after c_genericize() considered middle-end?

After gimplification.  I realize the global trees are in a messy
state already and most of them should be moved to frontend specific
places.  It would be a start if you do that.  And lowering your
pointer representation earlier will probably make that easier.

Richard.

> We definitely need those global tree nodes up through upc_genericize(),
> which is called just before c_genericize().  We might be able to
> do away with upc_phase_field_node, upc_thread_field_node,
> and upc_vaddr_field_node and find them in upc_pts_rep_type_node,
> which is struct with those fields.
> 
> In config/i386/i386.c, we only need the mode of the internal
> representation of a UPC pointer-to-shared type.
> 
>   if (type != NULL_TREE && POINTER_TYPE_P (type))
>     {
>       if (SHARED_TYPE_P (TREE_TYPE (type)))
>         {
>           *punsignedp = 1;
>           return TYPE_MODE (upc_pts_rep_type_node);
>         }
>       *punsignedp = POINTERS_EXTEND_UNSIGNED;
>       return word_mode;
>     }
> 
> In config/rs6000/rs6000.c, we need to know if the UPC pointer-to-shared
> internal representation is an aggregate type.
> 
> 
>   /* TRUE if TYPE is a UPC pointer-to-shared type
>      and its underlying representation is an aggregate.  */
>   bool upc_struct_pts_p = (POINTER_TYPE_P (type)
>                              && SHARED_TYPE_P (TREE_TYPE (type)))
>                            && AGGREGATE_TYPE_P (upc_pts_rep_type_node);
>   /* If TYPE is a UPC struct PTS type, handle it as an aggregate type.  */
>   bool aggregate_p = AGGREGATE_TYPE_P (type)
>                      || upc_struct_pts_p;
> 
> Until recently, we supported two internal representation types,
> packed and struct.  The packed representation was an int64
> but couldn't express the full range for threads, virtual address,
> and block offset.  So we decided to go only with 'struct'.
> That makes the test for AGGREGATE_TYPE_P (upc_pts_rep_type_node)
> redundant above, but left it there because we felt that it had
> some descriptive value.
> 
> Looks like both of those target dependent references to
> upc_pts_rep_type_node could go away if they need to.
Gary Funck Dec. 6, 2015, 12:20 a.m. UTC | #4
On 12/03/15 12:07:35, Richard Biener wrote:
> On Wed, 2 Dec 2015, Gary Funck wrote:
> > OK. As I mentioned in a previous reply, originally we prefixed
> > all "UPC" specific tree node fields and functions with UPC_ or upc_,
> > but as we transitioned away from UPC as a separate language
> > (ala ObjC) and made compilation conditional upon -fupc, an
> > observation was made off list that since the base tree nodes
> > are generic that naming UPC-related fields with "UPC" prefixes
> > didn't make sense, so we removed those prefixes.  There might
> > be a middle ground, however, whee UPC_SHARED_TYPE_P() is preferred
> > to SHARED_TYPE_P() because as you/others have mentioned,
> > the term "shared" gets used in a lot of contexts.
> 
> Yes, specifically for predicates/functions used in the middle-end.

OK
 
> > > > +  outer_is_pts_p = (POINTER_TYPE_P (outer_type)
> > > > +                    && SHARED_TYPE_P (TREE_TYPE (outer_type)));
> > > > +  inner_is_pts_p = (POINTER_TYPE_P (inner_type)
> > > > +                    && SHARED_TYPE_P (TREE_TYPE (inner_type)));
> > > > +
> > > > +  /* Pointer-to-shared types have special
> > > > +     equivalence rules that must be checked.  */
> > > > +  if (outer_is_pts_p && inner_is_pts_p
> > > > +      && lang_hooks.types_compatible_p)
> > > > +    return lang_hooks.types_compatible_p (outer_type, inner_type);
> > > 
> > > Sorry, but that can't fly with LTO.
> > 
> > Can you elaborate?  I'm not familiar with LTO or its requirements.
> 
> With LTO the langhooks from the frontends are no longer available
> so you'd need to implement the same logic in the LTO "frontend"
> which means it wouldn't need a langhook at all because all information
> would be contained in the middle-end representations.

Still not quite understanding this one.  Will need to take
a more detailed look at LTO.

> > We would also still need to make sure that the parts of the
> > compiler that think that pointers are interchangeable with
> > integers doesn't do that with UPC pointers-to-shared.
> 
> I'm not very familiar with address-spaces but at least they
> can be used to distinguish different pointer kinds (and prevent
> conversions).  Not sure if it would allow different behavior
> for a simple plus.
> 
> Note that I belive you should lower your "pointer" representation
> when you lower the rest (I suppose you lower this now only during
> RTL generation?)

We lower all *operations* (plus/minus, get/put, conversions)
in the UPC lowering pass, which runs just before c_genericize().
We retain the pointer-to-shared-qualified type in the tree,
often wrapped by a conversion to the internal representation type.

As I mentioned previously, we ran into some issues try to lower
to just the representation type, but I don't recall the specifics.
I can try and check on that.

The RTL will see the pointer-to-shared types, but won't see
things like indirections through them, addition/subtraction and
so on, because that was handled in the lowering pass.

We could probably lower most all things in the front-end when
the program is being parsed, but it would make the initial
tree difficult to understand and would push the lowering
logic into front-end/parser which makes the implementation
less modular.

> > > Use a function please.  No such unwiedlingly large macros.
> > 
> > OK.  Are static inline's OK here?
> 
> Implementations in non-headers are prefered, but yes.

I doubt that performance will be impacted much by making the call
out-of-line.  Will take a look into whether that is feasible.

> > > > +/* UPC pointer to shared qualified object representation */
> > > > +#define upc_pts_rep_type_node	global_trees[TI_UPC_PTS_REP_TYPE]
> > > > +#define upc_char_pts_type_node	global_trees[TI_UPC_CHAR_PTS_TYPE]
> > > > +#define upc_phase_field_node	global_trees[TI_UPC_PHASE_FIELD]
> > > > +#define upc_thread_field_node	global_trees[TI_UPC_THREAD_FIELD]
> > > > +#define upc_vaddr_field_node	global_trees[TI_UPC_VADDR_FIELD]
> > > > +#define upc_null_pts_node	global_trees[TI_UPC_NULL_PTS]
> > > > +
> > > 
> > > Ugh.  Please no further global tree nodes.
> > > Do you really need all of them in middle-end code?
> [...]
> After gimplification.  I realize the global trees are in a messy
> state already and most of them should be moved to frontend specific
> places.  It would be a start if you do that.  And lowering your
> pointer representation earlier will probably make that easier.

I will review the code to see if they can be moved to front-end
specific procedures/files.
diff mbox

Patch

--- gcc/tree-core.h     (.../trunk)     (revision 228959)
+++ gcc/tree-core.h     (.../branches/gupc)     (revision 229159)
@@ -470,7 +470,11 @@  enum cv_qualifier {
   TYPE_QUAL_CONST    = 0x1,
   TYPE_QUAL_VOLATILE = 0x2,
   TYPE_QUAL_RESTRICT = 0x4,
-  TYPE_QUAL_ATOMIC   = 0x8
+  TYPE_QUAL_ATOMIC   = 0x8,
+  /* UPC qualifiers */
+  TYPE_QUAL_SHARED   = 0x10,
+  TYPE_QUAL_RELAXED  = 0x20,
+  TYPE_QUAL_STRICT   = 0x40
 };
[...]
@@ -857,9 +875,14 @@  struct GTY(()) tree_base {
       unsigned user_align : 1;
       unsigned nameless_flag : 1;
       unsigned atomic_flag : 1;
-      unsigned spare0 : 3;
-
-      unsigned spare1 : 8;
+      unsigned shared_flag : 1;
+      unsigned strict_flag : 1;
+      unsigned relaxed_flag : 1;
+
+      unsigned threads_factor_flag : 1;
+      unsigned block_factor_0 : 1;
+      unsigned block_factor_x : 1;
+      unsigned spare1 : 5;

A given type is a UPC shared type if its 'shared_flag' is set.
However, for array types, the shared_flag of the *element type*
must be checked.  Thus,

    /* Return TRUE if TYPE is a shared type.  For arrays,
       the element type must be queried, because array types
       are never qualified.  */
    #define SHARED_TYPE_P(TYPE) \
      ((TYPE) && TYPE_P (TYPE) \
       && TYPE_SHARED ((TREE_CODE (TYPE) != ARRAY_TYPE \
                        ? (TYPE) : strip_array_types (TYPE))))

By default, a type has a blocking factor of 1.  If the blocking factor is 0
(known as "indefinite") then 'block_factor_0' is set. If the blocking
factor is neither 0 nor 1, then 'block_factor_x' is set and the
actual blocking factor is found in a 'tree map' hash table called
'block_factor_htab' which is managed in tree.c.

This use of a garbage collected hash table which maps tree nodes to
a UPC blocking factor leads to a need to implement custom garbage
collection logic for all tree nodes.  This custom garbage collection
logic is implemented in gt_ggc_mx().  PCH support is implemented
in gt_pch_nx().  This custom garbage collector is defined in tree-core.h
as follows:

-struct GTY(()) tree_type_common {
+struct GTY((user)) tree_type_common {
   struct tree_common common;
   tree size;
   tree size_unit;
[...]
   tree pointer_to;
   tree reference_to;
   union tree_type_symtab {
-    int GTY ((tag ("TYPE_SYMTAB_IS_ADDRESS"))) address;
-    const char * GTY ((tag ("TYPE_SYMTAB_IS_POINTER"))) pointer;
-    struct die_struct * GTY ((tag ("TYPE_SYMTAB_IS_DIE"))) die;
-  } GTY ((desc ("debug_hooks->tree_type_symtab_field"))) symtab;
+    int address;
+    const char *pointer;
+    struct die_struct *die;
+  } symtab;
   tree canonical;
   tree next_variant;

Above, 'tree_type_symtab' has to be explicitly traversed by
the garbage collection routine.

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

	gcc/
	* expr.c (tree_expr_size): Move to tree.c and make it an
	extern function.
	* print-tree.c (print_node): Print UPC "shared" qualifier
	and blocking factor (if present).  Indicate THREADS scaling,
	if present.
	* tree-core.h (cv_qualifier): Add UPC type qualifiers:
	TYPE_QUAL_SHARED, TYPE_QUAL_RELAXED, and TYPE_QUAL_STRICT.
	(tree_index): Add UPC tree indexes:
	TI_UPC_PTS_TYPE, TI_UPC_PTS_REP_TYPE, TI_UPC_CHAR_PTS_TYPE,
	TI_UPC_PHASE_FIELD, TI_UPC_THREAD_FIELD, TI_UPC_VADDR_FIELD,
	TI_UPC_NULL_PTS.
	(tree_base): Add UPC-specific flags:
	shared_flag, strict_flag, relaxed_flag, threads_factor_flag,
	block_factor_0, block_factor_x.
	(tree_type_common): Remove ggc tag type descriptions in
	tree_type_symtab fields to accommodate UPC-related garbage collection
	changes.
	(gt_ggc_mx, gt_pch_nx, gt_pch_nx): New prototypes.
	Add custom garbage collection and PCH support for tree_type_common.
	* tree-dump.c (dequeue_and_dump): Add qualifier tags for
	UPC language qualifier (shared, strict, relaxed).
	* tree-pretty-print.c (dump_upc_type_quals): Print UPC language
	qualifiers and blocking factor.
	(dump_generic_node): Call dump_upc_type_quals()
	if the type asserts the "shared" qualifier.
	Print UPC qualifiers if applied to a tree node.
	Print type name for the UPC pointer-to-shared representation type.
	* tree-sra.c (find_param_candidates):
	Exclude UPC pointer-to-shared types.
	* tree.c: #include "debug.h".  Needed for access to symtab
	definition in the tree node garbage collection logic.
	(tm_block_factor_hasher, block_factor_htab): New.
	Define a garbage-collected mapping from tree node to
	UPC blocking factor.
	(init_ttree): Call block_factor_lookup_init().
	(copy_node_stat): Call SET_TYPE_BLOCK_FACTOR if
	type has a UPC blocking factor.
	(tree_expr_size): Move from expr.c and make it an
	'extern' function.
	(stabilize_reference_1): Copy UPC qualifiers to result.
	(build1_stat): Copy shared qualifier from type node.
	(build1_stat, build2_stat): For unary and binary operations,
	remove UPC "shared" qualifiers from the result type.
	(build3_stat): For reference expressions, ensure that
	the result node preserves the UPC qualifiers applied to the
	first argument.
	(set_type_quals): Add a 'tree' argument for the
	UPC layout qualifier (blocking factor).  Set the blocking factor
	if the type asserts the "shared" qualifier.
	(check_qualified_type): Add a 'tree' argument for the
	UPC layout qualifier (blocking factor).  Include the blocking factor
	into the type check.
	(check_aligned_type): Include the blocking factor
	into the type check.
	(get_qualified_type_1): Rename get_qualified_type()
	to get_qualified_type_1() and add a blocking factor argument.
	A #define of get_qualified_type is added to tree.h;
	it will call get_qualified_type_1() with a null layout qualifier.
	(build_qualified_type): Adjust calls to
	get_qualified_type_1() and set_type_quals().
	(build_pointer_type): For UPC pointer-to-shared types
	ensure that the resulting pointer type is compatible with the
	UPC pointer-to-shared representation type.
	(build_atomic_base): Adjust call to set_type_quals().
	(build_opaque_vector_type):
	Adjust call to check_qualified_type().
	(tree_nop_conversion): Handle conversions involving
	UPC pointer-to-shared types.
	(gt_ggc_mx, gt_pch_nx, gt_pch_nx): Implement custom
	garbage collection logic, necessitated by the use of a garbage
	collected hash tree map used to look up UPC blocking factors.
	Contributed by Meador Inge <meadori@codesourcery.com>.
	(get_block_factor, build_unshared_type,
	block_factor_lookup, block_factor_insert,
	block_factor_lookup_init): New.
	* tree.h (SHARED_TYPE_P, PTS_CVT_OP_P, TREE_QUALS,
	TREE_SHARED, TREE_STRICT, TREE_RELAXED,
	TYPE_SHARED, TYPE_STRICT, TYPE_RELAXED, TYPE_HAS_THREADS_FACTOR,
	TREE_FUNC_QUALS, TYPE_HAS_BLOCK_FACTOR_0, TYPE_HAS_BLOCK_FACTOR_X,
	TYPE_HAS_BLOCK_FACTOR, SET_TYPE_BLOCK_FACTOR): New.
	(TYPE_QUALS, TYPE_QUALS_NO_ADDR_SPACE,
	TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC):
	Add UPC type qualifiers (shared, relaxed, strict).
	(block_factor_insert, block_factor_lookup,
	build_unshared_type, block_factor_lookup_init,
	get_block_factor): New.  Declare prototypes.
	(SSA_VAR_P): Exclude UPC shared types.
	(upc_pts_type_node, upc_pts_rep_type_node,
	upc_char_pts_type_node, upc_phase_field_node,
	upc_thread_field_node, upc_vaddr_field_node,
	upc_null_pts_node): New.  Define UPC-related global tree nodes.
	(check_qualified_type, get_qualified_type_1):
	Adjust prototypes.
	(get_qualified_type): Re-implement as a pre-processor macro
	that invokes get_qualified_type_1() with a null blocking factor.
	(tree_expr_size): New. Declare prototype for function
	moved from expr.c into tree.c.

Index: gcc/expr.c
===================================================================
--- gcc/expr.c	(.../trunk)	(revision 231059)
+++ gcc/expr.c	(.../branches/gupc)	(revision 231080)
@@ -137,7 +137,6 @@  static void emit_single_push_insn (machi
 #endif
 static void do_tablejump (rtx, machine_mode, rtx, rtx, rtx, int);
 static rtx const_vector_from_tree (tree);
-static tree tree_expr_size (const_tree);
 static HOST_WIDE_INT int_expr_size (tree);
 
 
@@ -11566,18 +11565,6 @@  get_personality_function (tree decl)
   return XEXP (DECL_RTL (personality), 0);
 }
 
-/* Returns a tree for the size of EXP in bytes.  */
-
-static tree
-tree_expr_size (const_tree exp)
-{
-  if (DECL_P (exp)
-      && DECL_SIZE_UNIT (exp) != 0)
-    return DECL_SIZE_UNIT (exp);
-  else
-    return size_in_bytes (TREE_TYPE (exp));
-}
-
 /* Return an rtx for the size in bytes of the value of EXP.  */
 
 rtx
Index: gcc/print-tree.c
===================================================================
--- gcc/print-tree.c	(.../trunk)	(revision 231059)
+++ gcc/print-tree.c	(.../branches/gupc)	(revision 231080)
@@ -299,6 +299,8 @@  print_node (FILE *file, const char *pref
     fputs (" readonly", file);
   if (TYPE_P (node) && TYPE_ATOMIC (node))
     fputs (" atomic", file);
+  if (TREE_SHARED (node))
+    fputs (" shared", file);
   if (!TYPE_P (node) && TREE_CONSTANT (node))
     fputs (" constant", file);
   else if (TYPE_P (node) && TYPE_SIZES_GIMPLIFIED (node))
@@ -607,6 +609,14 @@  print_node (FILE *file, const char *pref
 
       print_node (file, "size", TYPE_SIZE (node), indent + 4);
       print_node (file, "unit size", TYPE_SIZE_UNIT (node), indent + 4);
+      if (TYPE_SHARED (node))
+        {
+          if (TYPE_HAS_THREADS_FACTOR(node))
+	    fputs (" THREADS factor", file);
+	  if (TYPE_HAS_BLOCK_FACTOR (node))
+	    print_node (file, "block factor",
+	                TYPE_BLOCK_FACTOR (node), indent + 4);
+        }
       indent_to (file, indent + 3);
 
       if (TYPE_USER_ALIGN (node))
Index: gcc/tree-core.h
===================================================================
--- gcc/tree-core.h	(.../trunk)	(revision 231059)
+++ gcc/tree-core.h	(.../branches/gupc)	(revision 231080)
@@ -501,7 +501,11 @@  enum cv_qualifier {
   TYPE_QUAL_CONST    = 0x1,
   TYPE_QUAL_VOLATILE = 0x2,
   TYPE_QUAL_RESTRICT = 0x4,
-  TYPE_QUAL_ATOMIC   = 0x8
+  TYPE_QUAL_ATOMIC   = 0x8,
+  /* UPC qualifiers */
+  TYPE_QUAL_SHARED   = 0x10,
+  TYPE_QUAL_RELAXED  = 0x20,
+  TYPE_QUAL_STRICT   = 0x40
 };
 
 /* Standard named or nameless data types of the C compiler.  */
@@ -578,6 +582,14 @@  enum tree_index {
   TI_FILEPTR_TYPE,
   TI_POINTER_SIZED_TYPE,
 
+  TI_UPC_PTS_TYPE,
+  TI_UPC_PTS_REP_TYPE,
+  TI_UPC_CHAR_PTS_TYPE,
+  TI_UPC_PHASE_FIELD,
+  TI_UPC_THREAD_FIELD,
+  TI_UPC_VADDR_FIELD,
+  TI_UPC_NULL_PTS,
+
   TI_POINTER_BOUNDS_TYPE,
 
   TI_DFLOAT32_TYPE,
@@ -880,9 +892,14 @@  struct GTY(()) tree_base {
       unsigned user_align : 1;
       unsigned nameless_flag : 1;
       unsigned atomic_flag : 1;
-      unsigned spare0 : 3;
-
-      unsigned spare1 : 8;
+      unsigned shared_flag : 1;
+      unsigned strict_flag : 1;
+      unsigned relaxed_flag : 1;
+
+      unsigned threads_factor_flag : 1;
+      unsigned block_factor_0 : 1;
+      unsigned block_factor_x : 1;
+      unsigned spare1 : 5;
 
       /* This field is only used with TREE_TYPE nodes; the only reason it is
 	 present in tree_base instead of tree_type is to save space.  The size
@@ -1411,7 +1428,7 @@  struct GTY(()) tree_block {
   struct die_struct *die;
 };
 
-struct GTY(()) tree_type_common {
+struct GTY((user)) tree_type_common {
   struct tree_common common;
   tree size;
   tree size_unit;
@@ -1441,10 +1458,10 @@  struct GTY(()) tree_type_common {
   tree pointer_to;
   tree reference_to;
   union tree_type_symtab {
-    int GTY ((tag ("TYPE_SYMTAB_IS_ADDRESS"))) address;
-    const char * GTY ((tag ("TYPE_SYMTAB_IS_POINTER"))) pointer;
-    struct die_struct * GTY ((tag ("TYPE_SYMTAB_IS_DIE"))) die;
-  } GTY ((desc ("debug_hooks->tree_type_symtab_field"))) symtab;
+    int address;
+    const char *pointer;
+    struct die_struct *die;
+  } symtab;
   tree canonical;
   tree next_variant;
   tree main_variant;
@@ -1452,6 +1469,11 @@  struct GTY(()) tree_type_common {
   tree name;
 };
 
+/* Garbage collection and PCH support for tree_type_common.  */
+extern void gt_ggc_mx (tree_type_common *t);
+extern void gt_pch_nx (tree_type_common *t);
+extern void gt_pch_nx (tree_type_common *t, gt_pointer_operator, void *);
+
 struct GTY(()) tree_type_with_lang_specific {
   struct tree_type_common common;
   /* Points to a structure whose details depend on the language in use.  */
Index: gcc/tree-dump.c
===================================================================
--- gcc/tree-dump.c	(.../trunk)	(revision 231059)
+++ gcc/tree-dump.c	(.../branches/gupc)	(revision 231080)
@@ -387,10 +387,13 @@  dequeue_and_dump (dump_info_p di)
 
       if (quals != TYPE_UNQUALIFIED)
 	{
-	  fprintf (di->stream, "qual: %c%c%c     ",
+	  fprintf (di->stream, "qual: %c%c%c%c%c%c  ",
 		   (quals & TYPE_QUAL_CONST) ? 'c' : ' ',
 		   (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ',
-		   (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' ');
+		   (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' ',
+		   (quals & TYPE_QUAL_SHARED) ? 's' : ' ',
+		   (quals & TYPE_QUAL_STRICT) ? 't' : ' ',
+		   (quals & TYPE_QUAL_RELAXED) ? 'x' : ' ');
 	  di->column += 14;
 	}
 
Index: gcc/tree-pretty-print.c
===================================================================
--- gcc/tree-pretty-print.c	(.../trunk)	(revision 231059)
+++ gcc/tree-pretty-print.c	(.../branches/gupc)	(revision 231080)
@@ -1105,6 +1105,25 @@  dump_block_node (pretty_printer *pp, tre
 }
 
 
+static void
+dump_upc_type_quals (pretty_printer *buffer, tree type, int quals)
+{
+  gcc_assert (type && TYPE_CHECK (type));
+  gcc_assert (quals & TYPE_QUAL_SHARED);
+  if (quals & TYPE_QUAL_STRICT)
+    pp_string (buffer, "strict ");
+  if (quals & TYPE_QUAL_RELAXED)
+    pp_string (buffer, "relaxed ");
+  pp_string (buffer, "shared ");
+  if (TYPE_HAS_BLOCK_FACTOR (type))
+    {
+      tree block_factor = TYPE_BLOCK_FACTOR (type);
+      pp_string (buffer, "[");
+      pp_wide_integer (buffer, TREE_INT_CST_LOW (block_factor));
+      pp_string (buffer, "] ");
+    }
+}
+
 /* Dump the node NODE on the pretty_printer PP, SPC spaces of
    indent.  FLAGS specifies details to show in the dump (see TDF_* in
    dumpfile.h).  If IS_STMT is true, the object printed is considered
@@ -1204,6 +1223,8 @@  dump_generic_node (pretty_printer *pp, t
 	  pp_string (pp, "volatile ");
 	else if (quals & TYPE_QUAL_RESTRICT)
 	  pp_string (pp, "restrict ");
+	else if (quals & TYPE_QUAL_SHARED)
+          dump_upc_type_quals (pp, node, quals);
 
 	if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (node)))
 	  {
@@ -1346,6 +1367,14 @@  dump_generic_node (pretty_printer *pp, t
 	    pp_string (pp, " volatile");
 	  if (quals & TYPE_QUAL_RESTRICT)
 	    pp_string (pp, " restrict");
+          if (quals & TYPE_QUAL_SHARED)
+	    {
+	      if (quals & TYPE_QUAL_STRICT)
+		pp_string (pp, " strict");
+	      if (quals & TYPE_QUAL_RELAXED)
+		pp_string (pp, " relaxed");
+              pp_string (pp, " shared");
+	    }
 
 	  if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (node)))
 	    {
@@ -1515,6 +1544,8 @@  dump_generic_node (pretty_printer *pp, t
 	  pp_string (pp, "const ");
 	if (quals & TYPE_QUAL_VOLATILE)
 	  pp_string (pp, "volatile ");
+	if (quals & TYPE_QUAL_SHARED)
+          dump_upc_type_quals (pp, node, quals);
 
         /* Print the name of the structure.  */
         if (TREE_CODE (node) == RECORD_TYPE)
@@ -1522,7 +1553,12 @@  dump_generic_node (pretty_printer *pp, t
         else if (TREE_CODE (node) == UNION_TYPE)
 	  pp_string (pp, "union ");
 
-        if (TYPE_NAME (node))
+	if (upc_pts_rep_type_node && node == upc_pts_rep_type_node)
+	  /* Normally, builtin types will not be printed.
+	     We short-circuit that check for the UPC "struct PTS"
+	     representation type.  */
+	  pp_string (pp, "upc_shared_ptr_t");
+        else if (TYPE_NAME (node))
 	  dump_generic_node (pp, TYPE_NAME (node), spc, flags, false);
 	else if (!(flags & TDF_SLIM))
 	  /* FIXME: If we eliminate the 'else' above and attempt
Index: gcc/tree-sra.c
===================================================================
--- gcc/tree-sra.c	(.../trunk)	(revision 231059)
+++ gcc/tree-sra.c	(.../branches/gupc)	(revision 231080)
@@ -3882,6 +3882,7 @@  find_param_candidates (void)
 
 	  if (TREE_CODE (type) == FUNCTION_TYPE
 	      || TYPE_VOLATILE (type)
+	      || SHARED_TYPE_P (type)
 	      || (TREE_CODE (type) == ARRAY_TYPE
 		  && TYPE_NONALIASED_COMPONENT (type))
 	      || !is_gimple_reg (parm)
Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(.../trunk)	(revision 231059)
+++ gcc/tree.c	(.../branches/gupc)	(revision 231080)
@@ -58,6 +58,7 @@  along with GCC; see the file COPYING3.
 #include "langhooks-def.h"
 #include "tree-diagnostic.h"
 #include "except.h"
+#include "debug.h"
 #include "builtins.h"
 #include "print-tree.h"
 #include "ipa-utils.h"
@@ -243,7 +244,23 @@  struct tree_vec_map_cache_hasher : ggc_c
 static GTY ((cache))
      hash_table<tree_vec_map_cache_hasher> *debug_args_for_decl;
 
-static void set_type_quals (tree, int);
+struct tm_block_factor_hasher : ggc_cache_ptr_hash<tree_map>
+{
+  static hashval_t hash (tree_map *m) { return tree_map_hash (m); }
+  static bool equal (tree_map *a, tree_map *b) { return tree_map_eq (a, b); }
+
+  static int
+  keep_cache_entry (tree_map *&e)
+  {
+    return ggc_marked_p (e->base.from);
+  }
+};
+
+/* Hash table for block factor lookups when the block factor
+   is not 0 (the indefinite block factor) or 1 (the default).  */
+static GTY((cache)) hash_table<tm_block_factor_hasher> *block_factor_htab;
+
+static void set_type_quals (tree, int, tree);
 static void print_type_hash_statistics (void);
 static void print_debug_expr_statistics (void);
 static void print_value_expr_statistics (void);
@@ -639,6 +656,9 @@  init_ttree (void)
   type_hash_table
     = hash_table<type_cache_hasher>::create_ggc (TYPE_HASH_INITIAL_SIZE);
 
+  /* Initialize hash table used to manage blocking factors.  */
+  block_factor_lookup_init ();
+
   debug_expr_for_decl
     = hash_table<tree_decl_map_cache_hasher>::create_ggc (512);
 
@@ -1197,6 +1217,9 @@  copy_node_stat (tree node MEM_STAT_DECL)
 	  TYPE_CACHED_VALUES_P (t) = 0;
 	  TYPE_CACHED_VALUES (t) = NULL_TREE;
 	}
+
+      if (TYPE_HAS_BLOCK_FACTOR (node))
+        SET_TYPE_BLOCK_FACTOR (t, TYPE_BLOCK_FACTOR (node));
     }
     else if (code == TARGET_OPTION_NODE)
       {
@@ -2932,6 +2955,18 @@  size_in_bytes (const_tree type)
   return t;
 }
 
+/* Returns a tree for the size of EXP in bytes.  */
+
+tree
+tree_expr_size (const_tree exp)
+{
+  if (DECL_P (exp)
+      && DECL_SIZE_UNIT (exp) != 0)
+    return DECL_SIZE_UNIT (exp);
+  else
+    return size_in_bytes (TREE_TYPE (exp));
+}
+
 /* Return the size of TYPE (in bytes) as a wide integer
    or return -1 if the size can vary or is larger than an integer.  */
 
@@ -4155,6 +4190,9 @@  stabilize_reference_1 (tree e)
   TREE_READONLY (result) = TREE_READONLY (e);
   TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (e);
   TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e);
+  TREE_SHARED (result)  = TREE_SHARED (e);
+  TREE_STRICT (result)  = TREE_STRICT (e);
+  TREE_RELAXED (result) = TREE_RELAXED (e);
 
   return result;
 }
@@ -4238,6 +4276,9 @@  stabilize_reference (tree ref)
   TREE_READONLY (result) = TREE_READONLY (ref);
   TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (ref);
   TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (ref);
+  TREE_SHARED (result)  = TREE_SHARED (ref);
+  TREE_STRICT (result)  = TREE_STRICT (ref);
+  TREE_RELAXED (result) = TREE_RELAXED (ref);
 
   return result;
 }
@@ -4381,6 +4422,7 @@  build1_stat (enum tree_code code, tree t
       /* Whether a dereference is readonly has nothing to do with whether
 	 its operand is readonly.  */
       TREE_READONLY (t) = 0;
+      TREE_SHARED (t) = SHARED_TYPE_P (type);
       break;
 
     case ADDR_EXPR:
@@ -4396,6 +4438,12 @@  build1_stat (enum tree_code code, tree t
       if (TREE_CODE_CLASS (code) == tcc_reference
 	  && node && TREE_THIS_VOLATILE (node))
 	TREE_THIS_VOLATILE (t) = 1;
+      /* Drop the "shared" type qualifier for
+         expressions involving shared objects.  */ 
+      if (TREE_CODE_CLASS (code) == tcc_unary
+	  && node && !TYPE_P (node)
+	  && SHARED_TYPE_P (type))
+	TREE_TYPE (t) = build_unshared_type (type);
       break;
     }
 
@@ -4439,6 +4487,10 @@  build2_stat (enum tree_code code, tree t
 		&& ptrofftype_p (TREE_TYPE (arg1)));
 
   t = make_node_stat (code PASS_MEM_STAT);
+
+  /* Remove shared type qualifiers from the result type.  */
+  if (SHARED_TYPE_P (tt))
+    tt = build_unshared_type (tt);
   TREE_TYPE (t) = tt;
 
   /* Below, we automatically set TREE_SIDE_EFFECTS and TREE_READONLY for the
@@ -4516,6 +4568,14 @@  build3_stat (enum tree_code code, tree t
   TREE_THIS_VOLATILE (t)
     = (TREE_CODE_CLASS (code) == tcc_reference
        && arg0 && TREE_THIS_VOLATILE (arg0));
+  TREE_SHARED (t)
+    = (TREE_CODE_CLASS (code) == tcc_reference
+       && arg0 && TREE_SHARED (arg0));
+  if (TREE_SHARED (t))
+    {
+      TREE_STRICT (t)  = TREE_STRICT (arg0);
+      TREE_RELAXED (t) = TREE_RELAXED (arg0);
+    }
 
   return t;
 }
@@ -6464,16 +6524,22 @@  handle_dll_attribute (tree * pnode, tree
 #endif /* TARGET_DLLIMPORT_DECL_ATTRIBUTES  */
 
 /* Set the type qualifiers for TYPE to TYPE_QUALS, which is a bitmask
-   of the various TYPE_QUAL values.  */
+   of the various TYPE_QUAL values.  Also, set the blocking factor,
+   which is either null or a reference to an integral constant.  */
 
 static void
-set_type_quals (tree type, int type_quals)
+set_type_quals (tree type, int type_quals, tree block_factor)
 {
   TYPE_READONLY (type) = (type_quals & TYPE_QUAL_CONST) != 0;
   TYPE_VOLATILE (type) = (type_quals & TYPE_QUAL_VOLATILE) != 0;
   TYPE_RESTRICT (type) = (type_quals & TYPE_QUAL_RESTRICT) != 0;
   TYPE_ATOMIC (type) = (type_quals & TYPE_QUAL_ATOMIC) != 0;
   TYPE_ADDR_SPACE (type) = DECODE_QUAL_ADDR_SPACE (type_quals);
+  TYPE_SHARED (type) = (type_quals & TYPE_QUAL_SHARED) != 0;
+  TYPE_STRICT (type) = (type_quals & TYPE_QUAL_STRICT) != 0;
+  TYPE_RELAXED (type) = (type_quals & TYPE_QUAL_RELAXED) != 0;
+  if (TYPE_SHARED (type))
+    SET_TYPE_BLOCK_FACTOR (type, block_factor);
 }
 
 /* Returns true iff unqualified CAND and BASE are equivalent.  */
@@ -6490,12 +6556,15 @@  check_base_type (const_tree cand, const_
 				   TYPE_ATTRIBUTES (base)));
 }
 
-/* Returns true iff CAND is equivalent to BASE with TYPE_QUALS.  */
+/* Returns true iff CAND is equivalent to BASE with TYPE_QUALS
+   and BLOCK_FACTOR.  */
 
 bool
-check_qualified_type (const_tree cand, const_tree base, int type_quals)
+check_qualified_type (const_tree cand, const_tree base,
+                      int type_quals, tree block_factor)
 {
   return (TYPE_QUALS (cand) == type_quals
+	  && TYPE_BLOCK_FACTOR (cand) == block_factor
 	  && check_base_type (cand, base));
 }
 
@@ -6505,6 +6574,7 @@  static bool
 check_aligned_type (const_tree cand, const_tree base, unsigned int align)
 {
   return (TYPE_QUALS (cand) == TYPE_QUALS (base)
+	  && TYPE_BLOCK_FACTOR (cand) == TYPE_BLOCK_FACTOR (base)
 	  && TYPE_NAME (cand) == TYPE_NAME (base)
 	  /* Apparently this is needed for Objective-C.  */
 	  && TYPE_CONTEXT (cand) == TYPE_CONTEXT (base)
@@ -6557,11 +6627,11 @@  find_atomic_core_type (tree type)
 }
 
 /* Return a version of the TYPE, qualified as indicated by the
-   TYPE_QUALS, if one exists.  If no qualified version exists yet,
-   return NULL_TREE.  */
+   TYPE_QUALS, and BLOCK_FACTOR if one exists.
+   If no qualified version exists yet, return NULL_TREE.  */
 
 tree
-get_qualified_type (tree type, int type_quals)
+get_qualified_type_1 (tree type, int type_quals, tree block_factor)
 {
   tree t;
 
@@ -6572,28 +6642,28 @@  get_qualified_type (tree type, int type_
      like the one we need to have.  If so, use that existing one.  We must
      preserve the TYPE_NAME, since there is code that depends on this.  */
   for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
-    if (check_qualified_type (t, type, type_quals))
+    if (check_qualified_type (t, type, type_quals, block_factor))
       return t;
 
   return NULL_TREE;
 }
 
-/* Like get_qualified_type, but creates the type if it does not
+/* Like get_qualified_type_1, but creates the type if it does not
    exist.  This function never returns NULL_TREE.  */
 
 tree
-build_qualified_type (tree type, int type_quals)
+build_qualified_type_1 (tree type, int type_quals, tree block_factor)
 {
   tree t;
 
   /* See if we already have the appropriate qualified variant.  */
-  t = get_qualified_type (type, type_quals);
+  t = get_qualified_type_1 (type, type_quals, block_factor);
 
   /* If not, build it.  */
   if (!t)
     {
       t = build_variant_type_copy (type);
-      set_type_quals (t, type_quals);
+      set_type_quals (t, type_quals, block_factor);
 
       if (((type_quals & TYPE_QUAL_ATOMIC) == TYPE_QUAL_ATOMIC))
 	{
@@ -7934,6 +8004,16 @@  build_pointer_type (tree to_type)
   addr_space_t as = to_type == error_mark_node? ADDR_SPACE_GENERIC
 					      : TYPE_ADDR_SPACE (to_type);
   machine_mode pointer_mode = targetm.addr_space.pointer_mode (as);
+  if (SHARED_TYPE_P (to_type))
+    {
+      tree upc_pts_type;
+      pointer_mode = TYPE_MODE (upc_pts_rep_type_node);
+      upc_pts_type = build_pointer_type_for_mode (to_type, pointer_mode,
+                                                  false);
+      TYPE_USER_ALIGN (upc_pts_type) = TYPE_USER_ALIGN (upc_pts_rep_type_node);
+      TYPE_ALIGN (upc_pts_type) = TYPE_ALIGN (upc_pts_rep_type_node);
+      return upc_pts_type;
+    }
   return build_pointer_type_for_mode (to_type, pointer_mode, false);
 }
 
@@ -9991,7 +10071,7 @@  build_atomic_base (tree type, unsigned i
     return t;
   
   t = build_variant_type_copy (type);
-  set_type_quals (t, TYPE_QUAL_ATOMIC);
+  set_type_quals (t, TYPE_QUAL_ATOMIC, NULL_TREE);
 
   if (align)
     TYPE_ALIGN (t) = align;
@@ -10724,7 +10804,7 @@  build_opaque_vector_type (tree innertype
   cand = TYPE_NEXT_VARIANT (t);
   if (cand
       && TYPE_VECTOR_OPAQUE (cand)
-      && check_qualified_type (cand, t, TYPE_QUALS (t)))
+      && check_qualified_type (cand, t, TYPE_QUALS (t), NULL_TREE))
     return cand;
   /* Othewise build a variant type and make sure to queue it after
      the non-opaque type.  */
@@ -12205,6 +12285,7 @@  static inline bool
 tree_nop_conversion (const_tree exp)
 {
   tree outer_type, inner_type;
+  int outer_is_pts_p, inner_is_pts_p;
 
   if (!CONVERT_EXPR_P (exp)
       && TREE_CODE (exp) != NON_LVALUE_EXPR)
@@ -12218,6 +12299,22 @@  tree_nop_conversion (const_tree exp)
   if (!inner_type)
     return false;
 
+  outer_is_pts_p = (POINTER_TYPE_P (outer_type)
+                    && SHARED_TYPE_P (TREE_TYPE (outer_type)));
+  inner_is_pts_p = (POINTER_TYPE_P (inner_type)
+                    && SHARED_TYPE_P (TREE_TYPE (inner_type)));
+
+  /* Pointer-to-shared types have special
+     equivalence rules that must be checked.  */
+  if (outer_is_pts_p && inner_is_pts_p
+      && lang_hooks.types_compatible_p)
+    return lang_hooks.types_compatible_p (outer_type, inner_type);
+
+  /* Pointer-to-shared types are not interchangeable
+     with integral types.  */
+  if (outer_is_pts_p || inner_is_pts_p)
+    return false;
+
   return tree_nop_conversion_p (outer_type, inner_type);
 }
 
@@ -12731,6 +12828,121 @@  block_may_fallthru (const_tree block)
     }
 }
 
+/* Garbage collection support for tree_type_common.  */
+
+extern void gt_ggc_mx (tree&);
+extern void gt_ggc_mx_die_struct (void *);
+
+void gt_ggc_mx (tree_type_common *tt)
+{
+  tree t = (tree) tt;
+  tree block_factor = TYPE_BLOCK_FACTOR (t);
+
+  gt_ggc_mx (tt->common.typed.type);
+  gt_ggc_mx (tt->common.chain);
+  gt_ggc_mx (tt->size);
+  gt_ggc_mx (tt->size_unit);
+  gt_ggc_mx (tt->attributes);
+  gt_ggc_mx (tt->pointer_to);
+  gt_ggc_mx (tt->reference_to);
+  switch (debug_hooks->tree_type_symtab_field)
+    {
+    case TYPE_SYMTAB_IS_ADDRESS:
+      break;
+    case TYPE_SYMTAB_IS_POINTER:
+      gt_ggc_m_S (tt->symtab.pointer);
+      break;
+    case TYPE_SYMTAB_IS_DIE:
+      gt_ggc_mx_die_struct (tt->symtab.die);
+      break;
+    default:
+      break;
+    }
+  gt_ggc_mx (tt->name);
+  gt_ggc_mx (tt->next_variant);
+  gt_ggc_mx (tt->main_variant);
+  gt_ggc_mx (tt->context);
+  gt_ggc_mx (tt->canonical);
+
+  if (TYPE_HAS_BLOCK_FACTOR_X (t))
+    gt_ggc_mx (block_factor);
+}
+
+/* PCH support for tree_type_common.  */
+
+extern void gt_pch_nx (tree&);
+extern void gt_ggc_nx_die_struct (void *);
+
+void gt_pch_nx (tree_type_common *tt)
+{
+  tree t = (tree) tt;
+  tree block_factor = TYPE_BLOCK_FACTOR (t);
+
+  gt_pch_nx (tt->common.typed.type);
+  gt_pch_nx (tt->common.chain);
+  gt_pch_nx (tt->size);
+  gt_pch_nx (tt->size_unit);
+  gt_pch_nx (tt->attributes);
+  gt_pch_nx (tt->pointer_to);
+  gt_pch_nx (tt->reference_to);
+  switch (debug_hooks->tree_type_symtab_field)
+    {
+    case TYPE_SYMTAB_IS_ADDRESS:
+      break;
+    case TYPE_SYMTAB_IS_POINTER:
+      gt_pch_n_S (tt->symtab.pointer);
+      break;
+    case TYPE_SYMTAB_IS_DIE:
+      gt_pch_nx_die_struct (tt->symtab.die);
+      break;
+    default:
+      break;
+    }
+  gt_pch_nx (tt->name);
+  gt_pch_nx (tt->next_variant);
+  gt_pch_nx (tt->main_variant);
+  gt_pch_nx (tt->context);
+  gt_pch_nx (tt->canonical);
+
+  if (TYPE_HAS_BLOCK_FACTOR_X (t))
+    gt_pch_nx (block_factor);
+}
+
+void gt_pch_nx (tree_type_common *tt, gt_pointer_operator op, void *cookie)
+{
+  tree t = (tree) tt;
+  tree block_factor = TYPE_BLOCK_FACTOR (t);
+
+  op (&(tt->common.typed.type), cookie);
+  op (&(tt->common.chain), cookie);
+  op (&(tt->size), cookie);
+  op (&(tt->size_unit), cookie);
+  op (&(tt->attributes), cookie);
+  op (&(tt->pointer_to), cookie);
+  op (&(tt->reference_to), cookie);
+  switch (debug_hooks->tree_type_symtab_field)
+    {
+    case TYPE_SYMTAB_IS_ADDRESS:
+      break;
+    case TYPE_SYMTAB_IS_POINTER:
+      op (&(tt->symtab.pointer), cookie);
+      break;
+    case TYPE_SYMTAB_IS_DIE:
+      op (&(tt->symtab.die), cookie);
+      break;
+    default:
+      break;
+    }
+  op (&(tt->name), cookie);
+  op (&(tt->next_variant), cookie);
+  op (&(tt->main_variant), cookie);
+  op (&(tt->context), cookie);
+  op (&(tt->canonical), cookie);
+
+  if (TYPE_HAS_BLOCK_FACTOR_X (t))
+    op (&(block_factor), cookie);
+}
+
 /* True if we are using EH to handle cleanups.  */
 static bool using_eh_for_cleanups_flag = false;
 
@@ -13901,6 +14113,103 @@  nonnull_arg_p (const_tree arg)
   return false;
 }
 
+/* Return the blocking factor of the shared type, TYPE.
+   If the blocking factor is NULL, then return the default blocking
+   factor of 1.  */
+
+tree
+get_block_factor (const tree type)
+{
+  tree block_factor = size_one_node;
+  const tree elt_type = strip_array_types (type);
+  if (elt_type && (TREE_CODE (elt_type) != ERROR_MARK)
+      && TYPE_HAS_BLOCK_FACTOR (elt_type))
+    block_factor = TYPE_BLOCK_FACTOR (elt_type);
+  return block_factor;
+}
+
+/* Return a variant of TYPE, where the shared, strict, and relaxed
+   qualifiers have been removed.  */
+
+tree
+build_unshared_type (tree type)
+{
+  tree u_type = type;
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      const tree elem_type = TREE_TYPE(type);
+      const tree u_elem_type = build_unshared_type (elem_type);
+      if (u_elem_type != elem_type)
+        {
+          for (u_type = TYPE_MAIN_VARIANT (type);
+               u_type && TREE_TYPE(u_type) != u_elem_type;
+               u_type = TYPE_NEXT_VARIANT (u_type)) /* loop */;
+          if (!u_type)
+            {
+              u_type = build_variant_type_copy (type);
+              TREE_TYPE (u_type) = u_elem_type;
+            }
+        }
+    }
+  else
+    {
+      const int quals = TYPE_QUALS (type);
+      const int u_quals = quals & ~(TYPE_QUAL_SHARED
+                                    | TYPE_QUAL_RELAXED
+                                    | TYPE_QUAL_STRICT);
+      u_type = build_qualified_type (type, u_quals);
+    }
+  return u_type;
+}
+
+/* Lookup the block size of TYPE, and return it if we find one.  */
+
+tree
+block_factor_lookup (const_tree type)
+{
+  struct tree_map in;
+  union
+    {
+      const_tree ct;
+      tree t;
+    } ct_to_t;
+  ct_to_t.ct = type;
+  /* Drop the const qualifier, avoid the warning.  */
+  in.base.from = ct_to_t.t;
+  in.hash = TYPE_HASH (in.base.from);
+  struct tree_map **loc = block_factor_htab->
+                            find_slot_with_hash (&in, in.hash, NO_INSERT);
+  gcc_assert (loc != NULL);
+  struct tree_map *h = *loc;
+  if (h)
+    return h->to;
+  return NULL_TREE;
+}
+
+/* Insert a mapping TYPE->BLOCK_FACTOR in the block factor hashtable.  */
+
+void
+block_factor_insert (tree type, tree block_factor)
+{
+
+  gcc_assert (type && TYPE_P (type));
+  gcc_assert (block_factor && INTEGRAL_TYPE_P (TREE_TYPE (block_factor)));
+  gcc_assert (!(integer_zerop (block_factor) || integer_onep (block_factor)));
+  tree_map *h = ggc_alloc<tree_map> ();
+  h->base.from = type;
+  h->hash = TYPE_HASH (type);
+  h->to = block_factor;
+  tree_map **loc = block_factor_htab->
+                     find_slot_with_hash (h, h->hash, INSERT);
+  *loc = h;
+}
+
+void
+block_factor_lookup_init (void)
+{
+  block_factor_htab = hash_table<tm_block_factor_hasher>::create_ggc (17);
+}
+
 /* Given location LOC, strip away any packed range information
    or ad-hoc information.  */
 
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(.../trunk)	(revision 231059)
+++ gcc/tree.h	(.../branches/gupc)	(revision 231080)
@@ -636,6 +636,24 @@  extern void omp_clause_range_check_faile
 #define FUNC_OR_METHOD_TYPE_P(NODE) \
   (TREE_CODE (NODE) == FUNCTION_TYPE || TREE_CODE (NODE) == METHOD_TYPE)
 
+/* Return TRUE if TYPE is a shared type.  For arrays,
+   the element type must be queried, because array types
+   are never qualified.  */
+#define SHARED_TYPE_P(TYPE) \
+  ((TYPE) && TYPE_P (TYPE) \
+   && TYPE_SHARED ((TREE_CODE (TYPE) != ARRAY_TYPE \
+                    ? (TYPE) : strip_array_types (TYPE))))
+
+/* Return TRUE if EXP is a conversion operation involving
+   pointers-to-shared.  If either of the types involved
+   in the conversion is a pointer-to-shared type, return TRUE.  */
+#define PTS_CVT_OP_P(EXP) \
+  ((EXP) && ((POINTER_TYPE_P (TREE_TYPE (EXP)) \
+              && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (EXP, 0)))) \
+              && (SHARED_TYPE_P (TREE_TYPE (TREE_TYPE (EXP))) \
+                  || SHARED_TYPE_P (TREE_TYPE ( \
+	                TREE_TYPE (TREE_OPERAND (EXP, 0)))))))
+
 /* Define many boolean fields that all tree nodes have.  */
 
 /* In VAR_DECL, PARM_DECL and RESULT_DECL nodes, nonzero means address
@@ -812,6 +830,14 @@  extern void omp_clause_range_check_faile
 #define DECL_UNSIGNED(NODE) \
   (DECL_COMMON_CHECK (NODE)->base.u.bits.unsigned_flag)
 
+/* Convert tree flags to type qualifiers.  */
+#define TREE_QUALS(NODE)				\
+  ((TREE_READONLY(NODE) * TYPE_QUAL_CONST) |		\
+   (TREE_THIS_VOLATILE(NODE) * TYPE_QUAL_VOLATILE) |	\
+   (TREE_SHARED(NODE) * TYPE_QUAL_SHARED) |		\
+   (TREE_STRICT(NODE) * TYPE_QUAL_STRICT) |		\
+   (TREE_RELAXED(NODE) * TYPE_QUAL_RELAXED))
+
 /* In integral and pointer types, means an unsigned type.  */
 #define TYPE_UNSIGNED(NODE) (TYPE_CHECK (NODE)->base.u.bits.unsigned_flag)
 
@@ -941,6 +967,11 @@  extern void omp_clause_range_check_faile
 #define IDENTIFIER_TRANSPARENT_ALIAS(NODE) \
   (IDENTIFIER_NODE_CHECK (NODE)->base.deprecated_flag)
 
+/* Shared, strict, and relaxed common tree flags */
+#define TREE_SHARED(NODE) ((NODE)->base.u.bits.shared_flag)
+#define TREE_STRICT(NODE) ((NODE)->base.u.bits.strict_flag)
+#define TREE_RELAXED(NODE) ((NODE)->base.u.bits.relaxed_flag)
+
 /* In an aggregate type, indicates that the scalar fields of the type are
    stored in reverse order from the target order.  This effectively
    toggles BYTES_BIG_ENDIAN and WORDS_BIG_ENDIAN within the type.  */
@@ -1887,6 +1918,21 @@  extern machine_mode element_mode (const_
    the term.  */
 #define TYPE_RESTRICT(NODE) (TYPE_CHECK (NODE)->type_common.restrict_flag)
 
+/* If nonzero, this type is `shared'-qualified, in the UPC dialect */
+#define TYPE_SHARED(NODE) (TYPE_CHECK (NODE)->base.u.bits.shared_flag)
+
+/* If nonzero, this type is `strict'-qualified, in the UPC dialect  */
+#define TYPE_STRICT(NODE) (TYPE_CHECK (NODE)->base.u.bits.strict_flag)
+
+/* If nonzero, this type is `relaxed'-qualified, in the UPC dialect  */
+#define TYPE_RELAXED(NODE) \
+  (TYPE_CHECK (NODE)->base.u.bits.relaxed_flag)
+
+/* Record that we are processing a UPC shared array declaration
+   or type definition that refers to THREADS in its array dimension.*/
+#define TYPE_HAS_THREADS_FACTOR(NODE) \
+  (TYPE_CHECK (NODE)->base.u.bits.threads_factor_flag)
+
 /* If nonzero, type's name shouldn't be emitted into debug info.  */
 #define TYPE_NAMELESS(NODE) (TYPE_CHECK (NODE)->base.u.bits.nameless_flag)
 
@@ -1911,13 +1957,24 @@  extern machine_mode element_mode (const_
 	  | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE)		\
 	  | (TYPE_ATOMIC (NODE) * TYPE_QUAL_ATOMIC)		\
 	  | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT)		\
+	  | (TYPE_SHARED (NODE) * TYPE_QUAL_SHARED)		\
+	  | (TYPE_STRICT (NODE) * TYPE_QUAL_STRICT)		\
+	  | (TYPE_RELAXED (NODE) * TYPE_QUAL_RELAXED)		\
 	  | (ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (NODE)))))
 
+/* The set of qualifiers pertinent to a FUNCTION_DECL node.  */
+#define TREE_FUNC_QUALS(NODE)				\
+  ((TREE_READONLY (NODE) * TYPE_QUAL_CONST)		\
+   | (TREE_THIS_VOLATILE (NODE) * TYPE_QUAL_VOLATILE))
+
 /* The same as TYPE_QUALS without the address space qualifications.  */
 #define TYPE_QUALS_NO_ADDR_SPACE(NODE)				\
   ((int) ((TYPE_READONLY (NODE) * TYPE_QUAL_CONST)		\
 	  | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE)		\
 	  | (TYPE_ATOMIC (NODE) * TYPE_QUAL_ATOMIC)		\
+	  | (TYPE_SHARED (NODE) * TYPE_QUAL_SHARED)		\
+	  | (TYPE_STRICT (NODE) * TYPE_QUAL_STRICT)		\
+	  | (TYPE_RELAXED (NODE) * TYPE_QUAL_RELAXED)		\
 	  | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT)))
 
 /* The same as TYPE_QUALS without the address space and atomic 
@@ -1925,8 +1982,72 @@  extern machine_mode element_mode (const_
 #define TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC(NODE)		\
   ((int) ((TYPE_READONLY (NODE) * TYPE_QUAL_CONST)		\
 	  | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE)		\
+          | (TYPE_SHARED (NODE) * TYPE_QUAL_SHARED)		\
+          | (TYPE_STRICT (NODE) * TYPE_QUAL_STRICT)		\
+          | (TYPE_RELAXED (NODE) * TYPE_QUAL_RELAXED)		\
 	  | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT)))
 
+/* Non-zero if the blocking factor is 0.  */
+#define TYPE_HAS_BLOCK_FACTOR_0(NODE)  \
+  TYPE_CHECK (NODE)->base.u.bits.block_factor_0
+
+/* Non-zero if the blocking factor is greater than 1.
+   In this case, the blocking factor value is stored in a hash table.  */
+#define TYPE_HAS_BLOCK_FACTOR_X(NODE) \
+  TYPE_CHECK (NODE)->base.u.bits.block_factor_x
+
+/* Non-zero if the blocking factor is not equal to 1 (the default).  */
+#define TYPE_HAS_BLOCK_FACTOR(NODE) \
+  (TYPE_SHARED(NODE) \
+   && (TYPE_HAS_BLOCK_FACTOR_0 (NODE) \
+       || TYPE_HAS_BLOCK_FACTOR_X (NODE)))
+
+/* Return the blocking factor of the type given by NODE..
+   The default block factor is one.  The additional flag bits
+   over-ride the default.  */
+#define TYPE_BLOCK_FACTOR(NODE) \
+  (TYPE_SHARED (NODE) \
+    ? (TYPE_HAS_BLOCK_FACTOR_0 (NODE) ? size_zero_node \
+      : TYPE_HAS_BLOCK_FACTOR_X (NODE) ? block_factor_lookup (NODE) \
+      : NULL_TREE) \
+    : NULL_TREE)
+
+/* Set the block factor in the type described by NODE.
+   For a zero blocking factor set TYPE_BLOCK_FACTOR_0 (NODE). 
+   For a blocking factor greater than 1, insert the value
+   into a hash table indexed by NODE, and then set the
+   flag TYPE_BLOCK_FACTOR_X (NODE).  */
+#define SET_TYPE_BLOCK_FACTOR(NODE, VAL) \
+  do { \
+    if (TYPE_SHARED (NODE)) \
+      { \
+	TYPE_HAS_BLOCK_FACTOR_0 (NODE) = 0; \
+	TYPE_HAS_BLOCK_FACTOR_X (NODE) = 0; \
+	if (VAL) \
+	  { \
+	    gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (VAL))); \
+	    if (!integer_onep (VAL)) \
+	      { \
+		if (integer_zerop (VAL)) \
+		  TYPE_HAS_BLOCK_FACTOR_0 (NODE) = 1; \
+		else \
+		  { \
+		    TYPE_HAS_BLOCK_FACTOR_X (NODE) = 1; \
+		    block_factor_insert (NODE, VAL); \
+		  } \
+	      } \
+          } \
+      } \
+    else \
+      gcc_assert (!VAL); \
+  } while (0)
+
+extern void block_factor_insert (tree, tree);
+extern tree block_factor_lookup (const_tree);
+extern tree build_unshared_type (tree);
+extern void block_factor_lookup_init (void);
+extern tree get_block_factor (const tree);
+
 /* These flags are available for each language front end to use internally.  */
 #define TYPE_LANG_FLAG_0(NODE) (TYPE_CHECK (NODE)->type_common.lang_flag_0)
 #define TYPE_LANG_FLAG_1(NODE) (TYPE_CHECK (NODE)->type_common.lang_flag_1)
@@ -2176,7 +2297,7 @@  extern machine_mode element_mode (const_
 /* Nonzero if DECL represents an SSA name or a variable that can possibly
    have an associated SSA name.  */
 #define SSA_VAR_P(DECL)							\
-	(TREE_CODE (DECL) == VAR_DECL					\
+	((TREE_CODE (DECL) == VAR_DECL && !TREE_SHARED (DECL))          \
 	 || TREE_CODE (DECL) == PARM_DECL				\
 	 || TREE_CODE (DECL) == RESULT_DECL				\
 	 || TREE_CODE (DECL) == SSA_NAME)
@@ -3611,6 +3732,17 @@  tree_operand_check_code (const_tree __t,
 #define boolean_false_node		global_trees[TI_BOOLEAN_FALSE]
 #define boolean_true_node		global_trees[TI_BOOLEAN_TRUE]
 
+/* The UPC type `void *'.  */
+#define upc_pts_type_node	global_trees[TI_UPC_PTS_TYPE]
+
+/* UPC pointer to shared qualified object representation */
+#define upc_pts_rep_type_node	global_trees[TI_UPC_PTS_REP_TYPE]
+#define upc_char_pts_type_node	global_trees[TI_UPC_CHAR_PTS_TYPE]
+#define upc_phase_field_node	global_trees[TI_UPC_PHASE_FIELD]
+#define upc_thread_field_node	global_trees[TI_UPC_THREAD_FIELD]
+#define upc_vaddr_field_node	global_trees[TI_UPC_VADDR_FIELD]
+#define upc_null_pts_node	global_trees[TI_UPC_NULL_PTS]
+
 /* The decimal floating point types. */
 #define dfloat32_type_node              global_trees[TI_DFLOAT32_TYPE]
 #define dfloat64_type_node              global_trees[TI_DFLOAT64_TYPE]
@@ -4151,20 +4283,25 @@  extern tree handle_dll_attribute (tree *
 extern bool check_base_type (const_tree cand, const_tree base);
 
 /* Check whether CAND is suitable to be returned from get_qualified_type
-   (BASE, TYPE_QUALS).  */
+   (BASE, TYPE_QUALS, BLOCK_FACTOR).  */
 
-extern bool check_qualified_type (const_tree, const_tree, int);
+extern bool check_qualified_type (const_tree cand, const_tree base,
+				  int type_quals, tree block_factor);
 
 /* Return a version of the TYPE, qualified as indicated by the
-   TYPE_QUALS, if one exists.  If no qualified version exists yet,
-   return NULL_TREE.  */
+   TYPE_QUALS and BLOCK_FACTOR, if one exists.
+   If no qualified version exists yet, return NULL_TREE.  */
 
-extern tree get_qualified_type (tree, int);
+extern tree get_qualified_type_1 (tree type, int type_quals, tree block_factor);
+#define get_qualified_type(TYPE, QUALS) \
+          get_qualified_type_1 (TYPE, QUALS, 0)
 
 /* Like get_qualified_type, but creates the type if it does not
    exist.  This function never returns NULL_TREE.  */
 
-extern tree build_qualified_type (tree, int);
+extern tree build_qualified_type_1 (tree type, int type_quals, tree block_factor);
+#define build_qualified_type(TYPE, QUALS) \
+   build_qualified_type_1 (TYPE, QUALS, 0)
 
 /* Create a variant of type T with alignment ALIGN.  */
 
@@ -4195,6 +4332,7 @@  extern tree type_hash_canon (unsigned in
 extern tree convert (tree, tree);
 extern unsigned int expr_align (const_tree);
 extern tree size_in_bytes (const_tree);
+extern tree tree_expr_size (const_tree);
 extern HOST_WIDE_INT int_size_in_bytes (const_tree);
 extern HOST_WIDE_INT max_int_size_in_bytes (const_tree);
 extern tree bit_position (const_tree);