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


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

[PATCH 3/5] Named address spaces: C front-end support


Hello,

this implements C front-end support for named address spaces.  It is
intended to be a straight-forward implementation of the semantics as
specified in the TR 18037 document.

The target uses the TARGET_ADDR_SPACE_KEYWORDS hook to provide information
about the named address space keywords and associated addr_space_t values
that are to be supported.  At this point, we do not support non-intrinsic
named address spaces (an optional feature of TR 18037).

In addition, the C front-end uses the TARGET_ADDR_SPACE_SUBSET_P hook to
determine the implementation-defined subset relation between address spaces, 
which is used to define the semantics of many operations according to the TR.

This version of the patch should address all issues raised by Joseph Myers
on prior patches ...

The whole series tested on spu-elf and s390x-ibm-linux.
OK for mainline?

Bye,
Ulrich


2009-08-19  Ben Elliston  <bje@au.ibm.com>
	    Michael Meissner  <meissner@linux.vnet.ibm.com>
	    Ulrich Weigand  <uweigand@de.ibm.com>

	* doc/tm.texi (TARGET_ADDR_SPACE_KEYWORDS): Document.

	* c-common.c (c_common_reswords): If TARGET_ADDR_SPACE_KEYWORDS is
	defined, add the named address space keywords.
	(c_addr_space_name): New function.
	(complete_array_type): Preserve named address space.
	(handle_mode_attribute): Use targetm.addr_space.valid_pointer_mode
	instead of targetm.valid_pointer_mode.

	* c-common.h (enum rid): Add RID_ADDR_SPACE_0 .. RID_ADDR_SPACE_15,
	RID_FIRST_ADDR_SPACE and RID_LAST_ADDR_SPACE.
       	(ADDR_SPACE_KEYWORD): New macro.
	(c_addr_space_name): Add prototype.

	* c-tree.h (struct c_declspecs): Add address_space member.
	(declspecs_add_addrspace): Add prototype.

	* c-pretty-print.c (pp_c_type_qualifier_list): Handle address spaces.

	* c-parser.c (c_parse_init): Add assertion.
	(typedef enum c_id_kind): Add C_ID_ADDRSPACE.
	(c_lex_one_token): Handle address space keywords.
	(c_token_starts_typename): Likewise.
	(c_token_starts_declspecs): Likewise.
	(c_parser_declspecs): Likewise.
	(c_parser_postfix_expression_after_paren_type): Diagnose compound
	literal within function qualified with named address space.

	* c-decl.c (diagnose_mismatched_decls): Diagnose conflicting named
	address space qualifiers.
	(shadow_tag_warned): Warn about useless address space qualifiers.
	(quals_from_declspecs): Handle address space qualifiers.
	(grokdeclarator): Likewise.
	(build_null_declspecs): Likewise.
	(declspecs_add_addrspace): New function.

	* c-typeck.c (addr_space_superset): New function.
	(qualify_type): Handle named address spaces.
	(composite_type): Likewise.
	(common_pointer_type): Likewise.
	(comp_target_types): Likewise.
	(build_conditional_expr): Likewise.
	(handle_warn_cast_qual): Likewise.
	(build_c_cast): Likewise.
	(convert_for_assignment): Likewise.
	(build_binary_op): Likewise.
	(pointer_diff): Handle named address spaces.  Use intermediate
	integer type of sufficient size if required.


Index: gcc-head/gcc/c-common.c
===================================================================
--- gcc-head.orig/gcc/c-common.c
+++ gcc-head/gcc/c-common.c
@@ -708,6 +708,11 @@ const struct c_common_resword c_common_r
   { "inout",		RID_INOUT,		D_OBJC },
   { "oneway",		RID_ONEWAY,		D_OBJC },
   { "out",		RID_OUT,		D_OBJC },
+
+#ifdef TARGET_ADDR_SPACE_KEYWORDS
+  /* Any address space keywords recognized by the target.  */
+  TARGET_ADDR_SPACE_KEYWORDS,
+#endif
 };
 
 const unsigned int num_c_common_reswords =
@@ -838,6 +843,19 @@ const struct attribute_spec c_common_for
   { NULL,                     0, 0, false, false, false, NULL }
 };
 
+/* Return identifier for address space AS.  */
+const char *
+c_addr_space_name (addr_space_t as)
+{
+  unsigned int i;
+
+  for (i = 0; i < num_c_common_reswords; i++)
+    if (c_common_reswords[i].rid == RID_FIRST_ADDR_SPACE + as)
+      return c_common_reswords[i].word;
+
+  gcc_unreachable ();
+}
+
 /* Push current bindings for the function name VAR_DECLS.  */
 
 void
@@ -6453,9 +6471,10 @@ handle_mode_attribute (tree *node, tree 
 
       if (POINTER_TYPE_P (type))
 	{
+	  addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (type));
 	  tree (*fn)(tree, enum machine_mode, bool);
 
-	  if (!targetm.valid_pointer_mode (mode))
+	  if (!targetm.addr_space.valid_pointer_mode (mode, as))
 	    {
 	      error ("invalid pointer mode %qs", p);
 	      return NULL_TREE;
@@ -8504,7 +8523,7 @@ complete_array_type (tree *ptype, tree i
   if (quals == 0)
     unqual_elt = elt;
   else
-    unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED);
+    unqual_elt = c_build_qualified_type (elt, KEEP_QUAL_ADDR_SPACE (quals));
 
   /* Using build_distinct_type_copy and modifying things afterward instead
      of using build_array_type to create a new type preserves all of the
Index: gcc-head/gcc/c-common.h
===================================================================
--- gcc-head.orig/gcc/c-common.h
+++ gcc-head/gcc/c-common.h
@@ -126,6 +126,30 @@ enum rid
   RID_AT_INTERFACE,
   RID_AT_IMPLEMENTATION,
 
+  /* Named address support, mapping the keyword to a particular named address
+     number.  Named address space 0 is reserved for the generic address.  If
+     there are more than 254 named addresses, the addr_space_t type will need
+     to be grown from an unsigned char to unsigned short.  */
+  RID_ADDR_SPACE_0,		/* generic address */
+  RID_ADDR_SPACE_1,
+  RID_ADDR_SPACE_2,
+  RID_ADDR_SPACE_3,
+  RID_ADDR_SPACE_4,
+  RID_ADDR_SPACE_5,
+  RID_ADDR_SPACE_6,
+  RID_ADDR_SPACE_7,
+  RID_ADDR_SPACE_8,
+  RID_ADDR_SPACE_9,
+  RID_ADDR_SPACE_10,
+  RID_ADDR_SPACE_11,
+  RID_ADDR_SPACE_12,
+  RID_ADDR_SPACE_13,
+  RID_ADDR_SPACE_14,
+  RID_ADDR_SPACE_15,
+
+  RID_FIRST_ADDR_SPACE = RID_ADDR_SPACE_0,
+  RID_LAST_ADDR_SPACE = RID_ADDR_SPACE_15,
+
   RID_MAX,
 
   RID_FIRST_MODIFIER = RID_STATIC,
@@ -263,6 +287,10 @@ struct c_common_resword
 #define D_CXX_OBJC	0x100	/* In Objective C, and C++, but not C.  */
 #define D_CXXWARN	0x200	/* In C warn with -Wcxx-compat.  */
 
+/* Macro for backends to define named address keywords.  */
+#define ADDR_SPACE_KEYWORD(STRING, VALUE) \
+  { STRING, RID_FIRST_ADDR_SPACE + (VALUE), D_CONLY | D_EXT }
+
 /* The reserved keyword table.  */
 extern const struct c_common_resword c_common_reswords[];
 
@@ -760,6 +788,7 @@ extern const struct attribute_spec c_com
 
 extern tree (*make_fname_decl) (location_t, tree, int);
 
+extern const char *c_addr_space_name (addr_space_t as);
 extern tree identifier_global_value (tree);
 extern void record_builtin_type (enum rid, const char *, tree);
 extern tree build_void_list_node (void);
Index: gcc-head/gcc/c-decl.c
===================================================================
--- gcc-head.orig/gcc/c-decl.c
+++ gcc-head/gcc/c-decl.c
@@ -1748,8 +1748,35 @@ diagnose_mismatched_decls (tree newdecl,
 	}
       else
 	{
-	  if (TYPE_QUALS (newtype) != TYPE_QUALS (oldtype))
-	    error ("conflicting type qualifiers for %q+D", newdecl);
+	  int new_quals = TYPE_QUALS (newtype);
+	  int old_quals = TYPE_QUALS (oldtype);
+
+	  if (new_quals != old_quals)
+	    {
+	      addr_space_t new_addr = DECODE_QUAL_ADDR_SPACE (new_quals);
+	      addr_space_t old_addr = DECODE_QUAL_ADDR_SPACE (old_quals);
+	      if (new_addr != old_addr)
+		{
+		  if (!new_addr)
+		    error ("conflicting named address spaces (generic vs %s) "
+			   "for %q+D",
+			   c_addr_space_name (old_addr), newdecl);
+		  else if (!old_addr)
+		    error ("conflicting named address spaces (%s vs generic) "
+			   "for %q+D",
+			   c_addr_space_name (new_addr), newdecl);
+		  else
+		    error ("conflicting named address spaces (%s vs %s) "
+			   "for %q+D",
+			   c_addr_space_name (new_addr),
+			   c_addr_space_name (old_addr),
+			   newdecl);
+		}
+
+	      if (CLEAR_QUAL_ADDR_SPACE (new_quals)
+		  != CLEAR_QUAL_ADDR_SPACE (old_quals))
+		error ("conflicting type qualifiers for %q+D", newdecl);
+	    }
 	  else
 	    error ("conflicting types for %q+D", newdecl);
 	  diagnose_arglist_conflict (newdecl, olddecl, newtype, oldtype);
@@ -3606,7 +3633,8 @@ shadow_tag_warned (const struct c_declsp
 	  else if (!declspecs->tag_defined_p
 		   && (declspecs->const_p
 		       || declspecs->volatile_p
-		       || declspecs->restrict_p))
+		       || declspecs->restrict_p
+		       || declspecs->address_space))
 	    {
 	      if (warned != 1)
 		pedwarn (input_location, 0,
@@ -3677,7 +3705,8 @@ shadow_tag_warned (const struct c_declsp
 
   if (!warned && !in_system_header && (declspecs->const_p
 				       || declspecs->volatile_p
-				       || declspecs->restrict_p))
+				       || declspecs->restrict_p
+				       || declspecs->address_space))
     {
       warning (0, "useless type qualifier in empty declaration");
       warned = 2;
@@ -3700,7 +3729,8 @@ quals_from_declspecs (const struct c_dec
 {
   int quals = ((specs->const_p ? TYPE_QUAL_CONST : 0)
 	       | (specs->volatile_p ? TYPE_QUAL_VOLATILE : 0)
-	       | (specs->restrict_p ? TYPE_QUAL_RESTRICT : 0));
+	       | (specs->restrict_p ? TYPE_QUAL_RESTRICT : 0)
+	       | (ENCODE_QUAL_ADDR_SPACE (specs->address_space)));
   gcc_assert (!specs->type
 	      && !specs->decl_attr
 	      && specs->typespec_word == cts_none
@@ -4764,6 +4794,7 @@ grokdeclarator (const struct c_declarato
   bool bitfield = width != NULL;
   tree element_type;
   struct c_arg_info *arg_info = 0;
+  addr_space_t as1, as2, address_space;
   location_t loc = UNKNOWN_LOCATION;
   const char *errmsg;
   tree expr_dummy;
@@ -4894,6 +4925,10 @@ grokdeclarator (const struct c_declarato
   constp = declspecs->const_p + TYPE_READONLY (element_type);
   restrictp = declspecs->restrict_p + TYPE_RESTRICT (element_type);
   volatilep = declspecs->volatile_p + TYPE_VOLATILE (element_type);
+  as1 = declspecs->address_space;
+  as2 = TYPE_ADDR_SPACE (element_type);
+  address_space = (as1 ? as1 : as2);
+
   if (pedantic && !flag_isoc99)
     {
       if (constp > 1)
@@ -4903,11 +4938,27 @@ grokdeclarator (const struct c_declarato
       if (volatilep > 1)
 	pedwarn (loc, OPT_pedantic, "duplicate %<volatile%>");
     }
+
+  if (as1 > 0 && as2 > 0 && as1 != as2)
+    {
+      if (!as1)
+	error ("conflicting named address spaces (generic vs %s)",
+	       c_addr_space_name (as1));
+      else if (!as2)
+	error ("conflicting named address spaces (%s vs generic),",
+	       c_addr_space_name (as2));
+      else
+	error ("conflicting named address spaces (%s vs %s)",
+	       c_addr_space_name (as1),
+	       c_addr_space_name (as2));
+    }
+
   if (!flag_gen_aux_info && (TYPE_QUALS (element_type)))
     type = TYPE_MAIN_VARIANT (type);
   type_quals = ((constp ? TYPE_QUAL_CONST : 0)
 		| (restrictp ? TYPE_QUAL_RESTRICT : 0)
-		| (volatilep ? TYPE_QUAL_VOLATILE : 0));
+		| (volatilep ? TYPE_QUAL_VOLATILE : 0)
+		| ENCODE_QUAL_ADDR_SPACE (address_space));
 
   /* Warn about storage classes that are invalid for certain
      kinds of declarations (parameters, typenames, etc.).  */
@@ -5323,7 +5374,14 @@ grokdeclarator (const struct c_declarato
 	       it, but here we want to make sure we don't ever
 	       modify the shared type, so we gcc_assert (itype)
 	       below.  */
-	      type = build_array_type (type, itype);
+	      {
+		addr_space_t as = DECODE_QUAL_ADDR_SPACE (type_quals);
+		if (as && as != TYPE_ADDR_SPACE (type))
+		  type = build_qualified_type (type,
+					       ENCODE_QUAL_ADDR_SPACE (as));
+
+		type = build_array_type (type, itype);
+	      }
 
 	    if (type != error_mark_node)
 	      {
@@ -5427,6 +5485,15 @@ grokdeclarator (const struct c_declarato
 	    if (really_funcdef)
 	      put_pending_sizes (arg_info->pending_sizes);
 
+	    /* Warn about functions declared in another address space.  */
+	    address_space = DECODE_QUAL_ADDR_SPACE (type_quals);
+	    if (address_space)
+	      {
+		type_quals = CLEAR_QUAL_ADDR_SPACE (type_quals);
+		error ("%qs specified for function %qE",
+		       c_addr_space_name (address_space), name);
+	      }
+
 	    /* Type qualifiers before the return type of the function
 	       qualify the return type, not the function type.  */
 	    if (type_quals)
@@ -5529,6 +5596,47 @@ grokdeclarator (const struct c_declarato
   /* Now TYPE has the actual type, apart from any qualifiers in
      TYPE_QUALS.  */
 
+  /* Warn about address space used for things other that static memory or
+     pointers.  */
+  address_space = DECODE_QUAL_ADDR_SPACE (type_quals);
+  if (address_space)
+    {
+      if (decl_context == NORMAL)
+	{
+	  switch (storage_class)
+	    {
+	    case csc_auto:
+	      error ("%qs combined with %<auto%> qualifier for %qE",
+		     c_addr_space_name (address_space), name);
+	      break;
+	    case csc_register:
+	      error ("%qs combined with %<register%> qualifier for %qE",
+		     c_addr_space_name (address_space), name);
+	      break;
+	    case csc_none:
+	      if (current_function_scope)
+		{
+		  error ("%qs specified for auto variable %qE",
+			 c_addr_space_name (address_space), name);
+		  break;
+		}
+	      break;
+	    case csc_static:
+	    case csc_extern:
+	    case csc_typedef:
+	      break;
+	    default:
+	      gcc_unreachable ();
+	    }
+	}
+      else if (decl_context == PARM && TREE_CODE (type) != ARRAY_TYPE)
+	error ("%qs specified for parameter %qE",
+	       c_addr_space_name (address_space), name);
+      else if (decl_context == FIELD)
+	error ("%qs specified for structure field %qE",
+	       c_addr_space_name (address_space), name);
+    }
+
   /* Check the type and width of a bit-field.  */
   if (bitfield)
     check_bitfield_type_and_width (&type, width, name);
@@ -8321,9 +8429,28 @@ build_null_declspecs (void)
   ret->volatile_p = false;
   ret->restrict_p = false;
   ret->saturating_p = false;
+  ret->address_space = 0;
   return ret;
 }
 
+/* Add the address space ADDRSPACE to the declaration specifiers
+   SPECS, returning SPECS.  */
+
+struct c_declspecs *
+declspecs_add_addrspace (struct c_declspecs *specs, addr_space_t as)
+{
+  specs->non_sc_seen_p = true;
+  specs->declspecs_seen_p = true;
+
+  if (specs->address_space > 0 && specs->address_space != as)
+    error ("incompatible address space qualifiers %qs and %qs",
+	   c_addr_space_name (as),
+	   c_addr_space_name (specs->address_space));
+  else
+    specs->address_space = as;
+  return specs;
+}
+
 /* Add the type qualifier QUAL to the declaration specifiers SPECS,
    returning SPECS.  */
 
Index: gcc-head/gcc/c-parser.c
===================================================================
--- gcc-head.orig/gcc/c-parser.c
+++ gcc-head/gcc/c-parser.c
@@ -71,6 +71,10 @@ c_parse_init (void)
   tree id;
   int mask = 0;
 
+  /* Make sure RID_MAX hasn't grown past the 8 bits used to hold the keyword in
+     the c_token structure.  */
+  gcc_assert (RID_MAX <= 255);
+
   mask |= D_CXXONLY;
   if (!flag_isoc99)
     mask |= D_C99;
@@ -131,6 +135,8 @@ typedef enum c_id_kind {
   C_ID_TYPENAME,
   /* An identifier declared as an Objective-C class name.  */
   C_ID_CLASSNAME,
+  /* An address space identifier.  */
+  C_ID_ADDRSPACE,
   /* Not an identifier.  */
   C_ID_NONE
 } c_id_kind;
@@ -225,6 +231,13 @@ c_lex_one_token (c_parser *parser, c_tok
 			    "identifier %qE conflicts with C++ keyword",
 			    token->value);
 	      }
+	    else if (rid_code >= RID_FIRST_ADDR_SPACE
+		     && rid_code <= RID_LAST_ADDR_SPACE)
+	      {
+		token->id_kind = C_ID_ADDRSPACE;
+		token->keyword = rid_code;
+		break;
+	      }
 	    else if (c_dialect_objc ())
 	      {
 		if (!objc_is_reserved_word (token->value)
@@ -351,6 +364,8 @@ c_token_starts_typename (c_token *token)
 	{
 	case C_ID_ID:
 	  return false;
+	case C_ID_ADDRSPACE:
+	  return true;
 	case C_ID_TYPENAME:
 	  return true;
 	case C_ID_CLASSNAME:
@@ -421,6 +436,8 @@ c_token_starts_declspecs (c_token *token
 	{
 	case C_ID_ID:
 	  return false;
+	case C_ID_ADDRSPACE:
+	  return true;
 	case C_ID_TYPENAME:
 	  return true;
 	case C_ID_CLASSNAME:
@@ -1404,6 +1421,7 @@ c_parser_asm_definition (c_parser *parse
      const
      restrict
      volatile
+     address-space-qualifier
 
    (restrict is new in C99.)
 
@@ -1412,6 +1430,12 @@ c_parser_asm_definition (c_parser *parse
    declaration-specifiers:
      attributes declaration-specifiers[opt]
 
+   type-qualifier:
+     address-space
+
+   address-space:
+     identifier recognized by the target
+
    storage-class-specifier:
      __thread
 
@@ -1452,6 +1476,17 @@ c_parser_declspecs (c_parser *parser, st
 	{
 	  tree value = c_parser_peek_token (parser)->value;
 	  c_id_kind kind = c_parser_peek_token (parser)->id_kind;
+
+	  if (kind == C_ID_ADDRSPACE)
+	    {
+	      addr_space_t as
+		= c_parser_peek_token (parser)->keyword - RID_FIRST_ADDR_SPACE;
+	      declspecs_add_addrspace (specs, as);
+	      c_parser_consume_token (parser);
+	      attrs_ok = true;
+	      continue;
+	    }
+
 	  /* This finishes the specifiers unless a type name is OK, it
 	     is declared as a type name and a type name hasn't yet
 	     been seen.  */
@@ -5710,6 +5745,14 @@ c_parser_postfix_expression_after_paren_
   finish_init ();
   maybe_warn_string_init (type, init);
 
+  if (type != error_mark_node
+      && TYPE_ADDR_SPACE (type)
+      && current_function_decl)
+    {
+      error ("compound literal qualified by address-space qualifier");
+      type = error_mark_node;
+    }
+
   if (!flag_isoc99)
     pedwarn (start_loc, OPT_pedantic, "ISO C90 forbids compound literals");
   non_const = ((init.value && TREE_CODE (init.value) == CONSTRUCTOR)
Index: gcc-head/gcc/c-pretty-print.c
===================================================================
--- gcc-head.orig/gcc/c-pretty-print.c
+++ gcc-head/gcc/c-pretty-print.c
@@ -225,7 +225,11 @@ pp_c_space_for_pointer_operator (c_prett
        const
        restrict                              -- C99
        __restrict__                          -- GNU C
-       volatile    */
+       address-space-qualifier		     -- GNU C
+       volatile
+
+   address-space-qualifier:
+       identifier			     -- GNU C  */
 
 void
 pp_c_type_qualifier_list (c_pretty_printer *pp, tree t)
@@ -245,6 +249,12 @@ pp_c_type_qualifier_list (c_pretty_print
     pp_c_cv_qualifier (pp, "volatile");
   if (qualifiers & TYPE_QUAL_RESTRICT)
     pp_c_cv_qualifier (pp, flag_isoc99 ? "restrict" : "__restrict__");
+
+  if (TYPE_ADDR_SPACE (t))
+    {
+      const char *as = c_addr_space_name (TYPE_ADDR_SPACE (t));
+      pp_c_identifier (pp, as);
+    }
 }
 
 /* pointer:
Index: gcc-head/gcc/c-tree.h
===================================================================
--- gcc-head.orig/gcc/c-tree.h
+++ gcc-head/gcc/c-tree.h
@@ -295,6 +295,8 @@ struct c_declspecs {
   BOOL_BITFIELD restrict_p : 1;
   /* Whether "_Sat" was specified.  */
   BOOL_BITFIELD saturating_p : 1;
+  /* The address space that the declaration belongs to.  */
+  addr_space_t address_space;
 };
 
 /* The various kinds of declarators in C.  */
@@ -512,6 +514,8 @@ extern struct c_declspecs *declspecs_add
 					       struct c_typespec);
 extern struct c_declspecs *declspecs_add_scspec (struct c_declspecs *, tree);
 extern struct c_declspecs *declspecs_add_attrs (struct c_declspecs *, tree);
+extern struct c_declspecs *declspecs_add_addrspace (struct c_declspecs *,
+						    addr_space_t);
 extern struct c_declspecs *finish_declspecs (struct c_declspecs *);
 
 /* in c-objc-common.c */
Index: gcc-head/gcc/c-typeck.c
===================================================================
--- gcc-head.orig/gcc/c-typeck.c
+++ gcc-head/gcc/c-typeck.c
@@ -283,14 +283,55 @@ c_type_promotes_to (tree type)
   return type;
 }
 
+/* Return true if between two named address spaces, whether there is a superset
+   named address space that encompasses both address spaces.  If there is a
+   superset, return which address space is the superset.  */
+
+static bool
+addr_space_superset (addr_space_t as1, addr_space_t as2, addr_space_t *common)
+{
+  if (as1 == as2)
+    {
+      *common = as1;
+      return true;
+    }
+  else if (targetm.addr_space.subset_p (as1, as2))
+    {
+      *common = as2;
+      return true;
+    }
+  else if (targetm.addr_space.subset_p (as2, as1))
+    {
+      *common = as1;
+      return true;
+    }
+  else
+    return false;
+}
+
 /* Return a variant of TYPE which has all the type qualifiers of LIKE
    as well as those of TYPE.  */
 
 static tree
 qualify_type (tree type, tree like)
 {
+  addr_space_t as_type = TYPE_ADDR_SPACE (type);
+  addr_space_t as_like = TYPE_ADDR_SPACE (like);
+  addr_space_t as_common;
+
+  /* If the two named address spaces are different, determine the common
+     superset address space.  If there isn't one, raise an error.  */
+  if (!addr_space_superset (as_type, as_like, &as_common))
+    {
+      as_common = as_type;
+      error ("%qT and %qT are in disjoint named address spaces",
+	     type, like);
+    }
+
   return c_build_qualified_type (type,
-				 TYPE_QUALS (type) | TYPE_QUALS (like));
+				 TYPE_QUALS_NO_ADDR_SPACE (type)
+				 | TYPE_QUALS_NO_ADDR_SPACE (like)
+				 | ENCODE_QUAL_ADDR_SPACE (as_common));
 }
 
 /* Return true iff the given tree T is a variable length array.  */
@@ -370,7 +411,8 @@ composite_type (tree t1, tree t2)
 	bool t1_complete, t2_complete;
 
 	/* We should not have any type quals on arrays at all.  */
-	gcc_assert (!TYPE_QUALS (t1) && !TYPE_QUALS (t2));
+	gcc_assert (!TYPE_QUALS_NO_ADDR_SPACE (t1)
+		    && !TYPE_QUALS_NO_ADDR_SPACE (t2));
 
 	t1_complete = COMPLETE_TYPE_P (t1);
 	t2_complete = COMPLETE_TYPE_P (t2);
@@ -584,6 +626,8 @@ common_pointer_type (tree t1, tree t2)
   tree pointed_to_2, mv2;
   tree target;
   unsigned target_quals;
+  addr_space_t as1, as2, as_common;
+  int quals1, quals2;
 
   /* Save time if the two types are the same.  */
 
@@ -615,10 +659,24 @@ common_pointer_type (tree t1, tree t2)
   /* For function types do not merge const qualifiers, but drop them
      if used inconsistently.  The middle-end uses these to mark const
      and noreturn functions.  */
+  quals1 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_1);
+  quals2 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_2);
+
   if (TREE_CODE (pointed_to_1) == FUNCTION_TYPE)
-    target_quals = TYPE_QUALS (pointed_to_1) & TYPE_QUALS (pointed_to_2);
+    target_quals = (quals1 & quals2);
   else
-    target_quals = TYPE_QUALS (pointed_to_1) | TYPE_QUALS (pointed_to_2);
+    target_quals = (quals1 | quals2);
+
+  /* If the two named address spaces are different, determine the common
+     superset address space.  This is guaranteed to exist due to the
+     assumption that comp_target_type returned non-zero.  */
+  as1 = TYPE_ADDR_SPACE (pointed_to_1);
+  as2 = TYPE_ADDR_SPACE (pointed_to_2);
+  if (!addr_space_superset (as1, as2, &as_common))
+    gcc_unreachable ();
+
+  target_quals |= ENCODE_QUAL_ADDR_SPACE (as_common);
+
   t1 = build_pointer_type (c_build_qualified_type (target, target_quals));
   return build_type_attribute_variant (t1, attributes);
 }
@@ -1102,20 +1160,28 @@ comptypes_internal (const_tree type1, co
   return attrval == 2 && val == 1 ? 2 : val;
 }
 
-/* Return 1 if TTL and TTR are pointers to types that are equivalent,
-   ignoring their qualifiers.  */
+/* Return 1 if TTL and TTR are pointers to types that are equivalent, ignoring
+   their qualifiers, except for named address spaces.  If the pointers point to
+   different named addresses, then we must determine if one address space is a
+   subset of the other.  */
 
 static int
 comp_target_types (location_t location, tree ttl, tree ttr)
 {
   int val;
-  tree mvl, mvr;
+  tree mvl = TREE_TYPE (ttl);
+  tree mvr = TREE_TYPE (ttr);
+  addr_space_t asl = TYPE_ADDR_SPACE (mvl);
+  addr_space_t asr = TYPE_ADDR_SPACE (mvr);
+  addr_space_t as_common;
   bool enum_and_int_p;
 
+  /* Fail if pointers point to incompatible address spaces.  */
+  if (!addr_space_superset (asl, asr, &as_common))
+    return 0;
+
   /* Do not lose qualifiers on element types of array types that are
      pointer targets by taking their TYPE_MAIN_VARIANT.  */
-  mvl = TREE_TYPE (ttl);
-  mvr = TREE_TYPE (ttr);
   if (TREE_CODE (mvl) != ARRAY_TYPE)
     mvl = TYPE_MAIN_VARIANT (mvl);
   if (TREE_CODE (mvr) != ARRAY_TYPE)
@@ -3062,11 +3128,43 @@ static tree
 pointer_diff (location_t loc, tree op0, tree op1)
 {
   tree restype = ptrdiff_type_node;
+  tree result, inttype;
 
+  addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op0)));
+  addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op1)));
   tree target_type = TREE_TYPE (TREE_TYPE (op0));
   tree con0, con1, lit0, lit1;
   tree orig_op1 = op1;
 
+  /* If the operands point into different address spaces, we need to
+     explicitly convert them to pointers into the common address space
+     before we can subtract the numerical address values.  */
+  if (as0 != as1)
+    {
+      addr_space_t as_common;
+      tree common_type;
+
+      /* Determine the common superset address space.  This is guaranteed
+	 to exist because the caller verified that comp_target_types
+	 returned non-zero.  */
+      if (!addr_space_superset (as0, as1, &as_common))
+	gcc_unreachable ();
+
+      common_type = common_pointer_type (TREE_TYPE (op0), TREE_TYPE (op1));
+      op0 = convert (common_type, op0);
+      op1 = convert (common_type, op1);
+    }
+
+  /* Determine integer type to perform computations in.  This will usually
+     be the same as the result type (ptrdiff_t), but may need to be a wider
+     type if pointers for the address space are wider than ptrdiff_t.  */
+  if (TYPE_PRECISION (restype) < TYPE_PRECISION (TREE_TYPE (op0)))
+    inttype = lang_hooks.types.type_for_size
+		(TYPE_PRECISION (TREE_TYPE (op0)), 0);
+  else
+    inttype = restype;
+
+
   if (TREE_CODE (target_type) == VOID_TYPE)
     pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith, 
 	     "pointer of type %<void *%> used in subtraction");
@@ -3083,12 +3181,18 @@ pointer_diff (location_t loc, tree op0, 
      So first try to find a common term here 'by hand'; we want to cover
      at least the cases that occur in legal static initializers.  */
   if (CONVERT_EXPR_P (op0)
+      && (!POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (op0, 0)))
+          || TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op0))) ==
+             TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (op0, 0)))))
       && (TYPE_PRECISION (TREE_TYPE (op0))
 	  == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op0, 0)))))
     con0 = TREE_OPERAND (op0, 0);
   else
     con0 = op0;
   if (CONVERT_EXPR_P (op1)
+      && (!POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (op1, 0)))
+          || TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op1))) ==
+             TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (op1, 0)))))
       && (TYPE_PRECISION (TREE_TYPE (op1))
 	  == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op1, 0)))))
     con1 = TREE_OPERAND (op1, 0);
@@ -3124,8 +3228,8 @@ pointer_diff (location_t loc, tree op0, 
      in case restype is a short type.  */
 
   op0 = build_binary_op (loc,
-			 MINUS_EXPR, convert (restype, op0),
-			 convert (restype, op1), 0);
+			 MINUS_EXPR, convert (inttype, op0),
+			 convert (inttype, op1), 0);
   /* This generates an error if op1 is pointer to incomplete type.  */
   if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (orig_op1))))
     error_at (loc, "arithmetic on pointer to an incomplete type");
@@ -3134,8 +3238,11 @@ pointer_diff (location_t loc, tree op0, 
   op1 = c_size_in_bytes (target_type);
 
   /* Divide by the size, in easiest possible way.  */
-  return fold_build2_loc (loc, EXACT_DIV_EXPR, restype,
-			  op0, convert (restype, op1));
+  result = fold_build2_loc (loc, EXACT_DIV_EXPR, inttype,
+			    op0, convert (inttype, op1));
+
+  /* Convert to final result type if necessary.  */
+  return convert (restype, result);
 }
 
 /* Construct and perhaps optimize a tree representation
@@ -3963,12 +4070,22 @@ build_conditional_expr (location_t colon
     }
   else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
     {
+      addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1));
+      addr_space_t as2 = TYPE_ADDR_SPACE (TREE_TYPE (type2));
+      addr_space_t as_common;
+
       if (comp_target_types (colon_loc, type1, type2))
 	result_type = common_pointer_type (type1, type2);
       else if (null_pointer_constant_p (orig_op1))
-	result_type = qualify_type (type2, type1);
+	result_type = type2;
       else if (null_pointer_constant_p (orig_op2))
-	result_type = qualify_type (type1, type2);
+	result_type = type1;
+      else if (!addr_space_superset (as1, as2, &as_common))
+	{
+	  error_at (colon_loc, "pointers to disjoint address spaces "
+		    "used in conditional expression");
+	  return error_mark_node;
+	}
       else if (VOID_TYPE_P (TREE_TYPE (type1)))
 	{
 	  if (TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE)
@@ -3989,10 +4106,13 @@ build_conditional_expr (location_t colon
 	}
       else
 	{
+	  int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
+
 	  if (!objc_ok)
 	    pedwarn (colon_loc, 0,
 		     "pointer type mismatch in conditional expression");
-	  result_type = build_pointer_type (void_type_node);
+	  result_type = build_pointer_type
+			  (build_qualified_type (void_type_node, qual));
 	}
     }
   else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
@@ -4151,7 +4271,8 @@ build_compound_expr (location_t loc, tre
 /* Issue -Wcast-qual warnings when appropriate.  TYPE is the type to
    which we are casting.  OTYPE is the type of the expression being
    cast.  Both TYPE and OTYPE are pointer types.  -Wcast-qual appeared
-   on the command line.  */
+   on the command line.  Named address space qualifiers are not handled
+   here, because they result in different warnings.  */
 
 static void
 handle_warn_cast_qual (tree type, tree otype)
@@ -4177,9 +4298,11 @@ handle_warn_cast_qual (tree type, tree o
 	 taken away.  */
       if (TREE_CODE (in_otype) == FUNCTION_TYPE
 	  && TREE_CODE (in_type) == FUNCTION_TYPE)
-	added |= (TYPE_QUALS (in_type) & ~TYPE_QUALS (in_otype));
+	added |= (TYPE_QUALS_NO_ADDR_SPACE (in_type)
+		  & ~TYPE_QUALS_NO_ADDR_SPACE (in_otype));
       else
-	discarded |= (TYPE_QUALS (in_otype) & ~TYPE_QUALS (in_type));
+	discarded |= (TYPE_QUALS_NO_ADDR_SPACE (in_otype)
+		      & ~TYPE_QUALS_NO_ADDR_SPACE (in_type));
     }
   while (TREE_CODE (in_type) == POINTER_TYPE
 	 && TREE_CODE (in_otype) == POINTER_TYPE);
@@ -4328,6 +4451,36 @@ build_c_cast (location_t loc, tree type,
 	  && TREE_CODE (otype) == POINTER_TYPE)
 	handle_warn_cast_qual (type, otype);
 
+      /* Warn about conversions between pointers to disjoint
+	 address spaces.  */
+      if (TREE_CODE (type) == POINTER_TYPE
+	  && TREE_CODE (otype) == POINTER_TYPE
+	  && !null_pointer_constant_p (value))
+	{
+	  addr_space_t as_to = TYPE_ADDR_SPACE (TREE_TYPE (type));
+	  addr_space_t as_from = TYPE_ADDR_SPACE (TREE_TYPE (otype));
+	  addr_space_t as_common;
+
+	  if (!addr_space_superset (as_to, as_from, &as_common))
+	    {
+	      if (!as_from)
+		warning_at (loc, 0, "cast to %s address space pointer "
+			    "from disjoint generic address space pointer",
+			    c_addr_space_name (as_to));
+
+	      else if (!as_to)
+		warning_at (loc, 0, "cast to generic address space pointer "
+			    "from disjoint %s address space pointer",
+			    c_addr_space_name (as_from));
+
+	      else
+		warning_at (loc, 0, "cast to %s address space pointer "
+			    "from disjoint %s address space pointer",
+			    c_addr_space_name (as_to),
+			    c_addr_space_name (as_from));
+	    }
+	}
+
       /* Warn about possible alignment problems.  */
       if (STRICT_ALIGNMENT
 	  && TREE_CODE (type) == POINTER_TYPE
@@ -4922,7 +5075,8 @@ convert_for_assignment (location_t locat
 		     certain things, it is okay to use a const or volatile
 		     function where an ordinary one is wanted, but not
 		     vice-versa.  */
-		  if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr))
+		  if (TYPE_QUALS_NO_ADDR_SPACE (ttl)
+		      & ~TYPE_QUALS_NO_ADDR_SPACE (ttr))
 		    WARN_FOR_ASSIGNMENT (location, 0,
 					 G_("passing argument %d of %qE "
 					    "makes qualified function "
@@ -4936,7 +5090,8 @@ convert_for_assignment (location_t locat
 					 G_("return makes qualified function "
 					    "pointer from unqualified"));
 		}
-	      else if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
+	      else if (TYPE_QUALS_NO_ADDR_SPACE (ttr)
+		       & ~TYPE_QUALS_NO_ADDR_SPACE (ttl))
 		WARN_FOR_ASSIGNMENT (location, 0,
 				     G_("passing argument %d of %qE discards "
 					"qualifiers from pointer target type"),
@@ -4969,6 +5124,8 @@ convert_for_assignment (location_t locat
       tree mvr = ttr;
       bool is_opaque_pointer;
       int target_cmp = 0;   /* Cache comp_target_types () result.  */
+      addr_space_t asl;
+      addr_space_t asr;
 
       if (TREE_CODE (mvl) != ARRAY_TYPE)
 	mvl = TYPE_MAIN_VARIANT (mvl);
@@ -4989,6 +5146,36 @@ convert_for_assignment (location_t locat
 	    	    "request for implicit conversion "
 		    "from %qT to %qT not permitted in C++", rhstype, type);
 
+      /* See if the pointers point to incompatible address spaces.  */
+      asl = TYPE_ADDR_SPACE (ttl);
+      asr = TYPE_ADDR_SPACE (ttr);
+      if (!null_pointer_constant_p (rhs)
+	  && asr != asl && !targetm.addr_space.subset_p (asr, asl))
+	{
+	  switch (errtype)
+	    {
+	    case ic_argpass:
+	      error_at (location, "passing argument %d of %qE from pointer to "
+			"non-enclosed address space", parmnum, rname);
+	      break;
+	    case ic_assign:
+	      error_at (location, "assignment from pointer to "
+			"non-enclosed address space");
+	      break;
+	    case ic_init:
+	      error_at (location, "initialization from pointer to "
+			"non-enclosed address space");
+	      break;
+	    case ic_return:
+	      error_at (location, "return from pointer to "
+			"non-enclosed address space");
+	      break;
+	    default:
+	      gcc_unreachable ();
+	    }
+	  return error_mark_node;
+	}
+
       /* Check if the right-hand side has a format attribute but the
 	 left-hand side doesn't.  */
       if (warn_missing_format_attribute
@@ -5052,7 +5239,8 @@ convert_for_assignment (location_t locat
 	  else if (TREE_CODE (ttr) != FUNCTION_TYPE
 		   && TREE_CODE (ttl) != FUNCTION_TYPE)
 	    {
-	      if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
+	      if (TYPE_QUALS_NO_ADDR_SPACE (ttr)
+		  & ~TYPE_QUALS_NO_ADDR_SPACE (ttl))
 		{
 		  /* Types differing only by the presence of the 'volatile'
 		     qualifier are acceptable if the 'volatile' has been added
@@ -5092,7 +5280,8 @@ convert_for_assignment (location_t locat
 		 that say the function will not do certain things,
 		 it is okay to use a const or volatile function
 		 where an ordinary one is wanted, but not vice-versa.  */
-	      if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr))
+	      if (TYPE_QUALS_NO_ADDR_SPACE (ttl)
+		  & ~TYPE_QUALS_NO_ADDR_SPACE (ttr))
 		WARN_FOR_ASSIGNMENT (location, 0,
 				     G_("passing argument %d of %qE makes "
 					"qualified function pointer "
@@ -9195,24 +9384,34 @@ build_binary_op (location_t location, en
 	{
 	  tree tt0 = TREE_TYPE (type0);
 	  tree tt1 = TREE_TYPE (type1);
+	  addr_space_t as0 = TYPE_ADDR_SPACE (tt0);
+	  addr_space_t as1 = TYPE_ADDR_SPACE (tt1);
+	  addr_space_t as_common = 0;
+
 	  /* Anything compares with void *.  void * compares with anything.
 	     Otherwise, the targets must be compatible
 	     and both must be object or both incomplete.  */
 	  if (comp_target_types (location, type0, type1))
 	    result_type = common_pointer_type (type0, type1);
+	  else if (null_pointer_constant_p (orig_op0))
+	    result_type = type1;
+	  else if (null_pointer_constant_p (orig_op1))
+	    result_type = type0;
+	  else if (!addr_space_superset (as0, as1, &as_common))
+	    {
+	      error_at (location, "comparison of pointers to "
+			"disjoint address spaces");
+	      return error_mark_node;
+	    }
 	  else if (VOID_TYPE_P (tt0))
 	    {
-	      /* op0 != orig_op0 detects the case of something
-		 whose value is 0 but which isn't a valid null ptr const.  */
-	      if (pedantic && !null_pointer_constant_p (orig_op0)
-		  && TREE_CODE (tt1) == FUNCTION_TYPE)
+	      if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE)
 		pedwarn (location, OPT_pedantic, "ISO C forbids "
 			 "comparison of %<void *%> with function pointer");
 	    }
 	  else if (VOID_TYPE_P (tt1))
 	    {
-	      if (pedantic && !null_pointer_constant_p (orig_op1)
-		  && TREE_CODE (tt0) == FUNCTION_TYPE)
+	      if (pedantic && TREE_CODE (tt0) == FUNCTION_TYPE)
 		pedwarn (location, OPT_pedantic, "ISO C forbids "
 			 "comparison of %<void *%> with function pointer");
 	    }
@@ -9223,7 +9422,11 @@ build_binary_op (location_t location, en
 		       "comparison of distinct pointer types lacks a cast");
 
 	  if (result_type == NULL_TREE)
-	    result_type = ptr_type_node;
+	    {
+	      int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
+	      result_type = build_pointer_type
+			      (build_qualified_type (void_type_node, qual));
+	    }
 	}
       else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1))
 	{
@@ -9267,6 +9470,10 @@ build_binary_op (location_t location, en
 	short_compare = 1;
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
 	{
+	  addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (type0));
+	  addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1));
+	  addr_space_t as_common;
+
 	  if (comp_target_types (location, type0, type1))
 	    {
 	      result_type = common_pointer_type (type0, type1);
@@ -9278,9 +9485,17 @@ build_binary_op (location_t location, en
 		pedwarn (location, OPT_pedantic, "ISO C forbids "
 			 "ordered comparisons of pointers to functions");
 	    }
+	  else if (!addr_space_superset (as0, as1, &as_common))
+	    {
+	      error_at (location, "comparison of pointers to "
+			"disjoint address spaces");
+	      return error_mark_node;
+	    }
 	  else
 	    {
-	      result_type = ptr_type_node;
+	      int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
+	      result_type = build_pointer_type
+			      (build_qualified_type (void_type_node, qual));
 	      pedwarn (location, 0,
 		       "comparison of distinct pointer types lacks a cast");
 	    }
Index: gcc-head/gcc/doc/tm.texi
===================================================================
--- gcc-head.orig/gcc/doc/tm.texi
+++ gcc-head/gcc/doc/tm.texi
@@ -9829,6 +9829,18 @@ Internally, address spaces are represent
 range 0 to 15 with address space 0 being reserved for the generic
 address space.
 
+@defmac TARGET_ADDR_SPACE_KEYWORDS
+A list of @code{ADDR_SPACE_KEYWORD} macros to define each named
+address keyword.  The @code{ADDR_SPACE_KEYWORD} macro takes two
+arguments, the keyword string and the number of the named address
+space.  For example, the SPU port uses the following to declare
+@code{__ea} as the keyword for named address space #1:
+@smallexample
+#define ADDR_SPACE_EA 1
+#define TARGET_ADDR_SPACE_KEYWORDS ADDR_SPACE_KEYWORD ("__ea", ADDR_SPACE_EA)
+@end smallexample
+@end defmac
+
 @deftypefn {Target Hook} {enum machine_mode} TARGET_ADDR_SPACE_POINTER_MODE (addr_space_t @var{address_space})
 Define this to return the machine mode to use for pointers to
 @var{address_space} if the target supports named address spaces.
-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com


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