[PATCH] Named address support for 4.5, take 3

Michael Meissner meissner@linux.vnet.ibm.com
Thu Jan 15 02:35:00 GMT 2009


This patch is the current implementation of the named address support that we
would like to go into 4.5.  There is one outstanding bug that came up during
testing, where the compiler generates the wrong code if you take the address of
a static variable in another named address space.

Normal uses of the variable work fine, but the compiler doesn't add in
__ea_local_store to the address that is saved in the constant pool (__ea
addresses are not treated as legitimate constants, so the compiler pushes the
address to the constant pool -- the @ppu syntax is used to indicate it is a
__ea address, but there isn't a hook right now to generate additional code when
loading up an address from a constant pool).  The other two SPU compilers that
support __ea addresses, currently do not generate the correct code for this
case either).  This is test execute1.c and execute1-m64. which are currently
marked as XFAIL.

In this set of patches as compared to my December patch against the mainline, I
went through the places where memory addresses are modified and added in named
address support.

I added a hook so that the result of subtracting two pointers to named address
spaces might not be size_type (for example on the Cell, subtracting two __ea
pointers with -mea64 gives a 64-bit result instead of 32-bit).

I added hooks for the named address support versions of the functions
memory_address, strict_memory_address, legitimize_address.

I added a hook to determine whether something in a named address space or a
pointer to a named address space can be initialized.  On the SPU, I disallowed
anything that needs to be relocated from going into the __ea address space, and
disallowed pointers to the named address space.

I changed how GCC adds the named address space keywords by putting the keywords
directly in the keyword look, rather than calling a target hook for each
identifier.  I allowed space in the RID's for up to 16 different named address
space keywords.

Both the x86_64 and powerpc compilers build and bootstrap against these set of
patches.  The powerpc make check is the same.  The x86_64 make check has
several failures on the trunk that are not present in the patched branch that
are timeouts (I need to bump up the timeout for use on that server I guess).
The SPU compiler has no new unexpected regressions compared to the mainline.

Do these changes answer all of the objections in previous versions of the
feature set?

[gcc changes]
2009-01-13  Ben Elliston  <bje@au.ibm.com>
	    Michael Meissner  <meissner@linux.vnet.ibm.com>

	* doc/extend.texi (Named Address Spaces): Add new section
	documenting named address space support.

	* doc/tm.texi (Named Address Spaces): Add new section to document
	named address space support.
	(TARGET_ADDR_SPACE_KEYWORDS): Document how to add named address
	space keywords.
	(TARGET_ADDR_SPACE_MINUS_TYPE): Document new named address space
	target hook.
	(TARGET_ADDR_SPACE_NAME): Ditto.
	(TARGET_ADDR_SPACE_MEMORY_ADDRESS_P): Ditto.
	(TARGET_ADDR_SPACE_STRICT_MEMORY_ADDRESS_P): Ditto.
	(TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS): Ditto.
	(TARGET_ADDR_SPACE_CAN_CONVERT_P): Ditto.
	(TARGET_ADDR_SPACE_NOP_CONVERT_P): Ditto.
	(TARGET_ADDR_SPACE_SUBSET_P): Ditto.
	(TARGET_ADDR_SPACE_CONVERT): Ditto.
	(TARGET_ADDR_SPACE_SECTION_NAME): Ditto.
	(TARGET_ADDR_SPACE_STATIC_INIT_OK_P): Ditto.

	* doc/invoke.texi (-mea32): Document new SPU switch.
	(-mea64): Ditto.
	(-mcache-size=...): Ditto.
	(-mea-to-generic-conversion): Ditto.
	(-mno-ea-to-generic-conversion): Ditto.
	(-maddress-space-conversion): Ditto.
	(-mno-address-space-conversion): Ditto.
	(-matomic-updates): Ditto.
	(-mno-atomic-updates): Ditto.

	* doc/rtl.texi (MEM_ADDR_SPACE): Document named address space
	accessor macro.

	* targhooks.c (default_valid_pointer_mode): New default hook added
	for named address space support.
	(default_addr_space_pointer_mode): Ditto.
	(default_addr_space_minus_type): Ditto.
	(default_addr_space_name): Ditto.
	(default_addr_space_memory_address_p): Ditto.
	(default_addr_space_strict_memory_address_p): Ditto.
	(default_addr_space_legitimize_address): Ditto.
	(default_addr_space_can_convert_p): Ditto.
	(default_addr_space_nop_convert_p): Ditto.
	(default_addr_space_subset_p): Ditto.
	(default_addr_space_convert): Ditto.
	(default_addr_space_section_name): Ditto.
	(default_addr_space_static_init_ok_p): Ditto.

	* targhooks.h (default_valid_pointer_mode): New declaration.
	(default_addr_space_pointer_mode): Ditto.
	(default_addr_space_minus_type): Ditto.
	(default_addr_space_name): Ditto.
	(default_addr_space_memory_address_p): Ditto.
	(default_addr_space_strict_memory_address_p): Ditto.
	(default_addr_space_legitimize_address): Ditto.
	(default_addr_space_can_convert_p): Ditto.
	(default_addr_space_nop_convert_p): Ditto.
	(default_addr_space_subset_p): Ditto.
	(default_addr_space_convert): Ditto.
	(default_addr_space_section_name): Ditto.
	(default_addr_space_static_init_ok_p): Ditto.

	* tree-pretty-print.c (dump_generic_node): If the tree is in a
	different named address space, print it out.

	* tree.c (integer_pow2p): Add support for having different pointer
	sizes for named address support.
	(tree_log2): Ditto.
	(tree_floor_log2): Ditto.
	(set_type_quals): Set the named address space field from the
	type qualifier.
	(check_qualified_type): Convert cand argument to const_tree.
	(build_pointer_type): Add named address space support.
	(build_reference_type): Ditto.
	(build_array_node): Ditto.
	(signed_or_unsigned_type_for): Ditto.
	(int_or_pointer_precision): New function to return the precision
	of int or pointer types.  Handle pointers to named address
	spaces.

	* tree.h (TYPE_ADDR_SPACE): New accessor macro for named address
	space support.
	(ENCODE_QUAL_ADDR_SPACE): Macro to encode named address space into
	the type qualifiers.
	(DECODE_QUAL_ADDR_SPACE): Macro to get named address space from
	type qualifiers.
	(CLEAR_QUAL_ADDR_SPACE): Macro to clear the named address space
	field in the type qualifiers.
	(KEEP_QUAL_ADDR_SPACE): Macro to clear all type qualifiers except
	for the named address space.
	(TYPE_QUALS): Add encoding of the named address space to the type
	qualifiers.
	(TYPE_QUALS_NO_ADDR_SPACE): New macro, like TYPE_QUALS, except
	don't include the named address space in the qualifiers.
	(struct tree_type): Add address_space field, move alias_set up
	higher.
	(int_or_pointer_precision): Add declaration.

	* target.h (struct addr_space): New structure that holds all of
	the named address space hooks.
	(struct gcc_target): Add struct addr_space.

	* fold-const.c (toplevel): Include target.h.
	(fit_double_type): Add named address space support.
	(fold_convert_const): Ditto.

	* auto-inc-dec.c (toplevel): Include target.h.
	(try_merge): Deal with pointers that can be different sizes due to
	named address space support.
	(find_inc): Ditto.

	* c-tree.h (struct c_declspecs): Add address space field.
	(declspecs_add_addrspace): Add declaration.

	* dwarf2out.c (modified_type_die): Add named address space
	support.

	* expr.c (emit_move_insn): Add named address space support.
	(expand_expr_addr_expr): Ditto.
	(expand_expr_real_1): Ditto.

	* expr.h (memory_address): Change to a macro passing 0 as the
	named address space.
	(memory_address_addr_space): New declaration.
	(change_address_addr_space): Ditto.

	* recog.c (memory_address_addr_space_p): Like memory_address_p,
	except take a named address space identifier.

	* recog.h (memory_address_addr_space_p): New declaration.
	(strict_memory_address_addr_space_p): Ditto.

	* c-decl.c (toplevel): Include target.h.
	(diagnose_mismatched_decls): Add named address space support.
	(shadow_tag_warned): Ditto.
	(quals_from_declspecs): Ditto.
	(start_decl): Ditto.
	(grokdeclarator): Ditto.
	(build_null_declspecs): Ditto.
	(declspecs_add_addrspace): New function to change the address
	space in the declspecs.

	* c-pretty-print.c (toplevel): Include target.h and target-def.h.
	(pp_c_space_for_pointer_operator): Add named address space
	support.
	(pp_c_type_qualifier_list): Ditto.

	* langhooks.c (lhd_tree_dump_dump_tree): Convert t to const_tree.

	* print-rtl.c (print_rtx): Add named address space support.

	* stor-layout.c (layout_type): Set precision for pointers.

	* c-typeck.c (null_pointer_constant): Add named address space
	support.
	(qualify_type): Ditto.
	(composite_type): Ditto.
	(common_pointer_type): Ditto.
	(comptypes_internal): Ditto.
	(comp_target_types): Ditto.
	(parser_build_binary_op): Ditto.
	(build_conditional_expr): Ditto.
	(build_c_cast): Ditto.
	(convert_for_assignment): Ditto.
	(store_init_value): Ditto.
	(maybe_warn_string_init): Ditto.
	(digest_init): Ditto.
	(output_init_element): Ditto.
	(build_binary_op): Ditto.
	(digest_init_addr_space_ok_p): New function to determine if it is
	ok to initialize an element in a named address space.

	* coretypes.h (addr_space_t): New type for named address spaces.

	* emit-rtl.c (toplevel): Include target.h.
	(mem_attrs_htab_hash): Add named address space support.
	(mem_attrs_htab_eq): Ditto.
	(get_mem_attrs): Ditto.
	(set_mem_attributes_minus_bitpos): Ditto.
	(set_mem_attrs_from_reg): Ditto.
	(set_mem_alias_set): Ditto.
	(set_mem_align): Ditto.
	(set_mem_expr): Ditto.
	(set_mem_offset): Ditto.
	(set_mem_size): Ditto.
	(change_address_1): Ditto.
	(adjust_address_1): Ditto.
	(adjust_automodify_address_1): Ditto.
	(offset_address): Ditto.
	(replace_equiv_address): Ditto.
	(widen_memoy_address): Ditto.
	(get_spill_slot_decl): Ditto.
	(set_mem_attrs_for_spill): Ditto.
	(set_mem_addr_space): New function to set the address space.
	(change_address_addr_space): New function modified from
	change_address to add address space argument.
	(change_address): Call change_address_addr_space with the current
	address space.

	* emit-rtl.h (set_mem_addr_space): Add declaration.

	* explow.c (break_out_memory_refs): Deal with pointers that can be
	different sizes due to named address space support.
	(memory_address_addr_space): New function, like memory_address,
	except add an explicit named address space.
	(memory_address_addr_space): New function, like memory_address
	except it takes a named address space identifier.
	(memory_address): Add support for addresses in a different named
	address space.
	(validize_mem): Ditto.

	* print-tree (print_node_brief): Print out named address space
	information if it isn't the default address space.
	(print_node): Ditto.

	* tree-ssa-forwprop.c (forward_propigate_addr_expr_1): Don't
	propigate named address space conversions.

	* varasm.c (make_decl_rtl): Add named address space support.
	(default_valid_pointer_mode): Move to targhooks.c.

	* tree-ssa.c (useless_type_conversion_p_1): Add named address
	space support.
	(useless_type_conversion_p): Ditto.

	* target-def.h (TARGET_ADDR_SPACE_POINTER_MODE): Add new hook for
	named address space support.
	(TARGET_ADDR_SPACE_MINUS_TYPE): Ditto.
	(TARGET_ADDR_SPACE_NAME): Ditto.
	(TARGET_ADDR_SPACE_MEMORY_ADDRESS_P): Ditto.
	(TARGET_ADDR_SPACE_STRICT_MEMORY_ADDRESS_P): Ditto.
	(TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS): Ditto.
	(TARGET_ADDR_SPACE_CAN_CONVERT_P): Ditto.
	(TARGET_ADDR_SPACE_NOP_CONVERT_P): Ditto.
	(TARGET_ADDR_SPACE_SUBSET_P): Ditto.
	(TARGET_ADDR_SPACE_CONVERT): Ditto.
	(TARGET_ADDR_SPACE_SECTION_NAME): Ditto.
	(TARGET_ADDR_SPACE_STATIC_INIT_OK_P): Ditto.
	(TARGET_ADDR_SPACE_HOOKS): Group all named address space hooks
	together.
	(TARGET_INITIALIZER): Add named address space hooks.

	* rtl.h (struct mem_attrs): Add named address space field.  Move
	align field up higher.
	(MEM_ADDR_SPACE): New accessor macro for named address space.

	* output.h (defalt_addr_space_pointer_mode): Add declaration.

	* c-common.c (c_common_reswords): If TARGET_ADDR_SPACE_KEYWORDS is
	defined, add the named address space keywords.
	(complete_array_type): Add named address space support.

	* c-common.h (enum rid): Add support for 16 named address space
	keywords.
	(ADDR_SPACE_KEYWORD): Macro for TARGET_ADDR_SPACE_KEYWORDS to use
	to define each keyword.

	* config.gcc (spu-*-elf*): Add spu_cache.h to extra_headers.

	* Makefile.in (c-decl.o): Add targhooks.h dependency.
	(c-pretty-print.o): Add $(TARGET_DEF_H) and $(TARGET_H)
	dependency.
	(convert.o): Add $(TARGET_H) dependency.
	(tree-pretty-print.o): Ditto.
	(fold-const.o): Ditto.
	(emit-rtl.o): Ditto.
	(auto-inc-dec.o): Ditto.

	* c-parser.c (c_parse_init): Add assertion to make sure RID
	keywords fit in a byte.
	(enum c_id_kind): Add C_ID_ADDRSPACE.
	(c_lex_one_token): Add named address space support.
	(c_token_starts_typename): Ditto.
	(c_token_starts_declspecs): Ditto.
	(c_parser_asm_definition): Ditto.
	(c_parser_declspecs): Ditto.
	(c_parser_postfix_expression_after_paren_type): Ditto.

	* config/spu/spu_cache.h: New __ea support file.
	* config/spu/cachemgr.c: Ditto.
	* config/spu/cache.S: Ditto.

	* config/spu/spu-protos.h (spu_legimitize_address): Add named
	address field to calling signature.

	* config/spu/spu.c (EAmode): Mode to use for __ea pointers, based
	on -mea32/-mea64.
	(TARGET_ADDR_SPACE_POINTER_MODE): Define named address hook.
	(TARGET_ADDR_SPACE_MINUS_TYPE): Ditto.
	(TARGET_ADDR_SPACE_MEMORY_ADDRESS_P): Ditto.
	(TARGET_ADDR_SPACE_STRICT_MEMORY_ADDRESS_P): Ditto.
	(TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS): Ditto.
	(TARGET_ADDR_SPACE_CAN_CONVERT_P): Ditto.
	(TARGET_ADDR_SPACE_NOP_CONVERT_P): Ditto.
	(TARGET_ADDR_SPACE_SUBSET_P): Ditto.
	(TARGET_ADDR_SPACE_CONVERT): Ditto.
	(TARGET_ADDR_SPACE_SECTION_NAME): Ditto.
	(TARGET_ADDR_SPACE_STATIC_INIT_OK_P): Ditto.
	(TARGET_SECTION_TYPE_FLAGS): Ditto.
	(TARGET_VALID_POINTER_MODE): Ditto.
	(TARGET_ASM_UNALGINED_DI_OP): Define to be .quad/.long to work
	around assembler limitations on @ppu declarations.
	(TARGET_ASM_UNALIGNED_SI_OP): Ditto.
	(ea_symbol_ref): New function to return true if a SYMBOL_REF is in
	the __ea named address space.
	(spu_legitimate_constant_p): Reject __ea symbols.
	(spu_legitimate_address): Take address space field, and restrict
	__ea addresses.
	(spu_legitimize_address): Take address space field, and don't do
	anything for __ea addresses.
	(cache_fetch): New static to hold SYMBOL_REF of __cache_fetch
	function.
	(cache_fetch_dirty): New static to hold SYMBOL_REF of
	__cache_fetch_dirty function.
	(ea_alias_set): New static to hold __ea alias set.
	(ea_load_store): New function to call __ea cache functions as out
	of line calls.
	(ea_load_store_inline): New function to call __ea cache function
	as inline code.
	(expand_ea_mem): Expand references to __ea memory.
	(spu_expand_mov): Add support for __ea address space.
	(spu_valid_move): Add assertion to make sure we are in the context
	of a function and not a static initializer, preventing a segfault.
	(spu_valid_pointer_mode): New function to return true for the
	various modes pointers can be.
	(spu_section_type_flags): New function, set special flags for the
	__ea section.
	(spu_addr_space_pointer_mode): New target hook, return the
	appropriate mode for generic and __ea named address spaces.
	(spu_addr_space_minus_type): New target hook, return the
	appropriate size for subtraction of two pointers.
	(spu_addr_space_name): New target hook to convert a named address
	space id into a string.
	(spu_addr_space_memory_address_p): New target hook to validate a
	memory address before register allocation.
	(spu_addr_space_strict_memory_address_p): New target hook to
	validate a memory address after register allocation.
	(spu_addr_space_can_convert_p): New target hook to determine if
	you can convert pointers from one named address space to another.
	(spu_addr_space_nop_convert_p): New target hook to determin if
	converting one named address space to another is a NOP.
	(spu_addr_space_subset_p): New target hook to determine if one
	named address space pointer is a subset of a pointer to a
	different named address space.
	(spu_addr_space_convert): New target hook to convert one named
	address pointer to another pointer in a different named address
	space.
	(spu_ea_name): New static to hold "._ea" as a string node.
	(spu_addr_space_section_name): New target hook to return the
	section name for a named address space.
	(spu_no_relocation): New function to determine if an
	intiialization expression contains relocation and can't be allowed
	in __ea memory.
	(spu_addr_space_static_init_ok_p): New target hook to determine if
	it is ok to initialize a value in a named address space or that
	points to a named address space.
	(toplevel): Include gt-spu.h for GTY static variables.

	* config/spu/spu.h (GO_IF_LEGITIMATE_ADDRESS): Update
	spu_legitimate_address call.
	(LEGITIMIZE_ADDRESS): Update spu_legitimize_address call.
	(TEXT_SECTION_ASM_OP): Put a tab in front of the directive.
	(DATA_SECTION_ASM_OP): Ditto.
	(ASM_OUTPUT_SYMBOL_REF): If the symbol ref is in the __ea address
	space, add @ppu suffix.
	(ADDR_SPACE_GENERIC): New macro for generic address space.
	(ADDR_SPACE_EA): New macro for __ea address space.
	(ADDR_SPACE_BAD): New macro that isn't a valid address space.
	(TARGET_ADDR_SPACE_KEYWORDS): New macro to define the __ea
	keyword.

	* config/spu/spu-elf.h (DRIVER_SELF_SPECS): Add support for
	-mcache-size=, -matomic-updates switches.
	(LIB_SPEC): Ditto.

	* config/spu/spu.md (to_ea): New expanders for __ea named address
	space support.
	(from_ea): Ditto.

	* config/spu/spu-c.c (spu_cpu_cpp_builtins): Define __EA32__ or
	__EA64__.

	* config/spu/spu.opt (-mea32): New switch.
	(-mea64): Ditto.
	(-mno-ea-to-generic-conversion): Ditto.
	(-mea-to-generic-conversion): Ditto.
	(-mno-address-space-conversion): Ditto.
	(-maddress-space-conversion): Ditto.

	* config/spu/t-spu-elf (MULTILIB_OPTIONS): Add -mea64 multilib.
	(EXTRA_MULTILIB_PARTS): Add libgcc_cachemgr.a,
	libgcc_cachemgr_nonatomic.a, libgcc_cache8k.a, libgcc_cache16k.a,
	libgcc_cache32k.a, libgcc_cache64k.a, libgcc_cache128k.a.
	(cachemgr.o, %/cachemgr.o): New targets.
	(cachemgr_nonatomic.o, %/cachemgr_nonatomic.o): Likewise.
	(libgcc_%.a, %/libgcc_%.a): Likewise.
	(cache8k.o, cache16k.o, cache32k.o, cache64k.o, cache128k.o,
	%/cache8k.o, %/cache16k.o, %/cache32k.o, %/cache64k.o,
	%/cache128k.o): Likewise.

	* convert.c (convert_to_pointer): Add named address space support.
	(convert_to_integer): Ditto.

[gcc/cp changes]
2009-01-13  Ben Elliston  <bje@au.ibm.com>
	    Michael Meissner  <meissner@linux.vnet.ibm.com>

	* typeck.c (cp_type_quals): Convert argument to const_tree.

[gcc/testsuite changes]
2009-01-13  Ben Elliston  <bje@au.ibm.com>
	    Michael Meissner  <meissner@linux.vnet.ibm.com>

	* testsuite/gcc.target/spu/ea/cache-common.h: New file for named
	address space support.
	* testsuite/gcc.target/spu/ea/errors2.c: Ditto.
	* testsuite/gcc.target/spu/ea/ea.exp: Ditto.
	* testsuite/gcc.target/spu/ea/errors3.c: Ditto.
	* testsuite/gcc.target/spu/ea/errors4.c: Ditto.
	* testsuite/gcc.target/spu/ea/cpudefine32.c: Ditto.
	* testsuite/gcc.target/spu/ea/cppdefine64.c: Ditto.
	* testsuite/gcc.target/spu/ea/cache32.c: Ditto.
	* testsuite/gcc.target/spu/ea/test-sizes.c: Ditto.
	* testsuite/gcc.target/spu/ea/compile2.c: Ditto.
	* testsuite/gcc.target/spu/ea/cast1.c: Ditto.
	* testsuite/gcc.target/spu/ea/compile3.c: Ditto.
	* testsuite/gcc.target/spu/ea/errors.c: Ditto.
	* testsuite/gcc.target/spu/ea/options1.c: Ditto.
	* testsuite/gcc.target/spu/ea/compile4.c: Ditto.
	* testsuite/gcc.target/spu/ea/cache64.c: Ditto.
	* testsuite/gcc.target/spu/ea/execute1.c: Ditto.
	* testsuite/gcc.target/spu/ea/execute2.c: Ditto.
	* testsuite/gcc.target/spu/ea/execute3.c: Ditto.
	* testsuite/gcc.target/spu/ea/execute1-m64.c: Ditto.
	* testsuite/gcc.target/spu/ea/compile.c: Ditto.
	* testsuite/gcc.target/spu/ea/execute2-m64.c: Ditto.
	* testsuite/gcc.target/spu/ea/execute3-m64.c: Ditto.

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/doc/extend.texi	(working copy)
@@ -37,6 +37,7 @@ extensions, accepted by GCC in C89 mode 
 * Decimal Float::       Decimal Floating Types. 
 * Hex Floats::          Hexadecimal floating-point constants.
 * Fixed-Point::         Fixed-Point Types.
+* Named Address Spaces::Named address spaces.
 * Zero Length::         Zero-length arrays.
 * Variable Length::     Arrays whose length is computed at run time.
 * Empty Structures::    Structures with no members.
@@ -1119,6 +1120,31 @@ Pragmas to control overflow and rounding
 
 Fixed-point types are supported by the DWARF2 debug information format.
 
+@node Named Address Spaces
+@section Named address spaces
+@cindex named address spaces
+
+As an extension, the GNU C compiler supports named address spaces as
+defined in the N1275 draft of ISO/IEC DTR 18037.  Support for named
+address spaces in GCC will evolve as the draft technical report changes.
+Calling conventions for any target might also change.  At present, only
+the SPU target supports other address spaces.  On the SPU target, for
+example, variables may be declared as belonging to another address space
+by qualifying the type with the @code{__ea} address space identifier:
+
+@smallexample
+extern int __ea i;
+@end smallexample
+
+When the variable @code{i} is accessed, the compiler will generate
+special code to access this variable.  It may use runtime library
+support, or generate special machine instructions to access that address
+space.
+
+The @code{__ea} identifier may be used exactly like any other C type
+qualifier (e.g., @code{const} or @code{volatile}).  See the N1275
+document for more details.
+
 @node Zero Length
 @section Arrays of Length Zero
 @cindex arrays of length zero
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/doc/tm.texi	(working copy)
@@ -54,6 +54,7 @@ through the macros defined in the @file{
 * MIPS Coprocessors::   MIPS coprocessor support and how to customize it.
 * PCH Target::          Validity checking for precompiled headers.
 * C++ ABI::             Controlling C++ ABI changes.
+* Named Address Spaces:: Adding support for named address spaces
 * Misc::                Everything else.
 @end menu
 
@@ -9604,6 +9605,127 @@ defined.  Use this hook to make adjustme
 visibility or perform any other required target modifications).
 @end deftypefn
 
+@node Named Address Spaces
+@section Adding support for named address spaces
+@cindex named address spaces
+
+The draft technical report of the ISO/IEC JTC1 S22 WG14 N1169
+standards committee, @cite{Programming Languages - C - Extensions to
+support embedded processors}, specifies a syntax for embedded
+processors to specify alternate address spaces.  You can configure a
+GCC port to support section 5.1 of the draft report to add support for
+address spaces other than the default address space.  These address
+spaces are new keywords that are similar to the @code{volatile} and
+@code{const} type attributes.
+
+Named address pointers can be a different size than native pointers.
+
+For example, the SPU port uses the @code{__ea} address space to refer
+to memory in the host processor, rather than memory local to the SPU
+processor.  Access to memory in the @code{__ea} address space involves
+making calls to move the memory to/from the host processor to the
+local processor memory address space.  Pointers in the @code{__ea}
+address space are either 32 bits or 64 bits based on the
+@option{-mea32} or @option{-mea64} switches (native SPU pointers are
+always 32 bits).
+
+Internally, address spaces are represented as a small integer in the
+range 0 to 15 with address space 0 being reserved for the generic
+address space.
+
+@deftypefn {Target Hook} {enum machine_mode} TARGET_ADDR_SPACE_POINTER_MODE (addr_space_t @var{address_space})
+Define this to return a pointer mode for a given @var{address_space} if
+the target supports named address spaces.  The default version of this
+hook returns @code{ptr_mode} for the generic address space only.
+@end deftypefn
+
+@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} {tree} TARGET_ADDR_SPACE_MINUS_TYPE (addr_space_t @var{asl}, addr_space_t @var{asr})
+Define this to return the @code{tree} type to use for the subtraction
+of two pointers to named address spaces (@var{asl} and @var{asr}).
+The default version of this hook returns @code{ptrdiff_type}.
+@end deftypefn
+
+@deftypefn {Target Hook} {const char *} TARGET_ADDR_SPACE_NAME (addr_space_t @var{address_space})
+Define this to return a string that describes the @var{address_space}.
+As this hook should never be called for targets that do not support
+named address spaces, the default version of this hook will cause the
+compiler to abort.
+@end deftypefn
+
+@deftypefn {Target Hook} {bool} TARGET_ADDR_SPACE_MEMORY_ADDRESS_P (enum machine_mode @var{mode}, rtx @var{exp}, addr_space_t @var{as})
+Define this to return true if @var{exp} is a valid address for mode
+@var{mode} in the named address space @var{as}.  Valid address can
+contain references to psuedo registers that are not yet assigned to
+hard registers.
+@end deftypefn
+
+@deftypefn {Target Hook} {bool} TARGET_ADDR_SPACE_STRICT_MEMORY_ADDRESS_P (enum machine_mode @var{mode}, rtx @var{exp}, addr_space_t @var{as})
+Define this to return true if @var{exp} is a valid address for mode
+@var{mode} in the named address space @var{as}.  Valid address can
+only contain references to hard registers.  Any address with a pseudo
+register should return false.
+@end deftypefn
+
+@deftypefn {Target Hook} {rtx} TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS (rtx @var{x}, rtx @var{oldx}, enum machine_mode @var{mode}, addr_space_t @var{as})
+Define this to modify an invalid address @var{x} to be a valid address
+with mode @var{mode} in the named address space @var{as}.  This hook
+is similar to the @code{LEGITIMIZE_ADDRESS} macro, except that it
+includes explicit named address space support.
+@end deftypefn
+
+@deftypefn {Target Hook} {bool} TARGET_ADDR_SPACE_CAN_CONVERT_P (addr_space_t @var{from}, addr_space_t @var{to})
+Define this to return whether a pointer which points to the @var{from}
+named address space can be converted to a pointer which points to the
+@var{to} named address space.
+@end deftypefn
+
+@deftypefn {Target Hook} {bool} TARGET_ADDR_SPACE_NOP_CONVERT_P (addr_space_t @var{from}, addr_space_t @var{to})
+Define this to return whether converting a pointer which points to the
+@var{from} named address space to a pointer which points to the
+@var{to} named address space can be done as a simple copy or if a real
+conversion needs to be done.
+@end deftypefn
+
+@deftypefn {Target Hook} {bool} TARGET_ADDR_SPACE_SUBSET_P (addr_space_t @var{superset}, addr_space_t @var{subset})
+Define this to return the @var{subset} named address space is
+contained within the @var{superset} named address space.
+@end deftypefn
+
+@deftypefn {Target Hook} {rtx} TARGET_ADDR_SPACE_CONVERT (rtx @var{op}, enum machine_mode @var{mode}, addr_space_t @var{from}, addr_space_t @var{to})
+Define this to convert the pointer expression represented by the RTL
+@var{op} that points to the named address space @var{from} to a new
+pointer expression with type @var{mode} in the named address space
+@var{to}.  As this hook should never be called for targets that do not
+support named address spaces, the default version of this hook will
+cause the compiler to abort.
+@end deftypefn
+
+@deftypefn {Target Hook} {tree} TARGET_ADDR_SPACE_SECTION_NAME (addr_space_t @var{address_space})
+Define this to return the section name to put static and global
+variables
+@end deftypefn
+
+@deftypefn {Target Hook} {bool} TARGET_ADDR_SPACE_STATIC_INIT_OK_P (tree @var{type}, tree @var{init}, addr_space_t @var{as_var}, addr_space_t @var{as_init})
+Define this to return whether a static initialization of the type
+@var{type} should be allowed for the expression @var{init} to be
+stored in the @var{as_var} named address space.  If @var{init} is a
+pointer or reference, @var{as_init} describes the named address space
+that the pointer points to.
+@end deftypefn
+
 @node Misc
 @section Miscellaneous Parameters
 @cindex parameters, miscellaneous
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/doc/invoke.texi	(working copy)
@@ -797,7 +797,12 @@ See RS/6000 and PowerPC Options.
 -msafe-dma -munsafe-dma @gol
 -mbranch-hints @gol
 -msmall-mem -mlarge-mem -mstdmain @gol
--mfixed-range=@var{register-range}}
+-mfixed-range=@var{register-range} @gol
+-mea32 -mea64 @gol
+-mcache-size=@var{cache-size} @gol
+-mea-to-generic-conversion -mno-ea-to-generic-conversion @gol
+-maddress-space-conversion -maddress-space-conversion @gol
+-matomic-updates -mno-atomic-updates}
 
 @emph{System V Options}
 @gccoptlist{-Qy  -Qn  -YP,@var{paths}  -Ym,@var{dir}}
@@ -15013,6 +15018,52 @@ useful when compiling kernel code.  A re
 two registers separated by a dash.  Multiple register ranges can be
 specified separated by a comma.
 
+@item -mea32
+@itemx -mea64
+@opindex mea32
+@opindex mea64
+
+Compile code assuming that pointers to the @code{__ea} address space are
+either 32 or 64 bits wide. The default is 32 bits.  The @code{__ea}
+address space qualifier specifies that variables reside in the PPU
+address space.  As this is an ABI changing option, all object code in an
+executable must be compiled with the same option.
+
+@item -mea-to-generic-conversion
+@itemx -mno-ea-to-generic-conversion
+@opindex mea-to-generic-conversion
+@opindex mno-ea-to-generic-conversion
+
+Allow/disallow pointers to the @code{__ea} address space to be
+converted local pointers.
+
+@item -maddress-space-conversion
+@itemx -mno-address-space-conversion
+@opindex maddress-space-conversion
+@opindex mno-address-space-conversion
+
+Allow/disallow automatically converting pointers to different named
+address spaces (@code{__ea} and generic) to the other address space.
+
+@item -mcache-size=@var{cache-size}
+@opindex mcache-size
+
+This option controls the version of libgcc that the compiler links to an
+executable and selects a software-managed cache for accessing variables
+in the PPU address space with a particular cache size.  Possible options
+for @var{cache-size} are @samp{8}, @samp{16}, @samp{32}, @samp{64} and
+@samp{128}.  The default cache size is 64KB.
+
+@item -matomic-updates
+@itemx -mno-atomic-updates
+@opindex matomic-updates
+@opindex mno-atomic-updates
+
+This option controls the version of libgcc that the compiler links to an
+executable and selects whether atomic updates to the software-managed
+cache of PPU-side variables are used.  The default behavior is to use
+atomic updates.
+
 @item -mdual-nops
 @itemx -mdual-nops=@var{n}
 @opindex mdual-nops
Index: gcc/doc/rtl.texi
===================================================================
--- gcc/doc/rtl.texi	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/doc/rtl.texi	(working copy)
@@ -420,6 +420,11 @@ the size is implied by the mode.
 @findex MEM_ALIGN
 @item MEM_ALIGN (@var{x})
 The known alignment in bits of the memory reference.
+
+@findex MEM_ADDR_SPACE
+@item MEM_ADDR_SPACE (@var{x})
+The address space of the memory reference.  This will commonly be zero
+for the generic address space.
 @end table
 
 @item REG
Index: gcc/testsuite/gcc.target/spu/ea/errors2.c
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/errors2.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/errors2.c	(revision 143347)
@@ -0,0 +1,87 @@
+/* Invalid conversions of __ea pointers to local pointers.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -std=gnu99 -pedantic-errors -mno-ea-to-generic-conversion" } */
+
+/* This is the same code as compile2.c but it should generate errors.  If you
+   modify this file, you should modify errors2.c as well.  */
+#ifndef TYPE
+#define TYPE void
+#endif
+
+typedef __ea TYPE *ea_ptr_t;
+typedef      TYPE *lm_ptr_t;
+
+extern ea_ptr_t ea_ptr;
+extern lm_ptr_t lm_ptr;
+
+extern void arg_ea (ea_ptr_t);
+extern void arg_lm (lm_ptr_t);
+
+#ifdef NO_CAST
+#define EA_CAST(ARG) (ARG)
+#define LM_CAST(ARG) (ARG)
+
+#else
+#define EA_CAST(ARG) ((ea_ptr_t)(ARG))
+#define LM_CAST(ARG) ((lm_ptr_t)(ARG))
+#endif
+
+void ea_to_ea_arg (void)
+{
+  arg_ea (ea_ptr);
+}
+
+void ea_to_lm_arg (void)
+{
+  arg_lm (LM_CAST (ea_ptr));	/* { dg-error "cast to generic address space pointer from __ea address space pointer" } */
+}
+
+void lm_to_ea_arg (void)
+{
+  arg_ea (EA_CAST (lm_ptr));
+}
+
+void lm_to_lm_arg (void)
+{
+  arg_lm (lm_ptr);
+}
+
+ea_ptr_t ea_to_ea_ret (void)
+{
+  return ea_ptr;
+}
+
+lm_ptr_t ea_to_lm_ret (void)
+{
+  return LM_CAST (ea_ptr);	/* { dg-error "cast to generic address space pointer from __ea address space pointer" } */
+}
+
+ea_ptr_t lm_to_ea_ret (void)
+{
+  return EA_CAST (lm_ptr);
+}
+
+lm_ptr_t lm_to_lm_ret (void)
+{
+  return lm_ptr;
+}
+
+void ea_to_ea_store (ea_ptr_t ptr)
+{
+  ea_ptr = ptr;
+}
+
+void ea_to_lm_store (ea_ptr_t ptr)
+{
+  lm_ptr = LM_CAST (ptr);	/* { dg-error "cast to generic address space pointer from __ea address space pointer" } */
+}
+
+void lm_to_ea_store (lm_ptr_t ptr)
+{
+  ea_ptr = EA_CAST (ptr);
+}
+
+void lm_to_lm_store (lm_ptr_t ptr)
+{
+  lm_ptr = ptr;
+}
Index: gcc/testsuite/gcc.target/spu/ea/cache-common.h
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/cache-common.h	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/cache-common.h	(revision 143347)
@@ -0,0 +1,201 @@
+#include <stdlib.h>
+#include <string.h>
+#include <spu_cache.h>
+extern void *malloc (__SIZE_TYPE__);
+extern void *memset (void *, int, __SIZE_TYPE__);
+extern void abort (void);
+
+#ifdef __EA64__
+#define addr unsigned long long
+#else
+#define addr unsigned long
+#endif
+
+#ifdef __EA64__
+#define malloc_ea __malloc_ea64
+#define memset_ea __memset_ea64
+#define memcpy_ea __memcpy_ea64
+
+typedef unsigned long long size_ea_t;
+
+__ea void *__malloc_ea64 (size_ea_t);
+__ea void *__memset_ea64 (__ea void *, int, size_ea_t);
+__ea void *__memcpy_ea64 (__ea void *, __ea const void *, size_ea_t);
+#define LINE_SIZE 128LL
+#else
+#define malloc_ea __malloc_ea32
+#define memset_ea __memset_ea32
+#define memcpy_ea __memcpy_ea32
+
+typedef unsigned long size_ea_t;
+
+__ea void *__malloc_ea32 (size_ea_t size);
+__ea void *__memset_ea32 (__ea void *, int, size_ea_t);
+__ea void *__memcpy_ea32 (__ea void *, __ea const void *, size_ea_t);
+#define LINE_SIZE 128
+#endif
+
+static __ea void *bigblock;
+static __ea void *block;
+static int *ls_block;
+
+extern void __cache_tag_array_size;
+#define CACHE_SIZE (4 * (int) &__cache_tag_array_size)
+
+void
+init_mem (void)
+{
+  bigblock = malloc_ea (CACHE_SIZE + 2 * LINE_SIZE);
+  block = malloc_ea (2 * LINE_SIZE);
+  ls_block = malloc (LINE_SIZE);
+
+  memset_ea (bigblock, 0, CACHE_SIZE + 2 * LINE_SIZE);
+  memset_ea (block, -1, 2 * LINE_SIZE);
+  memset (ls_block, -1, LINE_SIZE);
+  cache_flush ();
+}
+
+/* Test 1: Simple cache fetching.  */
+void
+test1 (void)
+{
+  addr aligned = ((((addr) block) + LINE_SIZE - 1) & -LINE_SIZE);
+  int *p1 = NULL;
+  int *p2 = NULL;
+  int i = 0;
+
+  /* First, check if the same addr give the same cache ptr.  */
+  p1 = cache_fetch ((__ea void *) aligned);
+  p2 = cache_fetch ((__ea void *) aligned);
+
+  if (p1 != p2)
+    abort ();
+
+  /* Check that the data actually is in the cache. */
+  for (i = 0; i < LINE_SIZE / sizeof (int); i++)
+    {
+      if (p1[i] != -1)
+	abort ();
+    }
+
+  /* Check returning within the cache line. */
+  p2 = cache_fetch ((__ea void *) (aligned + sizeof (int)));
+
+  if (p2 - p1 != 1)
+    abort ();
+
+  /* Finally, check that fetching an LS pointer returns that pointer.  */
+  p1 = cache_fetch ((__ea char *) ls_block);
+  if (p1 != ls_block)
+    abort ();
+}
+
+/* Test 2: Eviction testing. */
+void
+test2 (void)
+{
+  addr aligned = ((((addr) block) + LINE_SIZE - 1) & -LINE_SIZE);
+  int *p = NULL;
+  int i = 0;
+
+  /* First check that clean evictions don't write back.  */
+  p = cache_fetch ((__ea void *) aligned);
+  for (i = 0; i < LINE_SIZE / sizeof (int); i++)
+    p[i] = 0;
+
+  cache_evict ((__ea void *) aligned);
+  memcpy_ea ((__ea char *) ls_block, (__ea void *) aligned, LINE_SIZE);
+
+  for (i = 0; i < LINE_SIZE / sizeof (int); i++)
+    {
+      if (ls_block[i] == 0)
+	abort ();
+    }
+
+  /* Now check that dirty evictions do write back.  */
+  p = cache_fetch_dirty ((__ea void *) aligned, LINE_SIZE);
+  for (i = 0; i < LINE_SIZE / sizeof (int); i++)
+    p[i] = 0;
+
+  cache_evict ((__ea void *) aligned);
+  memcpy_ea ((__ea char *) ls_block, (__ea void *) aligned, LINE_SIZE);
+
+  for (i = 0; i < LINE_SIZE / sizeof (int); i++)
+    {
+      if (ls_block[i] != 0)
+	abort ();
+    }
+
+  /* Finally, check that non-atomic writeback only writes dirty bytes.  */
+
+  for (i = 0; i < LINE_SIZE / sizeof (int); i++)
+    {
+      p = cache_fetch_dirty ((__ea void *) (aligned + i * sizeof (int)),
+			     (i % 2) * sizeof (int));
+      p[0] = -1;
+    }
+
+  cache_evict ((__ea void *) aligned);
+  memcpy_ea ((__ea char *) ls_block, (__ea void *) aligned, LINE_SIZE);
+
+  for (i = 0; i < LINE_SIZE / sizeof (int); i++)
+    {
+      if ((ls_block[i] == -1) && (i % 2 == 0))
+	abort ();
+      if ((ls_block[i] == 0) && (i % 2 == 1))
+	abort ();
+    }
+}
+
+/* Test LS forced-eviction. */
+void
+test3 (void)
+{
+  addr aligned = ((((addr) bigblock) + LINE_SIZE - 1) & -LINE_SIZE);
+  char *test = NULL;
+  char *ls = NULL;
+  int i = 0;
+
+  /* Init memory, fill the cache to capacity.  */
+  ls = cache_fetch_dirty ((__ea void *) aligned, LINE_SIZE);
+  for (i = 1; i < (CACHE_SIZE / LINE_SIZE); i++)
+    cache_fetch_dirty ((__ea void *) (aligned + i * LINE_SIZE), LINE_SIZE);
+
+  memset (ls, -1, LINE_SIZE);
+  test = cache_fetch ((__ea void *) (aligned + CACHE_SIZE));
+
+  /* test == ls indicates cache collision.  */
+  if (test != ls)
+    abort ();
+
+  /* Make sure it actually wrote the cache line.  */
+  for (i = 0; i < LINE_SIZE; i++)
+    {
+      if (ls[i] != 0)
+	abort ();
+    }
+
+  ls = cache_fetch ((__ea void *) aligned);
+
+  /* test != ls indicates another entry was evicted.  */
+  if (test == ls)
+    abort ();
+
+  /* Make sure that the previous eviction actually wrote back.  */
+  for (i = 0; i < LINE_SIZE; i++)
+    {
+      if (ls[i] != 0xFF)
+	abort ();
+    }
+}
+
+int
+main (int argc, char **argv)
+{
+  init_mem ();
+  test1 ();
+  test2 ();
+  test3 ();
+
+  return 0;
+}
Index: gcc/testsuite/gcc.target/spu/ea/errors3.c
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/errors3.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/errors3.c	(revision 143347)
@@ -0,0 +1,53 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -std=gnu99 -pedantic-errors -mno-address-space-conversion" } */
+
+/* This is the same as compile3.c except it should generate errors where
+   pointers are mixed.  If you modify this code, please modify compile3.c as
+   well.  */
+
+#define __lm
+
+__ea int ea_var = 1;
+__lm int lm_var = 2;
+
+typedef __ea int *ea_ptr_t;
+typedef __lm int *lm_ptr_t;
+
+typedef __ea char *ea_cptr_t;
+typedef __lm char *lm_cptr_t;
+
+ea_ptr_t ea, ea2;
+lm_ptr_t lm, lm2;
+
+extern void call_ea (ea_ptr_t);
+extern void call_lm (lm_ptr_t);
+
+/* Errors should be generated here.  */
+void to_ea (void) { ea = lm; }				/* { dg-error "assignment to a pointer to an incompatible address space" } */
+void to_lm (void) { lm = ea; }				/* { dg-error "assignment to a pointer to an incompatible address space" } */
+ea_ptr_t ret_ea (void) { return lm; }			/* { dg-error "return of a pointer to an incompatible address space" } */
+lm_ptr_t ret_lm (void) { return ea; }			/* { dg-error "return of a pointer to an incompatible address space" } */
+void call_ea2 (void) { call_ea (lm); }			/* { dg-error "passing argument 1 of 'call_ea' is a pointer to an incompatible address space" } */
+void call_lm2 (void) { call_lm (ea); }			/* { dg-error "passing argument 1 of 'call_lm' is a pointer to an incompatible address space" } */
+int sub_ea (void) { return ea - lm; }			/* { dg-error "invalid operands to binary -" } */
+int sub_lm (void) { return lm - ea; }			/* { dg-error "invalid operands to binary -" } */
+int if_ea (int test) { return *((test) ? ea : lm); }	/* { dg-error "pointers to incompatible address spaces used in conditional expression" } */
+int if_lm (int test) { return *((test) ? lm : ea); }	/* { dg-error "pointers to incompatible address spaces used in conditional expression" } */
+
+/* No errors here.  */
+void to_ea2 (void) { ea = ea2; }
+void to_lm2 (void) { lm = lm2; }
+
+void to_ea_with_cast (void) { ea = (ea_ptr_t)lm; }
+void to_lm_with_cast (void) { lm = (lm_ptr_t)ea; }
+ea_ptr_t ret_ea_with_cast (void) { return (ea_ptr_t)lm; }
+lm_ptr_t ret_lm_with_cast (void) { return (lm_ptr_t)ea; }
+void call_ea2_with_cast (void) { call_ea ((ea_ptr_t)lm); }
+void call_lm2_with_cast (void) { call_lm ((lm_ptr_t)ea); }
+int sub_ea_with_cast (void) { return ea - (ea_ptr_t)lm; }
+int sub_lm_with_cast (void) { return lm - (lm_ptr_t)ea; }
+int if_ea_with_cast (int test) { return *((test) ? ea : (ea_ptr_t)lm); }
+int if_lm_with_cast (int test) { return *((test) ? lm : (lm_ptr_t)ea); }
+
+void void_ea (void) { ea = (void *)0; }
+void void_lm (void) { lm = (__ea void *)0; }
Index: gcc/testsuite/gcc.target/spu/ea/ea.exp
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/ea.exp	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/ea.exp	(revision 143347)
@@ -0,0 +1,77 @@
+#   Copyright (C) 2008 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Exit immediately if this isn't a SPU target.
+if { ![istarget spu-*-*] } then {
+  return
+}
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# Return 1 if -mea64 target library functions are available
+proc check_effective_target_ea64 { } {
+    return [check_no_compiler_messages ea64 executable {
+	#include <stdlib.h>
+	#include <string.h>
+	#include <spu_cache.h>
+
+	__ea void *ptr;
+	__ea void *__malloc_ea64 (unsigned long long);
+
+	int main (void)
+	{
+	    ptr = __malloc_ea64 (1024LL);
+	    return 0;
+	}
+    } "-O2 -mea64" ]
+}
+
+# Return 1 if -mea32 target library functions are available
+proc check_effective_target_ea32 { } {
+    return [check_no_compiler_messages ea32 executable {
+	#include <stdlib.h>
+	#include <string.h>
+	#include <spu_cache.h>
+
+	__ea void *ptr;
+	__ea void *__malloc_ea32 (unsigned long);
+
+	int main (void)
+	{
+	    ptr = __malloc_ea32 (1024L);
+	    return 0;
+	}
+    } "-O2 -mea32" ]
+}
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+    set DEFAULT_CFLAGS "-std=gnu89 -pedantic-errors -O2"
+}
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] \
+        "" $DEFAULT_CFLAGS
+
+# All done.
+dg-finish
Index: gcc/testsuite/gcc.target/spu/ea/errors4.c
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/errors4.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/errors4.c	(revision 143347)
@@ -0,0 +1,91 @@
+/* Invalid __ea declarations.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -std=gnu99 -pedantic-errors" } */
+
+__ea char ea_str[] = "abc";
+char lm_str[] = "abc";
+
+__ea char *lm_ea_ptr1 = "abc";				/* { dg-error "initializer element pointing to a named address space" } */
+__ea char *lm_ea_ptr2 = (__ea char *)"abc";		/* { dg-error "initializer element pointing to a named address space" } */
+__ea char *lm_ea_ptr3 = ea_str;				/* { dg-error "initializer element pointing to a named address space" } */
+__ea char *lm_ea_ptr4 = (__ea char *)ea_str;		/* { dg-error "initializer element pointing to a named address space" } */
+__ea char *lm_ea_ptr5 = lm_str;				/* { dg-error "initializer element pointing to a named address space" } */
+__ea char *lm_ea_ptr6 = (__ea char *)lm_str;		/* { dg-error "initializer element pointing to a named address space" } */
+
+__ea char * __ea ea_ea_ptr1 = ea_str;			/* { dg-error "initializer element is not allowed in named address space" } */
+__ea char * __ea ea_ea_ptr2 = (__ea char *)ea_str;	/* { dg-error "initializer element is not allowed in named address space" } */
+
+char * __ea ea_lm_ptr1 = lm_str;			/* { dg-error "initializer element is not allowed in named address space" } */
+char * __ea ea_lm_ptr2 = (char *)lm_str;		/* { dg-error "initializer element is not allowed in named address space" } */
+
+struct foo {
+  int first;
+  __ea char *ptr;
+  int last;
+};
+
+__ea struct foo ea_struct1 = {
+  10,
+  (__ea char *)0,
+  11,
+};
+
+__ea struct foo ea_struct2 = {
+  20,
+  0,
+  21,
+};
+
+struct foo ea_struct3 = {
+  30,
+  ea_str,		/* { dg-error "(initializer element pointing to a named address space)|(near initialization)" "" } */
+  31,
+};
+
+struct foo ea_struct4 = {
+  40,
+  (__ea char *)lm_str,	/* { dg-error "(initializer element pointing to a named address space)|(near initialization)" "" } */
+  41,
+};
+
+struct bar {
+  int first;
+  char *ptr;
+  int last;
+};
+
+__ea struct foo ea_struct5 = {
+  50,
+  0,
+  51,
+};
+
+__ea struct foo ea_struct6 = {
+  60,
+  (char *)0,
+  61,
+};
+
+__ea struct bar ea_struct7 = {
+  70,
+  lm_str,
+  71,
+};		/* { dg-error "(initializer element is not allowed in named address space)|(near initialization)" "" } */
+
+struct bar lm_struct8 = {
+  80,
+  0,
+  81,
+};
+
+struct bar lm_struct9 = {
+  90,
+  (char *)0,
+  91,
+};
+
+struct bar lm_struct10 = {
+  100,
+  lm_str,
+  101,
+};
Index: gcc/testsuite/gcc.target/spu/ea/cppdefine32.c
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/cppdefine32.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/cppdefine32.c	(revision 143347)
@@ -0,0 +1,9 @@
+/* Test default __EA32__ define.  */
+/* { dg-options "-std=gnu89 -pedantic-errors -mea32" } */
+/* { dg-do compile } */
+
+#ifdef __EA32__
+int x;
+#else
+#error __EA32__ undefined
+#endif
Index: gcc/testsuite/gcc.target/spu/ea/cppdefine64.c
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/cppdefine64.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/cppdefine64.c	(revision 143347)
@@ -0,0 +1,8 @@
+/* { dg-options "-std=gnu89 -mea64" } */
+/* { dg-do compile } */
+
+#ifdef __EA64__
+int x;
+#else
+#error __EA64__ undefined
+#endif
Index: gcc/testsuite/gcc.target/spu/ea/cache32.c
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/cache32.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/cache32.c	(revision 143347)
@@ -0,0 +1,26 @@
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+
+   This file is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 2 of the License, or (at your option)
+   any later version.
+
+   This file is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+   for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this file; see the file COPYING.  If not, write to the Free
+   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+/* { dg-do run } */
+/* { dg-require-effective-target "ea32" } */
+/* { dg-options "-mcache-size=8 -O2 -mea32 -g" } */
+
+#ifndef __EA32__
+#error "You must use -mea32 for this test"
+#endif
+
+#include "cache-common.h"
Index: gcc/testsuite/gcc.target/spu/ea/compile2.c
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/compile2.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/compile2.c	(revision 143347)
@@ -0,0 +1,86 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -std=gnu99 -pedantic-errors -mea-to-generic-conversion" } */
+
+/* This is the same code as errors2.c but it should compile cleanly.  If you
+   modify this file, you should modify errors2.c as well.  */
+#ifndef TYPE
+#define TYPE void
+#endif
+
+typedef __ea TYPE *ea_ptr_t;
+typedef      TYPE *lm_ptr_t;
+
+extern ea_ptr_t ea_ptr;
+extern lm_ptr_t lm_ptr;
+
+extern void arg_ea (ea_ptr_t);
+extern void arg_lm (lm_ptr_t);
+
+#ifdef NO_CAST
+#define EA_CAST(ARG) (ARG)
+#define LM_CAST(ARG) (ARG)
+
+#else
+#define EA_CAST(ARG) ((ea_ptr_t)(ARG))
+#define LM_CAST(ARG) ((lm_ptr_t)(ARG))
+#endif
+
+void ea_to_ea_arg (void)
+{
+  arg_ea (ea_ptr);
+}
+
+void ea_to_lm_arg (void)
+{
+  arg_lm (LM_CAST (ea_ptr));
+}
+
+void lm_to_ea_arg (void)
+{
+  arg_ea (EA_CAST (lm_ptr));
+}
+
+void lm_to_lm_arg (void)
+{
+  arg_lm (lm_ptr);
+}
+
+ea_ptr_t ea_to_ea_ret (void)
+{
+  return ea_ptr;
+}
+
+lm_ptr_t ea_to_lm_ret (void)
+{
+  return LM_CAST (ea_ptr);
+}
+
+ea_ptr_t lm_to_ea_ret (void)
+{
+  return EA_CAST (lm_ptr);
+}
+
+lm_ptr_t lm_to_lm_ret (void)
+{
+  return lm_ptr;
+}
+
+void ea_to_ea_store (ea_ptr_t ptr)
+{
+  ea_ptr = ptr;
+}
+
+void ea_to_lm_store (ea_ptr_t ptr)
+{
+  lm_ptr = LM_CAST (ptr);
+}
+
+void lm_to_ea_store (lm_ptr_t ptr)
+{
+  ea_ptr = EA_CAST (ptr);
+}
+
+void lm_to_lm_store (lm_ptr_t ptr)
+{
+  lm_ptr = ptr;
+}
Index: gcc/testsuite/gcc.target/spu/ea/test-sizes.c
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/test-sizes.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/test-sizes.c	(revision 143347)
@@ -0,0 +1,590 @@
+/* { dg-do run { target spu-*-* } } */
+/* { dg-options "-std=gnu99 -mea64" } */
+
+#ifndef __EA64__
+#error "-mea64 must be used"
+#endif
+
+#if !defined(LEVEL1) && !defined(LEVEL2) && !defined(LEVEL3)
+#define LEVEL1 1		/* single pointer indirection */
+#define LEVEL2 1		/* 2 levels of pointer indirection */
+#define LEVEL3 1		/* 3 levels of pointer indirection */
+
+#else
+#ifndef LEVEL1
+#define LEVEL1 0
+#endif
+
+#ifndef LEVEL2
+#define LEVEL2 0
+#endif
+
+#ifndef LEVEL3
+#define LEVEL3 0
+#endif
+#endif
+
+#if !defined(USE_SIMPLE) && !defined(USE_COMPLEX)
+#define USE_SIMPLE  1		/* build up pointers via multiple typedefs */
+#define USE_COMPLEX 1		/* single typedef for pointer indirections */
+
+#else
+#ifndef USE_SIMPLE
+#define USE_SIMPLE 0
+#endif
+
+#ifndef USE_COMPLEX
+#define USE_COMPLEX 0
+#endif
+#endif
+
+#if !defined(USE_LOCAL_VAR) && !defined(USE_EA_VAR)
+#define USE_LOCAL_VAR 1		/* use variables declared locally */
+#define USE_EA_VAR    1		/* use variables on the host */
+
+#else
+#ifndef USE_LOCAL_VAR
+#define USE_LOCAL_VAR 0
+#endif
+
+#ifndef USE_EA_VAR
+#define USE_EA_VAR    0
+#endif
+#endif
+
+static int errors;
+
+#ifdef USE_PRINTF		/* print results via printf */
+#include <stdio.h>
+#include <stdlib.h>
+
+static int num_tests;
+
+#define TEST_SIZE(EXPR, EXPECTED)					\
+do {									\
+  char *msg;								\
+									\
+  if (sizeof (EXPR) != EXPECTED)					\
+    {									\
+      msg = ", FAIL";							\
+      errors++;								\
+    }									\
+  else									\
+    msg = "";								\
+									\
+  num_tests++;								\
+  printf ("sizeof %-20s = %2u, expected = %2u%s\n",			\
+	  #EXPR,							\
+	  (unsigned) sizeof (EXPR),					\
+	  (unsigned) EXPECTED,						\
+	  msg);								\
+} while (0)
+
+#define PRINT1(FMT)	  printf (FMT)
+#define PRINT2(FMT,A1)	  printf (FMT,A1)
+#define PRINT3(FMT,A1,A2) printf (FMT,A1,A2)
+
+#else	/* standalone */
+extern void abort (void);
+
+#define TEST_SIZE(EXPR, EXPECTED)					\
+do {									\
+  if (sizeof (EXPR) != EXPECTED)					\
+    abort ();								\
+} while (0)
+
+#define PRINT1(FMT)
+#define PRINT2(FMT,ARG)
+#define PRINT3(FMT,A1,A2)
+#endif
+
+/* 'local memory' hack to keep the same spacing.  */
+#define __lm
+
+#if USE_SIMPLE
+#if (LEVEL1 || LEVEL2 || LEVEL3)
+typedef __lm char *lm_ptr_t;
+typedef __ea char *ea_ptr_t;
+#endif
+
+#if LEVEL1
+#if USE_LOCAL_VAR
+__lm lm_ptr_t lm_ptr;
+__lm ea_ptr_t ea_ptr;
+#endif
+
+#if USE_EA_VAR
+__ea lm_ptr_t lm_ptr_ea;
+__ea ea_ptr_t ea_ptr_ea;
+#endif
+#endif
+
+#if (LEVEL2 || LEVEL3)
+typedef __lm lm_ptr_t *lm_lm_ptr_t;
+typedef __ea lm_ptr_t *ea_lm_ptr_t;
+typedef __lm ea_ptr_t *lm_ea_ptr_t;
+typedef __ea ea_ptr_t *ea_ea_ptr_t;
+#endif
+
+#if LEVEL2
+#if USE_LOCAL_VAR
+__lm lm_lm_ptr_t lm_lm_ptr;
+__lm ea_lm_ptr_t ea_lm_ptr;
+__lm lm_ea_ptr_t lm_ea_ptr;
+__lm ea_ea_ptr_t ea_ea_ptr;
+#endif
+
+#if USE_EA_VAR
+__ea lm_lm_ptr_t lm_lm_ptr_ea;
+__ea ea_lm_ptr_t ea_lm_ptr_ea;
+__ea lm_ea_ptr_t lm_ea_ptr_ea;
+__ea ea_ea_ptr_t ea_ea_ptr_ea;
+#endif
+#endif
+
+#if LEVEL3
+typedef __lm lm_lm_ptr_t *lm_lm_lm_ptr_t;
+typedef __ea lm_lm_ptr_t *ea_lm_lm_ptr_t;
+typedef __lm ea_lm_ptr_t *lm_ea_lm_ptr_t;
+typedef __ea ea_lm_ptr_t *ea_ea_lm_ptr_t;
+typedef __lm lm_ea_ptr_t *lm_lm_ea_ptr_t;
+typedef __ea lm_ea_ptr_t *ea_lm_ea_ptr_t;
+typedef __lm ea_ea_ptr_t *lm_ea_ea_ptr_t;
+typedef __ea ea_ea_ptr_t *ea_ea_ea_ptr_t;
+
+#if USE_LOCAL_VAR
+__lm lm_lm_lm_ptr_t lm_lm_lm_ptr;
+__lm ea_lm_lm_ptr_t ea_lm_lm_ptr;
+__lm lm_ea_lm_ptr_t lm_ea_lm_ptr;
+__lm ea_ea_lm_ptr_t ea_ea_lm_ptr;
+__lm lm_lm_ea_ptr_t lm_lm_ea_ptr;
+__lm ea_lm_ea_ptr_t ea_lm_ea_ptr;
+__lm lm_ea_ea_ptr_t lm_ea_ea_ptr;
+__lm ea_ea_ea_ptr_t ea_ea_ea_ptr;
+#endif
+
+#if USE_EA_VAR
+__ea lm_lm_lm_ptr_t lm_lm_lm_ptr_ea;
+__ea ea_lm_lm_ptr_t ea_lm_lm_ptr_ea;
+__ea lm_ea_lm_ptr_t lm_ea_lm_ptr_ea;
+__ea ea_ea_lm_ptr_t ea_ea_lm_ptr_ea;
+__ea lm_lm_ea_ptr_t lm_lm_ea_ptr_ea;
+__ea ea_lm_ea_ptr_t ea_lm_ea_ptr_ea;
+__ea lm_ea_ea_ptr_t lm_ea_ea_ptr_ea;
+__ea ea_ea_ea_ptr_t ea_ea_ea_ptr_ea;
+#endif
+#endif
+#endif
+
+#if USE_COMPLEX
+#if LEVEL1
+#if USE_LOCAL_VAR
+__lm char *__lm lm_cptr;
+__ea char *__lm ea_cptr;
+#endif
+
+#if USE_EA_VAR
+__lm char *__ea lm_cptr_ea;
+__ea char *__ea ea_cptr_ea;
+#endif
+#endif
+
+#if LEVEL2
+#if USE_LOCAL_VAR
+__lm char *__lm *__lm lm_lm_cptr;
+__lm char *__ea *__lm ea_lm_cptr;
+__ea char *__lm *__lm lm_ea_cptr;
+__ea char *__ea *__lm ea_ea_cptr;
+#endif
+
+#if USE_EA_VAR
+__lm char *__lm *__ea lm_lm_cptr_ea;
+__lm char *__ea *__ea ea_lm_cptr_ea;
+__ea char *__lm *__ea lm_ea_cptr_ea;
+__ea char *__ea *__ea ea_ea_cptr_ea;
+#endif
+#endif
+
+#if LEVEL3
+#if USE_LOCAL_VAR
+__lm char *__lm *__lm *__lm lm_lm_lm_cptr;
+__lm char *__ea *__lm *__lm lm_ea_lm_cptr;
+__ea char *__lm *__lm *__lm lm_lm_ea_cptr;
+__ea char *__ea *__lm *__lm lm_ea_ea_cptr;
+__lm char *__lm *__ea *__lm ea_lm_lm_cptr;
+__lm char *__ea *__ea *__lm ea_ea_lm_cptr;
+__ea char *__lm *__ea *__lm ea_lm_ea_cptr;
+__ea char *__ea *__ea *__lm ea_ea_ea_cptr;
+#endif
+
+#if USE_EA_VAR
+__lm char *__lm *__lm *__ea lm_lm_lm_cptr_ea;
+__lm char *__ea *__lm *__ea lm_ea_lm_cptr_ea;
+__ea char *__lm *__lm *__ea lm_lm_ea_cptr_ea;
+__ea char *__ea *__lm *__ea lm_ea_ea_cptr_ea;
+__lm char *__lm *__ea *__ea ea_lm_lm_cptr_ea;
+__lm char *__ea *__ea *__ea ea_ea_lm_cptr_ea;
+__ea char *__lm *__ea *__ea ea_lm_ea_cptr_ea;
+__ea char *__ea *__ea *__ea ea_ea_ea_cptr_ea;
+#endif
+#endif
+#endif
+
+int
+main ()
+{
+  PRINT2 ("LEVEL1        = %d\n", LEVEL1);
+  PRINT2 ("LEVEL2        = %d\n", LEVEL2);
+  PRINT2 ("LEVEL3        = %d\n", LEVEL3);
+  PRINT2 ("USE_SIMPLE    = %d\n", USE_SIMPLE);
+  PRINT2 ("USE_COMPLEX   = %d\n", USE_COMPLEX);
+  PRINT2 ("USE_LOCAL_VAR = %d\n", USE_LOCAL_VAR);
+  PRINT2 ("USE_EA_VAR    = %d\n", USE_EA_VAR);
+  PRINT1 ("\n");
+
+#if USE_SIMPLE
+#if LEVEL1
+#if USE_LOCAL_VAR
+  TEST_SIZE ( lm_ptr, 4);
+  TEST_SIZE (*lm_ptr, 1);
+  TEST_SIZE ( ea_ptr, 8);
+  TEST_SIZE (*ea_ptr, 1);
+  PRINT1 ("\n");
+#endif
+
+#if USE_EA_VAR
+  TEST_SIZE ( lm_ptr_ea, 4);
+  TEST_SIZE (*lm_ptr_ea, 1);
+  TEST_SIZE ( ea_ptr_ea, 8);
+  TEST_SIZE (*ea_ptr_ea, 1);
+  PRINT1 ("\n");
+#endif
+#endif
+
+#if LEVEL2
+#if USE_LOCAL_VAR
+  TEST_SIZE (  lm_lm_ptr, 4);
+  TEST_SIZE ( *lm_lm_ptr, 4);
+  TEST_SIZE (**lm_lm_ptr, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (  lm_ea_ptr, 4);
+  TEST_SIZE ( *lm_ea_ptr, 8);
+  TEST_SIZE (**lm_ea_ptr, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (  ea_lm_ptr, 8);
+  TEST_SIZE ( *ea_lm_ptr, 4);
+  TEST_SIZE (**ea_lm_ptr, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (  ea_ea_ptr, 8);
+  TEST_SIZE ( *ea_ea_ptr, 8);
+  TEST_SIZE (**ea_ea_ptr, 1);
+  PRINT1 ("\n");
+#endif
+
+#if USE_EA_VAR
+  TEST_SIZE (  lm_lm_ptr_ea, 4);
+  TEST_SIZE ( *lm_lm_ptr_ea, 4);
+  TEST_SIZE (**lm_lm_ptr_ea, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (  lm_ea_ptr_ea, 4);
+  TEST_SIZE ( *lm_ea_ptr_ea, 8);
+  TEST_SIZE (**lm_ea_ptr_ea, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (  ea_lm_ptr_ea, 8);
+  TEST_SIZE ( *ea_lm_ptr_ea, 4);
+  TEST_SIZE (**ea_lm_ptr_ea, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (  ea_ea_ptr_ea, 8);
+  TEST_SIZE ( *ea_ea_ptr_ea, 8);
+  TEST_SIZE (**ea_ea_ptr_ea, 1);
+  PRINT1 ("\n");
+#endif
+#endif
+
+#if LEVEL3
+#if USE_LOCAL_VAR
+  TEST_SIZE (   lm_lm_lm_ptr, 4);
+  TEST_SIZE (  *lm_lm_lm_ptr, 4);
+  TEST_SIZE ( **lm_lm_lm_ptr, 4);
+  TEST_SIZE (***lm_lm_lm_ptr, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   lm_lm_ea_ptr, 4);
+  TEST_SIZE (  *lm_lm_ea_ptr, 4);
+  TEST_SIZE ( **lm_lm_ea_ptr, 8);
+  TEST_SIZE (***lm_lm_ea_ptr, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   lm_ea_lm_ptr, 4);
+  TEST_SIZE (  *lm_ea_lm_ptr, 8);
+  TEST_SIZE ( **lm_ea_lm_ptr, 4);
+  TEST_SIZE (***lm_ea_lm_ptr, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   lm_ea_ea_ptr, 4);
+  TEST_SIZE (  *lm_ea_ea_ptr, 8);
+  TEST_SIZE ( **lm_ea_ea_ptr, 8);
+  TEST_SIZE (***lm_ea_ea_ptr, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   ea_lm_lm_ptr, 8);
+  TEST_SIZE (  *ea_lm_lm_ptr, 4);
+  TEST_SIZE ( **ea_lm_lm_ptr, 4);
+  TEST_SIZE (***ea_lm_lm_ptr, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   ea_lm_ea_ptr, 8);
+  TEST_SIZE (  *ea_lm_ea_ptr, 4);
+  TEST_SIZE ( **ea_lm_ea_ptr, 8);
+  TEST_SIZE (***ea_lm_ea_ptr, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   ea_ea_lm_ptr, 8);
+  TEST_SIZE (  *ea_ea_lm_ptr, 8);
+  TEST_SIZE ( **ea_ea_lm_ptr, 4);
+  TEST_SIZE (***ea_ea_lm_ptr, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   ea_ea_ea_ptr, 8);
+  TEST_SIZE (  *ea_ea_ea_ptr, 8);
+  TEST_SIZE ( **ea_ea_ea_ptr, 8);
+  TEST_SIZE (***ea_ea_ea_ptr, 1);
+  PRINT1 ("\n");
+#endif
+
+#if USE_EA_VAR
+  TEST_SIZE (   lm_lm_lm_ptr_ea, 4);
+  TEST_SIZE (  *lm_lm_lm_ptr_ea, 4);
+  TEST_SIZE ( **lm_lm_lm_ptr_ea, 4);
+  TEST_SIZE (***lm_lm_lm_ptr_ea, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   lm_lm_ea_ptr_ea, 4);
+  TEST_SIZE (  *lm_lm_ea_ptr_ea, 4);
+  TEST_SIZE ( **lm_lm_ea_ptr_ea, 8);
+  TEST_SIZE (***lm_lm_ea_ptr_ea, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   lm_ea_lm_ptr_ea, 4);
+  TEST_SIZE (  *lm_ea_lm_ptr_ea, 8);
+  TEST_SIZE ( **lm_ea_lm_ptr_ea, 4);
+  TEST_SIZE (***lm_ea_lm_ptr_ea, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   lm_ea_ea_ptr_ea, 4);
+  TEST_SIZE (  *lm_ea_ea_ptr_ea, 8);
+  TEST_SIZE ( **lm_ea_ea_ptr_ea, 8);
+  TEST_SIZE (***lm_ea_ea_ptr_ea, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   ea_lm_lm_ptr_ea, 8);
+  TEST_SIZE (  *ea_lm_lm_ptr_ea, 4);
+  TEST_SIZE ( **ea_lm_lm_ptr_ea, 4);
+  TEST_SIZE (***ea_lm_lm_ptr_ea, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   ea_lm_ea_ptr_ea, 8);
+  TEST_SIZE (  *ea_lm_ea_ptr_ea, 4);
+  TEST_SIZE ( **ea_lm_ea_ptr_ea, 8);
+  TEST_SIZE (***ea_lm_ea_ptr_ea, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   ea_ea_lm_ptr_ea, 8);
+  TEST_SIZE (  *ea_ea_lm_ptr_ea, 8);
+  TEST_SIZE ( **ea_ea_lm_ptr_ea, 4);
+  TEST_SIZE (***ea_ea_lm_ptr_ea, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   ea_ea_ea_ptr_ea, 8);
+  TEST_SIZE (  *ea_ea_ea_ptr_ea, 8);
+  TEST_SIZE ( **ea_ea_ea_ptr_ea, 8);
+  TEST_SIZE (***ea_ea_ea_ptr_ea, 1);
+  PRINT1 ("\n");
+#endif
+#endif
+#endif
+
+#if USE_COMPLEX
+#if LEVEL1
+#if USE_LOCAL_VAR
+  TEST_SIZE ( lm_cptr, 4);
+  TEST_SIZE (*lm_cptr, 1);
+  TEST_SIZE ( ea_cptr, 8);
+  TEST_SIZE (*ea_cptr, 1);
+  PRINT1 ("\n");
+#endif
+
+#if USE_EA_VAR
+  TEST_SIZE ( lm_cptr_ea, 4);
+  TEST_SIZE (*lm_cptr_ea, 1);
+  TEST_SIZE ( ea_cptr_ea, 8);
+  TEST_SIZE (*ea_cptr_ea, 1);
+  PRINT1 ("\n");
+#endif
+#endif
+
+#if LEVEL2
+#if USE_LOCAL_VAR
+  TEST_SIZE (  lm_lm_cptr, 4);
+  TEST_SIZE ( *lm_lm_cptr, 4);
+  TEST_SIZE (**lm_lm_cptr, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (  lm_ea_cptr, 4);
+  TEST_SIZE ( *lm_ea_cptr, 8);
+  TEST_SIZE (**lm_ea_cptr, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (  ea_lm_cptr, 8);
+  TEST_SIZE ( *ea_lm_cptr, 4);
+  TEST_SIZE (**ea_lm_cptr, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (  ea_ea_cptr, 8);
+  TEST_SIZE ( *ea_ea_cptr, 8);
+  TEST_SIZE (**ea_ea_cptr, 1);
+  PRINT1 ("\n");
+#endif
+
+#if USE_EA_VAR
+  TEST_SIZE (  lm_lm_cptr_ea, 4);
+  TEST_SIZE ( *lm_lm_cptr_ea, 4);
+  TEST_SIZE (**lm_lm_cptr_ea, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (  lm_ea_cptr_ea, 4);
+  TEST_SIZE ( *lm_ea_cptr_ea, 8);
+  TEST_SIZE (**lm_ea_cptr_ea, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (  ea_lm_cptr_ea, 8);
+  TEST_SIZE ( *ea_lm_cptr_ea, 4);
+  TEST_SIZE (**ea_lm_cptr_ea, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (  ea_ea_cptr_ea, 8);
+  TEST_SIZE ( *ea_ea_cptr_ea, 8);
+  TEST_SIZE (**ea_ea_cptr_ea, 1);
+  PRINT1 ("\n");
+#endif
+#endif
+
+#if LEVEL3
+#if USE_LOCAL_VAR
+  TEST_SIZE (   lm_lm_lm_cptr, 4);
+  TEST_SIZE (  *lm_lm_lm_cptr, 4);
+  TEST_SIZE ( **lm_lm_lm_cptr, 4);
+  TEST_SIZE (***lm_lm_lm_cptr, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   lm_lm_ea_cptr, 4);
+  TEST_SIZE (  *lm_lm_ea_cptr, 4);
+  TEST_SIZE ( **lm_lm_ea_cptr, 8);
+  TEST_SIZE (***lm_lm_ea_cptr, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   lm_ea_lm_cptr, 4);
+  TEST_SIZE (  *lm_ea_lm_cptr, 8);
+  TEST_SIZE ( **lm_ea_lm_cptr, 4);
+  TEST_SIZE (***lm_ea_lm_cptr, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   lm_ea_ea_cptr, 4);
+  TEST_SIZE (  *lm_ea_ea_cptr, 8);
+  TEST_SIZE ( **lm_ea_ea_cptr, 8);
+  TEST_SIZE (***lm_ea_ea_cptr, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   ea_lm_lm_cptr, 8);
+  TEST_SIZE (  *ea_lm_lm_cptr, 4);
+  TEST_SIZE ( **ea_lm_lm_cptr, 4);
+  TEST_SIZE (***ea_lm_lm_cptr, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   ea_lm_ea_cptr, 8);
+  TEST_SIZE (  *ea_lm_ea_cptr, 4);
+  TEST_SIZE ( **ea_lm_ea_cptr, 8);
+  TEST_SIZE (***ea_lm_ea_cptr, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   ea_ea_lm_cptr, 8);
+  TEST_SIZE (  *ea_ea_lm_cptr, 8);
+  TEST_SIZE ( **ea_ea_lm_cptr, 4);
+  TEST_SIZE (***ea_ea_lm_cptr, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   ea_ea_ea_cptr, 8);
+  TEST_SIZE (  *ea_ea_ea_cptr, 8);
+  TEST_SIZE ( **ea_ea_ea_cptr, 8);
+  TEST_SIZE (***ea_ea_ea_cptr, 1);
+  PRINT1 ("\n");
+#endif
+
+#if USE_EA_VAR
+  TEST_SIZE (   lm_lm_lm_cptr_ea, 4);
+  TEST_SIZE (  *lm_lm_lm_cptr_ea, 4);
+  TEST_SIZE ( **lm_lm_lm_cptr_ea, 4);
+  TEST_SIZE (***lm_lm_lm_cptr_ea, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   lm_lm_ea_cptr_ea, 4);
+  TEST_SIZE (  *lm_lm_ea_cptr_ea, 4);
+  TEST_SIZE ( **lm_lm_ea_cptr_ea, 8);
+  TEST_SIZE (***lm_lm_ea_cptr_ea, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   lm_ea_lm_cptr_ea, 4);
+  TEST_SIZE (  *lm_ea_lm_cptr_ea, 8);
+  TEST_SIZE ( **lm_ea_lm_cptr_ea, 4);
+  TEST_SIZE (***lm_ea_lm_cptr_ea, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   lm_ea_ea_cptr_ea, 4);
+  TEST_SIZE (  *lm_ea_ea_cptr_ea, 8);
+  TEST_SIZE ( **lm_ea_ea_cptr_ea, 8);
+  TEST_SIZE (***lm_ea_ea_cptr_ea, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   ea_lm_lm_cptr_ea, 8);
+  TEST_SIZE (  *ea_lm_lm_cptr_ea, 4);
+  TEST_SIZE ( **ea_lm_lm_cptr_ea, 4);
+  TEST_SIZE (***ea_lm_lm_cptr_ea, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   ea_lm_ea_cptr_ea, 8);
+  TEST_SIZE (  *ea_lm_ea_cptr_ea, 4);
+  TEST_SIZE ( **ea_lm_ea_cptr_ea, 8);
+  TEST_SIZE (***ea_lm_ea_cptr_ea, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   ea_ea_lm_cptr_ea, 8);
+  TEST_SIZE (  *ea_ea_lm_cptr_ea, 8);
+  TEST_SIZE ( **ea_ea_lm_cptr_ea, 4);
+  TEST_SIZE (***ea_ea_lm_cptr_ea, 1);
+  PRINT1 ("\n");
+
+  TEST_SIZE (   ea_ea_ea_cptr_ea, 8);
+  TEST_SIZE (  *ea_ea_ea_cptr_ea, 8);
+  TEST_SIZE ( **ea_ea_ea_cptr_ea, 8);
+  TEST_SIZE (***ea_ea_ea_cptr_ea, 1);
+  PRINT1 ("\n");
+#endif
+#endif
+#endif
+
+  if (errors)
+    {
+      PRINT3 ("%d error(s), %d test(s)\n", errors, num_tests);
+      abort ();
+    }
+  else
+    PRINT2 ("No errors, %d test(s)\n", num_tests);
+
+  return 0;
+}
Index: gcc/testsuite/gcc.target/spu/ea/compile3.c
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/compile3.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/compile3.c	(revision 143347)
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -std=gnu99 -pedantic-errors -maddress-space-conversion" } */
+
+/* This is the same as errors3.c except it should not generate any errors.
+   If you modify this code, please modify errors3.c as well.  */
+
+#define __lm
+
+__ea int ea_var = 1;
+__lm int lm_var = 2;
+
+typedef __ea int *ea_ptr_t;
+typedef __lm int *lm_ptr_t;
+
+typedef __ea char *ea_cptr_t;
+typedef __lm char *lm_cptr_t;
+
+ea_ptr_t ea, ea2;
+lm_ptr_t lm, lm2;
+
+extern void call_ea (ea_ptr_t);
+extern void call_lm (lm_ptr_t);
+
+/* No errors here.  */
+void to_ea (void) { ea = lm; }
+void to_lm (void) { lm = ea; }
+ea_ptr_t ret_ea (void) { return lm; }
+lm_ptr_t ret_lm (void) { return ea; }
+void call_ea2 (void) { call_ea (lm); }
+void call_lm2 (void) { call_lm (ea); }
+int sub_ea (void) { return ea - lm; }
+int sub_lm (void) { return lm - ea; }
+int if_ea (int test) { return *((test) ? ea : lm); }
+int if_lm (int test) { return *((test) ? lm : ea); }
+
+void to_ea2 (void) { ea = ea2; }
+void to_lm2 (void) { lm = lm2; }
+
+void to_ea_with_cast (void) { ea = (ea_ptr_t)lm; }
+void to_lm_with_cast (void) { lm = (lm_ptr_t)ea; }
+ea_ptr_t ret_ea_with_cast (void) { return (ea_ptr_t)lm; }
+lm_ptr_t ret_lm_with_cast (void) { return (lm_ptr_t)ea; }
+void call_ea2_with_cast (void) { call_ea ((ea_ptr_t)lm); }
+void call_lm2_with_cast (void) { call_lm ((lm_ptr_t)ea); }
+int sub_ea_with_cast (void) { return ea - (ea_ptr_t)lm; }
+int sub_lm_with_cast (void) { return lm - (lm_ptr_t)ea; }
+int if_ea_with_cast (int test) { return *((test) ? ea : (ea_ptr_t)lm); }
+int if_lm_with_cast (int test) { return *((test) ? lm : (lm_ptr_t)ea); }
+
+void void_ea (void) { ea = (void *)0; }
+void void_lm (void) { lm = (__ea void *)0; }
Index: gcc/testsuite/gcc.target/spu/ea/cast1.c
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/cast1.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/cast1.c	(revision 143347)
@@ -0,0 +1,29 @@
+/* { dg-do run { target spu-*-* } } */
+/* { dg-require-effective-target "ea32" } */
+/* { dg-options "-std=gnu99 -O2 -mea32" } */
+
+extern void abort (void);
+extern unsigned long long __ea_local_store;
+
+__ea int *ppu;
+int x, *spu = &x, *spu2;
+
+int
+main (int argc, char **argv)
+{
+  ppu = (__ea int *) spu;
+  spu2 = (int *) ppu;
+
+#ifdef __EA32__
+  if ((int) ppu != (int) __ea_local_store + (int) spu)
+#else
+  if ((unsigned long long) ppu != __ea_local_store + (unsigned long long)(int) spu)
+#endif
+
+    abort ();
+
+  if (spu != spu2)
+    abort ();
+
+  return 0;
+}
Index: gcc/testsuite/gcc.target/spu/ea/compile4.c
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/compile4.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/compile4.c	(revision 143347)
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -std=gnu99 -pedantic-errors -mea64" } */
+/* Make sure __ea structure references work.  */
+
+typedef unsigned long int uintptr_t;
+
+struct tostruct
+{
+  uintptr_t selfpc;
+  long count;
+  unsigned short link;
+};
+
+/* froms are indexing tos */
+static __ea unsigned short *froms;
+static __ea struct tostruct *tos = 0;
+
+void
+foo (uintptr_t frompc, uintptr_t selfpc)
+{
+  __ea unsigned short *frompcindex;
+
+  frompcindex = &froms[(frompc) / (4 * sizeof (*froms))];
+  *frompcindex = tos[0].link;
+
+  return;
+}
Index: gcc/testsuite/gcc.target/spu/ea/options1.c
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/options1.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/options1.c	(revision 143347)
@@ -0,0 +1,5 @@
+/* Test -mcache-size.  */
+/* { dg-options "-mcache-size=128" } */
+/* { dg-do compile } */
+
+int x;
Index: gcc/testsuite/gcc.target/spu/ea/errors.c
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/errors.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/errors.c	(revision 143347)
@@ -0,0 +1,41 @@
+/* Invalid __ea declarations.  */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99 -pedantic-errors" } */
+
+extern __ea void f1 ();	 /* { dg-error "'__ea' specified for function 'f1'" } */
+
+void func ()
+{
+  register __ea int local1; /* { dg-error "'__ea' combined with 'register' qualifier for 'local1'" } */
+  auto __ea int local2;     /* { dg-error "'__ea' combined with 'auto' qualifier for 'local2'" } */
+  __ea int local3;	    /* { dg-error "'__ea' specified for auto variable 'local3'" } */
+  register int *__ea p1;    /* { dg-error "'__ea' combined with 'register' qualifier for 'p1'" } */
+  auto char *__ea p2;       /* { dg-error "'__ea' combined with 'auto' qualifier for 'p2'" } */
+  void *__ea p3;            /* { dg-error "'__ea' specified for auto variable 'p3'" } */
+  register __ea int a1[2];  /* { dg-error "'__ea' combined with 'register' qualifier for 'a1'" } */
+  auto __ea char a2[1];     /* { dg-error "'__ea' combined with 'auto' qualifier for 'a2'" } */
+  __ea char a3[5];          /* { dg-error "'__ea' specified for auto variable 'a3'" } */
+}
+
+void func2 (__ea int x)	    /* { dg-error "'__ea' specified for parameter 'x'" } */
+{ }
+
+struct st {
+  __ea int x;		    /* { dg-error "'__ea' specified for structure field 'x'" } */
+  int *__ea q;		    /* { dg-error "'__ea' specified for structure field 'q'" } */
+} s;
+
+__ea int func3 (int x) {    /* { dg-error "'__ea' specified for function 'func3'" } */
+  return x;
+}
+
+struct A { int a; };
+
+int func4 (int *__ea x)	    /* { dg-error "'__ea' specified for parameter 'x'" } */
+{
+  struct A i = (__ea struct A) { 1 };	/* { dg-error "compound literal qualified by address-space qualifier" } */
+  return i.a;
+}
+
+extern __ea int ea_var;		/* { dg-message "note: previous.*decl" "previous.*decl" } */
+int ea_var;			/* { dg-error "conflicting named address spaces" "conflicting named address spaces" } */
Index: gcc/testsuite/gcc.target/spu/ea/cache64.c
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/cache64.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/cache64.c	(revision 143347)
@@ -0,0 +1,26 @@
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+
+   This file is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 2 of the License, or (at your option)
+   any later version.
+
+   This file is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+   for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this file; see the file COPYING.  If not, write to the Free
+   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+/* { dg-do run } */
+/* { dg-require-effective-target "ea64" } */
+/* { dg-options "-mcache-size=8 -O2 -mea64 -g" } */
+
+#ifndef __EA64__
+#error "You must use -mea64 for this test"
+#endif
+
+#include "cache-common.h"
Index: gcc/testsuite/gcc.target/spu/ea/execute1.c
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/execute1.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/execute1.c	(revision 143347)
@@ -0,0 +1,27 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -std=gnu99 -g -pedantic-errors -mea32" } */
+/* { dg-xfail-run-if "" { "spu-*-*" } { "*" } { "" } } */
+
+#include <stdlib.h>
+
+__ea char str[] = "abc";
+
+int
+main (void)
+{
+  __ea char *p = str;
+
+  if (*p++ != 'a')
+    abort ();
+
+  if (*p++ != 'b')
+    abort ();
+
+  if (*p++ != 'c')
+    abort ();
+
+  if (*p++ != '\0')
+    abort ();
+
+  return 0;
+}
Index: gcc/testsuite/gcc.target/spu/ea/execute2.c
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/execute2.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/execute2.c	(revision 143347)
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -std=gnu99 -g -pedantic-errors -mea32" } */
+
+#include <stdlib.h>
+
+char str[] = "abc";
+
+int
+main (void)
+{
+  __ea char *p = (__ea char *)str;
+
+  if (*p++ != 'a')
+    abort ();
+
+  if (*p++ != 'b')
+    abort ();
+
+  if (*p++ != 'c')
+    abort ();
+
+  if (*p++ != '\0')
+    abort ();
+
+  return 0;
+}
Index: gcc/testsuite/gcc.target/spu/ea/execute3.c
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/execute3.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/execute3.c	(revision 143347)
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -std=gnu99 -g -pedantic-errors -mea32" } */
+
+#include <stdlib.h>
+
+int
+main (void)
+{
+  __ea char *p = (__ea char *)"abc";
+
+  if (*p++ != 'a')
+    abort ();
+
+  if (*p++ != 'b')
+    abort ();
+
+  if (*p++ != 'c')
+    abort ();
+
+  if (*p++ != '\0')
+    abort ();
+
+  return 0;
+}
Index: gcc/testsuite/gcc.target/spu/ea/execute1-m64.c
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/execute1-m64.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/execute1-m64.c	(revision 143347)
@@ -0,0 +1,27 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -std=gnu99 -g -pedantic-errors -mea64" } */
+/* { dg-xfail-run-if "" { "spu-*-*" } { "*" } { "" } } */
+
+#include <stdlib.h>
+
+__ea char str[] = "abc";
+
+int
+main (void)
+{
+  __ea char *p = str;
+
+  if (*p++ != 'a')
+    abort ();
+
+  if (*p++ != 'b')
+    abort ();
+
+  if (*p++ != 'c')
+    abort ();
+
+  if (*p++ != '\0')
+    abort ();
+
+  return 0;
+}
Index: gcc/testsuite/gcc.target/spu/ea/compile.c
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/compile.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/compile.c	(revision 143347)
@@ -0,0 +1,93 @@
+/* Valid __ea declarations.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -std=gnu99 -pedantic-errors" } */
+
+/* Typedefs.  */
+typedef __ea int ea_int_t;
+typedef __ea int *ea_int_star_t;
+typedef int outer_t;
+
+/* Externs.  */
+
+__ea extern int i1;
+extern __ea int i2;
+extern int __ea i3;
+extern __ea ea_int_t i4;		/* __ea qualifier permitted via typedef.  */
+extern int __ea __ea __ea dupe;		/* __ea duplicate permitted directly.  */
+extern int __ea *ppu;
+
+/* Pointers.  */
+__ea int *i4p;
+
+/* Structs.  */
+struct st {
+  __ea int *p;
+};
+
+/* Variable definitions.  */
+__ea int ii0;
+int *__ea ii1;
+static int __ea ii2;
+
+void
+f1 ()
+{
+  int *spu;
+  ppu = (ea_int_t *) spu;
+  ppu = (ea_int_star_t) spu;
+}
+
+void
+f2 ()
+{
+  int *spu;
+  spu = (int *) ppu;
+  ppu = (__ea int *) spu;
+}
+
+void
+f3 ()
+{
+  int i = sizeof (__ea int);
+}
+
+__ea int *f4 (void)
+{
+  return 0;
+}
+
+int f5 (__ea int *parm)
+{
+  static __ea int local4;
+  int tmp = local4;
+  local4 = *parm;
+  return tmp;
+}
+
+static inline __ea void *f6 (__ea void *start)
+{
+  return 0;
+}
+
+void f7 (void)
+{
+  __ea void *s1;
+  auto __ea void *s2;
+}
+
+__ea int *f8 (__ea int *x)
+{
+  register __ea int *y = x;
+  __ea int *z = y;
+  return z;
+}
+
+long long f9 (__ea long long x[2])
+{
+  return x[0] + x[1];
+}
+
+void f10 ()
+{
+  static __ea outer_t o;
+}
Index: gcc/testsuite/gcc.target/spu/ea/execute2-m64.c
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/execute2-m64.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/execute2-m64.c	(revision 143347)
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -std=gnu99 -g -pedantic-errors -mea64" } */
+
+#include <stdlib.h>
+
+char str[] = "abc";
+
+int
+main (void)
+{
+  __ea char *p = (__ea char *)str;
+
+  if (*p++ != 'a')
+    abort ();
+
+  if (*p++ != 'b')
+    abort ();
+
+  if (*p++ != 'c')
+    abort ();
+
+  if (*p++ != '\0')
+    abort ();
+
+  return 0;
+}
Index: gcc/testsuite/gcc.target/spu/ea/execute3-m64.c
===================================================================
--- gcc/testsuite/gcc.target/spu/ea/execute3-m64.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/spu/ea/execute3-m64.c	(revision 143347)
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -std=gnu99 -g -pedantic-errors -mea64" } */
+
+#include <stdlib.h>
+
+int
+main (void)
+{
+  __ea char *p = (__ea char *)"abc";
+
+  if (*p++ != 'a')
+    abort ();
+
+  if (*p++ != 'b')
+    abort ();
+
+  if (*p++ != 'c')
+    abort ();
+
+  if (*p++ != '\0')
+    abort ();
+
+  return 0;
+}
Index: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/cp/typeck.c	(working copy)
@@ -7133,7 +7133,7 @@ cp_type_quals (const_tree type)
   type = strip_array_types (CONST_CAST_TREE(type));
   if (type == error_mark_node)
     return TYPE_UNQUALIFIED;
-  return TYPE_QUALS (type);
+  return TYPE_QUALS (CONST_CAST_TREE (type));
 }
 
 /* Returns nonzero if the TYPE is const from a C++ perspective: look inside
Index: gcc/c-parser.c
===================================================================
--- gcc/c-parser.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/c-parser.c	(working copy)
@@ -70,6 +70,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;
@@ -130,6 +134,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;
@@ -226,6 +232,13 @@ c_lex_one_token (c_parser *parser, c_tok
 			    "identifier %qs conflicts with C++ keyword",
 			    IDENTIFIER_POINTER (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)
@@ -352,6 +365,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:
@@ -422,6 +437,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:
@@ -1391,6 +1408,7 @@ c_parser_asm_definition (c_parser *parse
      const
      restrict
      volatile
+     address-space-qualifier
 
    (restrict is new in C99.)
 
@@ -1399,6 +1417,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
 
@@ -1438,6 +1462,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.  */
@@ -5530,6 +5565,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");
   expr.value = build_compound_literal (type, init.value);
Index: gcc/config/spu/spu_cache.h
===================================================================
--- gcc/config/spu/spu_cache.h	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/config/spu/spu_cache.h	(revision 143347)
@@ -0,0 +1,41 @@
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+
+   This file is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 2 of the License, or (at your option)
+   any later version.
+
+   This file is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+   for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this file; see the file COPYING.  If not, write to the Free
+   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+/* As a special exception, if you include this header file into source files
+   compiled by GCC, this header file does not by itself cause  the resulting
+   executable to be covered by the GNU General Public License.  This exception
+   does not however invalidate any other reasons why the executable file might be
+   covered by the GNU General Public License.  */
+
+#ifndef SPU_CACHEH
+#define SPU_CACHEH
+
+void *__cache_fetch_dirty (__ea void *ea, int n_bytes_dirty);
+void *__cache_fetch (__ea void *ea);
+void __cache_evict (__ea void *ea);
+void __cache_flush (void);
+void __cache_touch (__ea void *ea);
+
+#define cache_fetch_dirty(_ea, _n_bytes_dirty) \
+     __cache_fetch_dirty(_ea, _n_bytes_dirty)
+
+#define cache_fetch(_ea) __cache_fetch(_ea)
+#define cache_touch(_ea) __cache_touch(_ea)
+#define cache_evict(_ea) __cache_evict(_ea)
+#define cache_flush() __cache_flush()
+
+#endif
Index: gcc/config/spu/cachemgr.c
===================================================================
--- gcc/config/spu/cachemgr.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/config/spu/cachemgr.c	(revision 143347)
@@ -0,0 +1,459 @@
+/* Copyright (C) 2008  Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
+
+#include <spu_mfcio.h>
+#include <spu_internals.h>
+#include <spu_intrinsics.h>
+#include <spu_cache.h>
+
+extern unsigned long long __ea_local_store;
+extern char __cache_tag_array_size;
+
+#define LINE_SIZE 128
+#define TAG_MASK (LINE_SIZE - 1)
+
+#define WAYS 4
+#define SET_MASK ((int) &__cache_tag_array_size - LINE_SIZE)
+
+#define CACHE_LINES ((int) &__cache_tag_array_size / \
+  sizeof (struct __cache_tag_array) * WAYS)
+
+struct __cache_tag_array
+{
+  unsigned int tag_lo[WAYS];
+  unsigned int tag_hi[WAYS];
+  void *base[WAYS];
+  int reserved[WAYS];
+  vector unsigned short dirty_bits[WAYS];
+};
+
+extern struct __cache_tag_array __cache_tag_array[];
+extern char __cache[];
+
+/* In order to make the code seem a little cleaner, and to avoid having
+   64/32 bit ifdefs all over the place, we macro.  */
+
+/* It may seem poor taste to define variables within a macro, but
+   it's C99 compliant.  */
+
+#ifdef __EA64__
+#define CHECK_TAG(_entry, _way, _tag) ((_entry->tag_lo[_way] == \
+  (_tag & 0xFFFFFFFF))&&(_entry->tag_hi[_way] == (_tag >> 32)))
+
+#define GET_TAG(_entry, _way) unsigned long long tag = _entry->tag_hi[_way]; \
+  tag = tag << 32;                                                           \
+  tag |= (_entry->tag_lo[_way]);
+
+#define SET_TAG(_entry, _way, _tag)             \
+  _entry->tag_lo[_way] = (_tag & 0xFFFFFFFF);   \
+  _entry->tag_hi[_way] = (_tag >> 32);
+
+#define addr unsigned long long
+#define si_from_eavoid(_x) si_from_ullong (eavoid_to_eanum(_x))
+#else /*__EA32__*/
+#define CHECK_TAG(_entry, _way, _tag) (_entry->tag_lo[_way] == _tag)
+
+#define GET_TAG(_entry, _way) unsigned long tag = _entry->tag_lo[_way]
+
+#define SET_TAG(_entry, _way, _tag)     \
+  _entry->tag_lo[_way] = _tag;
+
+#define addr unsigned long
+#define si_from_eavoid(_x) si_from_uint (eavoid_to_eanum(_x))
+#endif
+
+/* In GET_ENTRY, we cast away the high 32 bits,
+   as the tag is only in the low 32.  */
+
+#define GET_ENTRY(_addr) ((struct __cache_tag_array *)                  \
+        si_to_ptr(si_a                                                  \
+                   (si_and(si_from_uint((unsigned int) (addr) _addr),   \
+                           si_from_uint(SET_MASK)),                     \
+                    si_from_uint((unsigned int) __cache_tag_array))));
+
+#define GET_CACHE_LINE(_addr, _way)  ((void *) (__cache +       \
+  (_addr & SET_MASK) * WAYS) + (_way * LINE_SIZE));
+
+#define eavoid_to_eanum(_ea) ((addr) _ea)
+
+#define CHECK_DIRTY(_vec) (si_to_uint (si_orx ((qword) _vec)))
+#define SET_EMPTY(_entry, _way) (_entry->tag_lo[_way] = 1)
+#define CHECK_EMPTY(_entry, _way) (_entry->tag_lo[_way] == 1)
+
+#define LS_FLAG 0x80000000
+#define SET_IS_LS(_entry, _way) (_entry->reserved[_way] |= LS_FLAG)
+#define CHECK_IS_LS(_entry, _way) (_entry->reserved[_way] & LS_FLAG)
+#define GET_LRU(_entry, _way) (_entry->reserved[_way] & ~(LS_FLAG))
+
+static void __cache_flush_stub (void) __attribute__ ((destructor));
+static int dma_tag = 32;
+
+static void
+__cache_evict_entry (struct __cache_tag_array *entry, int way)
+{
+
+  GET_TAG (entry, way);
+
+  if ((CHECK_DIRTY (entry->dirty_bits[way])) && (!CHECK_IS_LS (entry, way)))
+    {
+#ifdef NONATOMIC
+      /* Non-atomic writes.  */
+      unsigned int oldmask, mach_stat;
+      char *line = ((void *) 0);
+
+      /* Enter critical section.  */
+      mach_stat = spu_readch (SPU_RdMachStat);
+      spu_idisable ();
+
+      /* Issue DMA request.  */
+      line = GET_CACHE_LINE (entry->tag_lo[way], way);
+      mfc_put (line, tag, LINE_SIZE, dma_tag, 0, 0);
+
+      /* Wait for DMA completion.  */
+      oldmask = mfc_read_tag_mask ();
+      mfc_write_tag_mask (1 << dma_tag);
+      mfc_read_tag_status_all ();
+      mfc_write_tag_mask (oldmask);
+
+      /* Leave critical section.  */
+      if (__builtin_expect (mach_stat & 1, 0))
+	spu_ienable ();
+#else
+      /* Allocate a buffer large enough that we know it has 128 bytes
+         that are 128 byte aligned (for DMA). */
+
+      char buffer[LINE_SIZE + 127];
+      qword *buf_ptr = (qword *) (((unsigned int) (buffer) + 127) & ~127);
+      qword *line = GET_CACHE_LINE (entry->tag_lo[way], way);
+      qword bits;
+      unsigned int mach_stat;
+
+      /* Enter critical section.  */
+      mach_stat = spu_readch (SPU_RdMachStat);
+      spu_idisable ();
+
+      do
+	{
+	  /* We atomically read the current memory into a buffer
+	     modify the dirty bytes in the buffer, and write it
+	     back. If writeback fails, loop and try again.  */
+
+	  mfc_getllar (buf_ptr, tag, 0, 0);
+	  mfc_read_atomic_status ();
+
+	  /* The method we're using to write 16 dirty bytes into
+	     the buffer at a time uses fsmb which in turn uses
+	     the least significant 16 bits of word 0, so we
+	     load the bits and rotate so that the first bit of
+	     the bitmap is in the first bit that fsmb will use.  */
+
+	  bits = (qword) entry->dirty_bits[way];
+	  bits = si_rotqbyi (bits, -2);
+
+	  /* Si_fsmb creates the mask of dirty bytes.
+	     Use selb to nab the appropriate bits.  */
+	  buf_ptr[0] = si_selb (buf_ptr[0], line[0], si_fsmb (bits));
+
+	  /* Rotate to next 16 byte section of cache.  */
+	  bits = si_rotqbyi (bits, 2);
+
+	  buf_ptr[1] = si_selb (buf_ptr[1], line[1], si_fsmb (bits));
+	  bits = si_rotqbyi (bits, 2);
+	  buf_ptr[2] = si_selb (buf_ptr[2], line[2], si_fsmb (bits));
+	  bits = si_rotqbyi (bits, 2);
+	  buf_ptr[3] = si_selb (buf_ptr[3], line[3], si_fsmb (bits));
+	  bits = si_rotqbyi (bits, 2);
+	  buf_ptr[4] = si_selb (buf_ptr[4], line[4], si_fsmb (bits));
+	  bits = si_rotqbyi (bits, 2);
+	  buf_ptr[5] = si_selb (buf_ptr[5], line[5], si_fsmb (bits));
+	  bits = si_rotqbyi (bits, 2);
+	  buf_ptr[6] = si_selb (buf_ptr[6], line[6], si_fsmb (bits));
+	  bits = si_rotqbyi (bits, 2);
+	  buf_ptr[7] = si_selb (buf_ptr[7], line[7], si_fsmb (bits));
+	  bits = si_rotqbyi (bits, 2);
+
+	  mfc_putllc (buf_ptr, tag, 0, 0);
+	}
+      while (mfc_read_atomic_status ());
+
+      /* Leave critical section.  */
+      if (__builtin_expect (mach_stat & 1, 0))
+	spu_ienable ();
+#endif
+    }
+
+  /* In any case, marking the lo tag with 1 which denotes empty.  */
+  SET_EMPTY (entry, way);
+  entry->dirty_bits[way] = (vector unsigned short) si_from_uint (0);
+}
+
+void
+__cache_evict (__ea void *ea)
+{
+  addr tag = (eavoid_to_eanum (ea) & ~(TAG_MASK));
+  struct __cache_tag_array *entry = GET_ENTRY (ea);
+  int i = 0;
+
+  /* Cycles through all the possible ways an address could be at
+     and evicts the way if found */
+
+  for (i = 0; i < WAYS; i++)
+    {
+      if (CHECK_TAG (entry, i, tag))
+	{
+	  __cache_evict_entry (entry, i);
+	}
+    }
+}
+
+static void *
+__cache_fill (int way, addr tag)
+{
+  unsigned int oldmask, mach_stat;
+  char *line = ((void *) 0);
+
+  /* Reserve our DMA tag.  */
+  if (dma_tag == 32)
+    dma_tag = mfc_tag_reserve ();
+
+  /* Enter critical section.  */
+  mach_stat = spu_readch (SPU_RdMachStat);
+  spu_idisable ();
+
+  /* Issue DMA request.  */
+  line = GET_CACHE_LINE (tag, way);
+  mfc_get (line, tag, LINE_SIZE, dma_tag, 0, 0);
+
+  /* Wait for DMA completion.  */
+  oldmask = mfc_read_tag_mask ();
+  mfc_write_tag_mask (1 << dma_tag);
+  mfc_read_tag_status_all ();
+  mfc_write_tag_mask (oldmask);
+
+  /* Leave critical section.  */
+  if (__builtin_expect (mach_stat & 1, 0))
+    spu_ienable ();
+
+  return (void *) line;
+}
+
+static void
+__cache_miss (__ea void *ea, struct __cache_tag_array *entry, int way)
+{
+
+  addr tag = (eavoid_to_eanum (ea) & ~(TAG_MASK));
+  unsigned int lru = 0;
+  int i = 0;
+  int idx = 0;
+
+  /* If way > 4, then there are no empty slots, so we must evict
+     the least recently used entry. */
+  if (way >= 4)
+    {
+      for (i = 0; i < WAYS; i++)
+	{
+	  if (GET_LRU (entry, i) > lru)
+	    {
+	      lru = GET_LRU (entry, i);
+	      idx = i;
+	    }
+	}
+      __cache_evict_entry (entry, idx);
+      way = idx;
+    }
+
+  /* Set the empty entry's tag and fill it's cache line. */
+
+  SET_TAG (entry, way, tag);
+  entry->reserved[way] = 0;
+
+  /* Check if the address is just an effective address within the
+     SPU's local store. */
+
+  /* Because the LS is not 256k aligned, we can't do a nice and mask
+     here to compare, so we must check the whole range.  */
+
+  if ((eavoid_to_eanum (ea) >= (addr) __ea_local_store) &&
+      (eavoid_to_eanum (ea) < (addr) (__ea_local_store + 0x40000)))
+    {
+      SET_IS_LS (entry, way);
+      entry->base[way] =
+	(void *) ((unsigned int) (eavoid_to_eanum (ea) -
+				  (addr) __ea_local_store) & ~(0x7f));
+    }
+  else
+    {
+      entry->base[way] = __cache_fill (way, tag);
+    }
+}
+
+void *
+__cache_fetch_dirty (__ea void *ea, int n_bytes_dirty)
+{
+#ifdef __EA64__
+  unsigned int tag_hi;
+  qword etag_hi;
+#endif
+  unsigned int tag_lo;
+  struct __cache_tag_array *entry;
+
+  qword etag_lo;
+  qword equal;
+  qword bit_mask;
+  qword way;
+
+  /* This first chunk, we merely fill the pointer and tag.  */
+
+  entry = GET_ENTRY (ea);
+
+#ifndef __EA64__
+  tag_lo =
+    si_to_uint (si_andc
+		(si_shufb
+		 (si_from_eavoid (ea), si_from_uint (0),
+		  si_from_uint (0x00010203)), si_from_uint (TAG_MASK)));
+#else
+  tag_lo =
+    si_to_uint (si_andc
+		(si_shufb
+		 (si_from_eavoid (ea), si_from_uint (0),
+		  si_from_uint (0x04050607)), si_from_uint (TAG_MASK)));
+
+  tag_hi =
+    si_to_uint (si_shufb
+		(si_from_eavoid (ea), si_from_uint (0),
+		 si_from_uint (0x00010203)));
+#endif
+
+  /* Increment LRU in reserved bytes.  */
+  si_stqd (si_ai (si_lqd (si_from_ptr (entry), 48), 1),
+	   si_from_ptr (entry), 48);
+
+missreturn:
+  /* Check if the entry's lo_tag is equal to the address' lo_tag.  */
+  etag_lo = si_lqd (si_from_ptr (entry), 0);
+  equal = si_ceq (etag_lo, si_from_uint (tag_lo));
+#ifdef __EA64__
+  /* And the high tag too  */
+  etag_hi = si_lqd (si_from_ptr (entry), 16);
+  equal = si_and (equal, (si_ceq (etag_hi, si_from_uint (tag_hi))));
+#endif
+
+  if ((si_to_uint (si_orx (equal)) == 0))
+    goto misshandler;
+
+  if (n_bytes_dirty)
+    {
+      /* way = 0x40,0x50,0x60,0x70 for each way, which is also the
+         offset of the appropriate dirty bits.  */
+      way = si_shli (si_clz (si_gbb (equal)), 2);
+
+      /* To create the bit_mask, we set it to all 1s (uint -1), then we
+         shift it over (128 - n_bytes_dirty) times.  */
+
+      bit_mask = si_from_uint (-1);
+
+      bit_mask =
+	si_shlqby (bit_mask, si_from_uint ((LINE_SIZE - n_bytes_dirty) / 8));
+
+      bit_mask =
+	si_shlqbi (bit_mask, si_from_uint ((LINE_SIZE - n_bytes_dirty) % 8));
+
+      /* Rotate it around to the correct offset.  */
+      bit_mask =
+	si_rotqby (bit_mask,
+		   si_from_uint (-1 * (eavoid_to_eanum (ea) & TAG_MASK) / 8));
+
+      bit_mask =
+	si_rotqbi (bit_mask,
+		   si_from_uint (-1 * (eavoid_to_eanum (ea) & TAG_MASK) % 8));
+
+      /* Update the dirty bits.  */
+      si_stqx (si_or (si_lqx (si_from_ptr (entry), way), bit_mask),
+	       si_from_ptr (entry), way);
+    };
+
+  /* We've definitely found the right entry, set LRU (reserved) to 0
+     maintaining the LS flag (MSB). */
+
+  si_stqd (si_andc
+	   (si_lqd (si_from_ptr (entry), 48),
+	    si_and (equal, si_from_uint (~(LS_FLAG)))),
+	   si_from_ptr (entry), 48);
+
+  return (void *)
+    si_to_ptr (si_a
+	       (si_orx
+		(si_and (si_lqd (si_from_ptr (entry), 32), equal)),
+		si_from_uint (((unsigned int) (addr) ea) & TAG_MASK)));
+
+misshandler:
+  equal = si_ceqi (etag_lo, 1);
+  __cache_miss (ea, entry, (si_to_uint (si_clz (si_gbb (equal))) - 16) >> 2);
+  goto missreturn;
+}
+
+void *
+__cache_fetch (__ea void *ea)
+{
+  return __cache_fetch_dirty (ea, 0);
+}
+
+void
+__cache_touch (__ea void *ea __attribute__ ((unused)))
+{
+  /* NO-OP for now.  */
+}
+
+static void
+__cache_flush_stub (void)
+{
+  __cache_flush ();
+}
+
+void
+__cache_flush (void)
+{
+  struct __cache_tag_array *entry = __cache_tag_array;
+  unsigned int i = 0;
+  int j = 0;
+
+  /* Cycle through each cache entry and evict all used ways.  */
+
+  for (i = 0; i < (CACHE_LINES / WAYS); i++)
+    {
+      for (j = 0; j < WAYS; j++)
+	{
+	  if (!CHECK_EMPTY (entry, j))
+	    {
+	      __cache_evict_entry (entry, j);
+	    }
+	}
+      entry++;
+    }
+}
Index: gcc/config/spu/cache.S
===================================================================
--- gcc/config/spu/cache.S	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 0)
+++ gcc/config/spu/cache.S	(revision 143347)
@@ -0,0 +1,47 @@
+/* Copyright (C) 2008  Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
+
+.data
+.p2align 7
+.global __cache
+__cache:
+.rept __CACHE_SIZE__ * 8
+.fill 128
+.endr
+
+.p2align 7
+.global __cache_tag_array
+__cache_tag_array:
+.rept __CACHE_SIZE__ * 2
+.long 1, 1, 1, 1
+.fill 128-16
+.endr
+__end_cache_tag_array:
+
+.globl __cache_tag_array_size
+.set __cache_tag_array_size, __end_cache_tag_array-__cache_tag_array
Index: gcc/config/spu/spu-protos.h
===================================================================
--- gcc/config/spu/spu-protos.h	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/config/spu/spu-protos.h	(working copy)
@@ -54,8 +54,9 @@ extern int arith_immediate_p (rtx op, en
 extern int spu_constant_address_p (rtx x);
 extern int spu_legitimate_constant_p (rtx x);
 extern int spu_legitimate_address (enum machine_mode mode, rtx x,
-				   int reg_ok_strict);
-extern rtx spu_legitimize_address (rtx x, rtx oldx, enum machine_mode mode);
+				   int reg_ok_strict, addr_space_t);
+extern rtx spu_legitimize_address (rtx x, rtx oldx, enum machine_mode mode,
+				   addr_space_t);
 extern int spu_initial_elimination_offset (int from, int to);
 extern rtx spu_function_value (const_tree type, const_tree func);
 extern rtx spu_function_arg (int cum, enum machine_mode mode, tree type,
Index: gcc/config/spu/spu.c
===================================================================
--- gcc/config/spu/spu.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/config/spu/spu.c	(working copy)
@@ -143,6 +143,7 @@ static bool spu_vector_alignment_reachab
 static tree spu_builtin_vec_perm (tree, tree *);
 static int spu_sms_res_mii (struct ddg *g);
 static void asm_file_start (void);
+static bool spu_no_relocation (tree, tree);
 
 extern const char *reg_names[];
 rtx spu_compare_op0, spu_compare_op1;
@@ -203,9 +204,73 @@ spu_libgcc_shift_count_mode (void);
 
 /* Built in types.  */
 tree spu_builtin_types[SPU_BTI_MAX];
+
+/* Pointer mode for __ea references.  */
+#define EAmode (spu_ea_model != 32 ? DImode : SImode)
 
 /*  TARGET overrides.  */
 
+static enum machine_mode spu_addr_space_pointer_mode (addr_space_t);
+#undef TARGET_ADDR_SPACE_POINTER_MODE
+#define TARGET_ADDR_SPACE_POINTER_MODE spu_addr_space_pointer_mode
+
+static tree spu_addr_space_minus_type (addr_space_t, addr_space_t);
+#undef TARGET_ADDR_SPACE_MINUS_TYPE
+#define TARGET_ADDR_SPACE_MINUS_TYPE spu_addr_space_minus_type
+
+static const char *spu_addr_space_name (addr_space_t);
+#undef TARGET_ADDR_SPACE_NAME
+#define TARGET_ADDR_SPACE_NAME spu_addr_space_name
+
+static bool spu_addr_space_memory_address_p (enum machine_mode, rtx,
+					     addr_space_t);
+#undef TARGET_ADDR_SPACE_MEMORY_ADDRESS_P
+#define TARGET_ADDR_SPACE_MEMORY_ADDRESS_P spu_addr_space_memory_address_p
+
+static bool spu_addr_space_strict_memory_address_p (enum machine_mode, rtx,
+						    addr_space_t);
+#undef TARGET_ADDR_SPACE_STRICT_MEMORY_ADDRESS_P
+#define TARGET_ADDR_SPACE_STRICT_MEMORY_ADDRESS_P \
+  spu_addr_space_strict_memory_address_p
+
+#undef TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS
+#define TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS spu_legitimize_address
+
+static bool spu_addr_space_can_convert_p (addr_space_t, addr_space_t);
+#undef TARGET_ADDR_SPACE_CAN_CONVERT_P
+#define TARGET_ADDR_SPACE_CAN_CONVERT_P spu_addr_space_can_convert_p
+
+static bool spu_addr_space_nop_convert_p (addr_space_t, addr_space_t);
+#undef TARGET_ADDR_SPACE_NOP_CONVERT_P
+#define TARGET_ADDR_SPACE_NOP_CONVERT_P spu_addr_space_nop_convert_p
+
+static bool spu_addr_space_subset_p (addr_space_t, addr_space_t,
+				     addr_space_t *);
+#undef TARGET_ADDR_SPACE_SUBSET_P
+#define TARGET_ADDR_SPACE_SUBSET_P spu_addr_space_subset_p
+
+static rtx spu_addr_space_convert (rtx, enum machine_mode, addr_space_t,
+				   addr_space_t);
+#undef TARGET_ADDR_SPACE_CONVERT
+#define TARGET_ADDR_SPACE_CONVERT spu_addr_space_convert
+
+static tree spu_addr_space_section_name (addr_space_t);
+#undef TARGET_ADDR_SPACE_SECTION_NAME
+#define TARGET_ADDR_SPACE_SECTION_NAME spu_addr_space_section_name
+
+static bool spu_addr_space_static_init_ok_p (tree, tree, addr_space_t,
+					     addr_space_t);
+#undef TARGET_ADDR_SPACE_STATIC_INIT_OK_P
+#define TARGET_ADDR_SPACE_STATIC_INIT_OK_P spu_addr_space_static_init_ok_p
+
+static unsigned int spu_section_type_flags (tree, const char *, int);
+#undef TARGET_SECTION_TYPE_FLAGS
+#define TARGET_SECTION_TYPE_FLAGS spu_section_type_flags
+
+static bool spu_valid_pointer_mode (enum machine_mode mode);
+#undef TARGET_VALID_POINTER_MODE
+#define TARGET_VALID_POINTER_MODE spu_valid_pointer_mode
+
 #undef TARGET_INIT_BUILTINS
 #define TARGET_INIT_BUILTINS spu_init_builtins
 
@@ -215,10 +280,17 @@ tree spu_builtin_types[SPU_BTI_MAX];
 #undef TARGET_UNWIND_WORD_MODE
 #define TARGET_UNWIND_WORD_MODE spu_unwind_word_mode
 
-/* The .8byte directive doesn't seem to work well for a 32 bit
-   architecture. */
+#undef TARGET_ASM_ALIGNED_DI_OP
+#define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
+
+/* The current assembler doesn't like .4byte foo@ppu, so use the normal .long
+   and .quad for the debugger.  When it is known that the assembler is fixed,
+   these can be removed.  */
+#undef TARGET_ASM_UNALIGNED_SI_OP
+#define TARGET_ASM_UNALIGNED_SI_OP	"\t.long\t"
+
 #undef TARGET_ASM_UNALIGNED_DI_OP
-#define TARGET_ASM_UNALIGNED_DI_OP NULL
+#define TARGET_ASM_UNALIGNED_DI_OP	"\t.quad\t"
 
 #undef TARGET_RTX_COSTS
 #define TARGET_RTX_COSTS spu_rtx_costs
@@ -3435,6 +3507,20 @@ arith_immediate_p (rtx op, enum machine_
   return val >= low && val <= high;
 }
 
+/* Return true if X is a SYMBOL_REF to an __ea qualified variable.  */
+
+static int
+ea_symbol_ref (rtx *px, void *data ATTRIBUTE_UNUSED)
+{
+  rtx x = *px;
+  tree decl;
+
+  return (GET_CODE (x) == SYMBOL_REF
+ 	  && (decl = SYMBOL_REF_DECL (x)) != 0
+ 	  && TREE_CODE (decl) == VAR_DECL
+ 	  && TYPE_ADDR_SPACE (TREE_TYPE (decl)));
+}
+
 /* We accept:
    - any 32-bit constant (SImode, SFmode)
    - any constant that can be generated with fsmbi (any mode)
@@ -3446,19 +3532,27 @@ spu_legitimate_constant_p (rtx x)
 {
   if (GET_CODE (x) == HIGH)
     x = XEXP (x, 0);
-  /* V4SI with all identical symbols is valid. */
-  if (!flag_pic
-      && GET_MODE (x) == V4SImode
-      && (GET_CODE (CONST_VECTOR_ELT (x, 0)) == SYMBOL_REF
-	  || GET_CODE (CONST_VECTOR_ELT (x, 0)) == LABEL_REF
-	  || GET_CODE (CONST_VECTOR_ELT (x, 0)) == CONST))
-    return CONST_VECTOR_ELT (x, 0) == CONST_VECTOR_ELT (x, 1)
-	   && CONST_VECTOR_ELT (x, 1) == CONST_VECTOR_ELT (x, 2)
-	   && CONST_VECTOR_ELT (x, 2) == CONST_VECTOR_ELT (x, 3);
 
-  if (GET_CODE (x) == CONST_VECTOR
-      && !const_vector_immediate_p (x))
+  /* Reject any __ea qualified reference.  These can't appear in
+     instructions but must be forced to the constant pool.  */
+  if (for_each_rtx (&x, ea_symbol_ref, 0))
     return 0;
+
+  if (GET_CODE (x) == CONST_VECTOR)
+    {
+      /* V4SI with all identical symbols is valid. */
+      if (GET_CODE (CONST_VECTOR_ELT (x, 0)) == SYMBOL_REF
+ 	  || GET_CODE (CONST_VECTOR_ELT (x, 0)) == LABEL_REF
+ 	  || GET_CODE (CONST_VECTOR_ELT (x, 0)) == CONST)
+ 	return (!flag_pic
+ 		&& GET_MODE (x) == V4SImode
+ 		&& CONST_VECTOR_ELT (x, 0) == CONST_VECTOR_ELT (x, 1)
+ 		&& CONST_VECTOR_ELT (x, 1) == CONST_VECTOR_ELT (x, 2)
+ 		&& CONST_VECTOR_ELT (x, 2) == CONST_VECTOR_ELT (x, 3));
+
+      if (!const_vector_immediate_p (x))
+	return 0;
+    }
   return 1;
 }
 
@@ -3472,18 +3566,31 @@ spu_legitimate_constant_p (rtx x)
   preferable to allow any alignment and fix it up when splitting.) */
 int
 spu_legitimate_address (enum machine_mode mode ATTRIBUTE_UNUSED,
-			rtx x, int reg_ok_strict)
+			rtx x, int reg_ok_strict,
+			addr_space_t as)
 {
+  if (as == ADDR_SPACE_EA)
+    return (REG_P (x) && (GET_MODE (x) == EAmode));
+
+  else if (as != ADDR_SPACE_GENERIC)
+    gcc_unreachable ();
+
   if (mode == TImode && GET_CODE (x) == AND
       && GET_CODE (XEXP (x, 1)) == CONST_INT
       && INTVAL (XEXP (x, 1)) == (HOST_WIDE_INT) -16)
     x = XEXP (x, 0);
   switch (GET_CODE (x))
     {
-    case SYMBOL_REF:
     case LABEL_REF:
       return !TARGET_LARGE_MEM;
 
+    case SYMBOL_REF:
+      /* Keep __ea references until reload so that spu_expand_mov
+         can see them in MEMs.  */
+      if (ea_symbol_ref (&x, 0))
+        return !reload_in_progress && !reload_completed;
+      return !TARGET_LARGE_MEM;
+
     case CONST:
       if (!TARGET_LARGE_MEM && GET_CODE (XEXP (x, 0)) == PLUS)
 	{
@@ -3493,6 +3600,10 @@ spu_legitimate_address (enum machine_mod
 	  /* Accept any symbol_ref + constant, assuming it does not
 	     wrap around the local store addressability limit.  */
 	  if (GET_CODE (sym) == SYMBOL_REF && GET_CODE (cst) == CONST_INT)
+	    {
+ 	      if (ea_symbol_ref (&sym, 0))
+ 		return 0;
+	    }
 	    return 1;
 	}
       return 0;
@@ -3545,9 +3656,13 @@ spu_legitimate_address (enum machine_mod
    register.  */
 rtx
 spu_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
-			enum machine_mode mode)
+			enum machine_mode mode, addr_space_t as)
 {
   rtx op0, op1;
+				 
+  if (as != ADDR_SPACE_GENERIC)
+    return NULL_RTX;
+
   /* Make sure both operands are registers.  */
   if (GET_CODE (x) == PLUS)
     {
@@ -3568,7 +3683,7 @@ spu_legitimize_address (rtx x, rtx oldx 
       else if (GET_CODE (op1) != REG)
 	op1 = force_reg (Pmode, op1);
       x = gen_rtx_PLUS (Pmode, op0, op1);
-      if (spu_legitimate_address (mode, x, 0))
+      if (spu_legitimate_address (mode, x, 0, as))
 	return x;
     }
   return NULL_RTX;
@@ -4101,6 +4216,237 @@ store_with_one_insn_p (rtx mem)
   return 0;
 }
 
+static GTY(()) rtx cache_fetch;		  /* __cache_fetch function */
+static GTY(()) rtx cache_fetch_dirty;	  /* __cache_fetch_dirty function */
+static alias_set_type ea_alias_set = -1;  /* alias set for __ea memory */
+
+/* MEM is known to be an __ea qualified memory access.  Emit a call to
+   fetch the ppu memory to local store, and return its address in local
+   store.  */
+
+static void
+ea_load_store (rtx mem, bool is_store, rtx ea_addr, rtx data_addr)
+{
+  if (is_store)
+    {
+      rtx ndirty = GEN_INT (GET_MODE_SIZE (GET_MODE (mem)));
+      if (!cache_fetch_dirty)
+	cache_fetch_dirty = init_one_libfunc ("__cache_fetch_dirty");
+      emit_library_call_value (cache_fetch_dirty, data_addr, LCT_NORMAL, Pmode,
+			       2, ea_addr, EAmode, ndirty, SImode);
+    }
+  else
+    {
+      if (!cache_fetch)
+	cache_fetch = init_one_libfunc ("__cache_fetch");
+      emit_library_call_value (cache_fetch, data_addr, LCT_NORMAL, Pmode,
+			       1, ea_addr, EAmode);
+    }
+}
+
+/* Like ea_load_store, but do the cache tag comparison and, for stores,
+   dirty bit marking, inline.
+
+   The cache control data structure is an array of
+
+   struct __cache_tag_array
+     {
+        unsigned int tag_lo[4];
+        unsigned int tag_hi[4];
+        void *data_pointer[4];
+        int reserved[4];
+        vector unsigned short dirty_bits[4];
+     }  */
+
+static void
+ea_load_store_inline (rtx mem, bool is_store, rtx ea_addr, rtx data_addr)
+{
+  rtx ea_addr_si;
+  HOST_WIDE_INT v;
+  rtx tag_size_sym = gen_rtx_SYMBOL_REF (Pmode, "__cache_tag_array_size");
+  rtx tag_arr_sym = gen_rtx_SYMBOL_REF (Pmode, "__cache_tag_array");
+  rtx index_mask = gen_reg_rtx (SImode);
+  rtx tag_arr = gen_reg_rtx (Pmode);
+  rtx splat_mask = gen_reg_rtx (TImode);
+  rtx splat = gen_reg_rtx (V4SImode);
+  rtx splat_hi = NULL_RTX;
+  rtx tag_index = gen_reg_rtx (Pmode);
+  rtx block_off = gen_reg_rtx (SImode);
+  rtx tag_addr = gen_reg_rtx (Pmode);
+  rtx tag = gen_reg_rtx (V4SImode);
+  rtx cache_tag = gen_reg_rtx (V4SImode);
+  rtx cache_tag_hi = NULL_RTX;
+  rtx cache_ptrs = gen_reg_rtx (TImode);
+  rtx cache_ptrs_si = gen_reg_rtx (SImode);
+  rtx tag_equal = gen_reg_rtx (V4SImode);
+  rtx tag_equal_hi = NULL_RTX;
+  rtx tag_eq_pack = gen_reg_rtx (V4SImode);
+  rtx tag_eq_pack_si = gen_reg_rtx (SImode);
+  rtx eq_index = gen_reg_rtx (SImode);
+  rtx bcomp, hit_label, hit_ref, cont_label, insn;
+
+  if (spu_ea_model != 32)
+    {
+      splat_hi = gen_reg_rtx (V4SImode);
+      cache_tag_hi = gen_reg_rtx (V4SImode);
+      tag_equal_hi = gen_reg_rtx (V4SImode);
+    }
+
+  emit_move_insn (index_mask, plus_constant (tag_size_sym, -128));
+  emit_move_insn (tag_arr, tag_arr_sym);
+  v = 0x0001020300010203LL;
+  emit_move_insn (splat_mask, immed_double_const (v, v, TImode));
+  ea_addr_si = ea_addr;
+  if (spu_ea_model != 32)
+    ea_addr_si = convert_to_mode (SImode, ea_addr, 1);
+
+  /* tag_index = ea_addr & (tag_array_size - 128)  */
+  emit_insn (gen_andsi3 (tag_index, ea_addr_si, index_mask));
+
+  /* splat ea_addr to all 4 slots.  */
+  emit_insn (gen_shufb (splat, ea_addr_si, ea_addr_si, splat_mask));
+  /* Similarly for high 32 bits of ea_addr.  */
+  if (spu_ea_model != 32)
+    emit_insn (gen_shufb (splat_hi, ea_addr, ea_addr, splat_mask));
+
+  /* block_off = ea_addr & 127  */
+  emit_insn (gen_andsi3 (block_off, ea_addr_si, spu_const (SImode, 127)));
+
+  /* tag_addr = tag_arr + tag_index  */
+  emit_insn (gen_addsi3 (tag_addr, tag_arr, tag_index));
+
+  /* Read cache tags.  */
+  emit_move_insn (cache_tag, gen_rtx_MEM (V4SImode, tag_addr));
+  if (spu_ea_model != 32)
+    emit_move_insn (cache_tag_hi, gen_rtx_MEM (V4SImode,
+					       plus_constant (tag_addr, 16)));
+
+  /* tag = ea_addr & -128  */
+  emit_insn (gen_andv4si3 (tag, splat, spu_const (V4SImode, -128)));
+
+  /* Read all four cache data pointers.  */
+  emit_move_insn (cache_ptrs, gen_rtx_MEM (TImode,
+					   plus_constant (tag_addr, 32)));
+
+  /* Compare tags.  */
+  emit_insn (gen_ceq_v4si (tag_equal, tag, cache_tag));
+  if (spu_ea_model != 32)
+    {
+      emit_insn (gen_ceq_v4si (tag_equal_hi, splat_hi, cache_tag_hi));
+      emit_insn (gen_andv4si3 (tag_equal, tag_equal, tag_equal_hi));
+    }
+
+  /* At most one of the tags compare equal, so tag_equal has one
+     32-bit slot set to all 1's, with the other slots all zero.
+     gbb picks off low bit from each byte in the 128-bit registers,
+     so tag_eq_pack is one of 0xf000, 0x0f00, 0x00f0, 0x000f, assuming
+     we have a hit.  */
+  emit_insn (gen_spu_gbb (tag_eq_pack, spu_gen_subreg (V16QImode, tag_equal)));
+  emit_insn (gen_spu_convert (tag_eq_pack_si, tag_eq_pack));
+
+  /* So counting leading zeros will set eq_index to 16, 20, 24 or 28.  */
+  emit_insn (gen_clzsi2 (eq_index, tag_eq_pack_si));
+
+  /* Allowing us to rotate the corresponding cache data pointer to slot0.
+     (rotating eq_index mod 16 bytes).  */
+  emit_insn (gen_rotqby_ti (cache_ptrs, cache_ptrs, eq_index));
+  emit_insn (gen_spu_convert (cache_ptrs_si, cache_ptrs));
+
+  /* Add block offset to form final data address.  */
+  emit_insn (gen_addsi3 (data_addr, cache_ptrs_si, block_off));
+
+  /* Check that we did hit.  */
+  hit_label = gen_label_rtx ();
+  hit_ref = gen_rtx_LABEL_REF (VOIDmode, hit_label);
+  bcomp = gen_rtx_NE (SImode, tag_eq_pack_si, const0_rtx);
+  insn = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
+				      gen_rtx_IF_THEN_ELSE (VOIDmode, bcomp,
+							    hit_ref, pc_rtx)));
+  /* Say that this branch is very likely to happen.  */
+  v = REG_BR_PROB_BASE - REG_BR_PROB_BASE / 100 - 1;
+  REG_NOTES (insn)
+    = gen_rtx_EXPR_LIST (REG_BR_PROB, GEN_INT (v), REG_NOTES (insn));
+
+  ea_load_store (mem, is_store, ea_addr, data_addr);
+  cont_label = gen_label_rtx ();
+  emit_jump_insn (gen_jump (cont_label));
+  emit_barrier ();
+
+  emit_label (hit_label);
+
+  if (is_store)
+    {
+      HOST_WIDE_INT v_hi;
+      rtx dirty_bits = gen_reg_rtx (TImode);
+      rtx dirty_off = gen_reg_rtx (SImode);
+      rtx dirty_128 = gen_reg_rtx (TImode);
+      rtx neg_block_off = gen_reg_rtx (SImode);
+
+      /* Set up mask with one dirty bit per byte of the mem we are
+	 writing, starting from top bit.  */
+      v_hi = v = -1;
+      v <<= (128 - GET_MODE_SIZE (GET_MODE (mem))) & 63;
+      if ((128 - GET_MODE_SIZE (GET_MODE (mem))) >= 64)
+	{
+	  v_hi = v;
+	  v = 0;
+	}
+      emit_move_insn (dirty_bits, immed_double_const (v, v_hi, TImode));
+
+      /* Form index into cache dirty_bits.  eq_index is one of
+	 0x10, 0x14, 0x18 or 0x1c.  Multiplying by 4 gives us
+	 0x40, 0x50, 0x60 or 0x70 which just happens to be the
+	 offset to each of the four dirty_bits elements.  */
+      emit_insn (gen_ashlsi3 (dirty_off, eq_index, spu_const (SImode, 2)));
+
+      emit_insn (gen_spu_lqx (dirty_128, tag_addr, dirty_off));
+
+      /* Rotate bit mask to proper bit.  */
+      emit_insn (gen_negsi2 (neg_block_off, block_off));
+      emit_insn (gen_rotqbybi_ti (dirty_bits, dirty_bits, neg_block_off));
+      emit_insn (gen_rotqbi_ti (dirty_bits, dirty_bits, neg_block_off));
+
+      /* Or in the new dirty bits.  */
+      emit_insn (gen_iorti3 (dirty_128, dirty_bits, dirty_128));
+
+      /* Store.  */
+      emit_insn (gen_spu_stqx (dirty_128, tag_addr, dirty_off));
+    }
+
+  emit_label (cont_label);
+}
+
+static rtx
+expand_ea_mem (rtx mem, bool is_store)
+{
+  rtx ea_addr;
+  rtx data_addr = gen_reg_rtx (Pmode);
+  rtx new_mem;
+
+  ea_addr = force_reg (EAmode, XEXP (mem, 0));
+  if (optimize_size || optimize == 0)
+    ea_load_store (mem, is_store, ea_addr, data_addr);
+  else
+    ea_load_store_inline (mem, is_store, ea_addr, data_addr);
+
+  if (ea_alias_set == -1)
+    ea_alias_set = new_alias_set ();
+
+  new_mem = change_address_addr_space (mem, VOIDmode, data_addr,
+				       ADDR_SPACE_GENERIC);
+
+  /* We can't just change the alias set directly to ea_alias_set, because the
+     --enable-checking code may complain that the alias sets don't conflict */
+  set_mem_alias_set (new_mem, 0);
+  set_mem_alias_set (new_mem, ea_alias_set);
+
+  /* Manually reset the address space of the pointer back to the generic
+     address space.  */
+  set_mem_addr_space (new_mem, ADDR_SPACE_GENERIC);
+
+  return new_mem;
+}
+
 int
 spu_expand_mov (rtx * ops, enum machine_mode mode)
 {
@@ -4150,6 +4496,8 @@ spu_expand_mov (rtx * ops, enum machine_
     {
       if (GET_CODE (ops[0]) == MEM)
 	{
+ 	  if (MEM_ADDR_SPACE (ops[0]))
+ 	    ops[0] = expand_ea_mem (ops[0], true);
 	  if (!spu_valid_move (ops))
 	    {
 	      emit_insn (gen_store (ops[0], ops[1], gen_reg_rtx (TImode),
@@ -4159,6 +4507,8 @@ spu_expand_mov (rtx * ops, enum machine_
 	}
       else if (GET_CODE (ops[1]) == MEM)
 	{
+ 	  if (MEM_ADDR_SPACE (ops[1]))
+ 	    ops[1] = expand_ea_mem (ops[1], false);
 	  if (!spu_valid_move (ops))
 	    {
 	      emit_insn (gen_load
@@ -4524,6 +4874,7 @@ spu_valid_move (rtx * ops)
      the direct_load[] and direct_store[] arrays.  We always want to
      consider those loads and stores valid.  init_expr_once is called in
      the context of a dummy function which does not have a decl. */
+  gcc_assert (cfun);
   if (cfun->decl == 0)
     return 1;
 
@@ -6154,6 +6505,23 @@ spu_vector_alignment_reachable (const_tr
   return true;
 }
 
+/* Return valid pointer modes.  */
+static bool
+spu_valid_pointer_mode (enum machine_mode mode)
+{
+  return (mode == ptr_mode || mode == Pmode ||
+	  (spu_ea_model != 32 && mode == DImode));
+}
+
+/* Adjust section flags for the __ea section.  */
+static unsigned int
+spu_section_type_flags (tree decl, const char *name, int reloc)
+{
+  if (strcmp (name, "._ea") == 0)
+    return SECTION_WRITE | SECTION_DEBUG;
+  return default_section_type_flags (decl, name, reloc);
+}
+
 /* Implement targetm.vectorize.builtin_vec_perm.  */
 tree
 spu_builtin_vec_perm (tree type, tree *mask_element_type)
@@ -6267,6 +6635,260 @@ spu_libgcc_shift_count_mode (void)
   return SImode;
 }
 
+/* Return the appropriate mode for a named address pointer.  */
+static enum machine_mode
+spu_addr_space_pointer_mode (addr_space_t addrspace)
+{
+  switch (addrspace)
+    {
+    case ADDR_SPACE_GENERIC:
+      return ptr_mode;
+    case ADDR_SPACE_EA:
+      return (EAmode);
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Return the appropriate type for subtracting two pointers.  */
+static tree
+spu_addr_space_minus_type (addr_space_t as1, addr_space_t as2)
+{
+  gcc_assert (as1 == ADDR_SPACE_GENERIC || as1 == ADDR_SPACE_EA);
+  gcc_assert (as2 == ADDR_SPACE_GENERIC || as2 == ADDR_SPACE_EA);
+
+  if (as1 == ADDR_SPACE_GENERIC && as2 == ADDR_SPACE_GENERIC)
+    return ptrdiff_type_node;
+
+  else if (spu_ea_model == 32)
+    return ptrdiff_type_node;
+
+  else
+    return unsigned_intDI_type_node;
+}
+
+/* Map an address space number into a name.  */
+static const char *
+spu_addr_space_name (addr_space_t addrspace)
+{
+  if (addrspace == ADDR_SPACE_EA)
+    return "__ea";
+
+  gcc_unreachable ();
+}
+
+/* Return if an address is valid for a given mode that points to a given named
+   address space.  */
+
+static bool
+spu_addr_space_memory_address_p (enum machine_mode mode, rtx x,
+				 addr_space_t as)
+{
+  gcc_assert (as == ADDR_SPACE_GENERIC || as == ADDR_SPACE_EA);
+  return spu_legitimate_address (mode, x, 0, as);
+}
+
+/* Return if an address is valid for a given mode that points to a given named
+   address space after register allocation has been done.  */
+
+static bool
+spu_addr_space_strict_memory_address_p (enum machine_mode mode, rtx x,
+					addr_space_t as)
+{
+  gcc_assert (as == ADDR_SPACE_GENERIC || as == ADDR_SPACE_EA);
+  return spu_legitimate_address (mode, x, 1, as);
+}
+
+/* Determine if you can convert one address to another.  */
+
+static bool
+spu_addr_space_can_convert_p (addr_space_t from, addr_space_t to)
+{
+  gcc_assert (from == ADDR_SPACE_GENERIC || from == ADDR_SPACE_EA);
+  gcc_assert (to == ADDR_SPACE_GENERIC || to == ADDR_SPACE_EA);
+
+  if (TARGET_NO_EA_TO_GENERIC_CONVERSION
+      && from == ADDR_SPACE_EA
+      && to == ADDR_SPACE_GENERIC)
+    return false;
+
+  return true;
+}
+
+/* Determine if converting one address to another is a NOP.  */
+
+static bool
+spu_addr_space_nop_convert_p (addr_space_t from, addr_space_t to)
+{
+  gcc_assert (from == ADDR_SPACE_GENERIC || from == ADDR_SPACE_EA);
+  gcc_assert (to == ADDR_SPACE_GENERIC || to == ADDR_SPACE_EA);
+  return (to == from);
+}
+
+/* Determine if one named address space is a subset of another.  */
+
+static bool
+spu_addr_space_subset_p (addr_space_t as1,
+			 addr_space_t as2,
+			 addr_space_t *common_as)
+{
+  gcc_assert (as1 == ADDR_SPACE_GENERIC || as1 == ADDR_SPACE_EA);
+  gcc_assert (as2 == ADDR_SPACE_GENERIC || as2 == ADDR_SPACE_EA);
+
+  if (as1 == as2)
+    {
+      *common_as = as1;
+      return true;
+    }
+
+  /* If we have -mno-address-space-conversion, treat __ea and generic as not
+     being subsets but instead as disjoint address spaces.  This will require
+     the user to explicitly convert between the different address spaces,
+     instead of relying on the compiler to do it automatically.  */
+  else if (TARGET_NO_ADDRESS_SPACE_CONVERSION)
+    {
+      *common_as = ADDR_SPACE_BAD;
+      return false;
+    }
+
+  else
+    {
+      *common_as = ADDR_SPACE_EA;
+      return true;
+    }
+}
+
+/* Convert from one address space to another.  */
+static rtx
+spu_addr_space_convert (rtx op,
+			enum machine_mode mode,
+			addr_space_t from,
+			addr_space_t to)
+{
+  rtx reg;
+
+  gcc_assert (from == ADDR_SPACE_GENERIC || from == ADDR_SPACE_EA);
+  gcc_assert (to == ADDR_SPACE_GENERIC || to == ADDR_SPACE_EA);
+
+  if (to == from)
+    return op;
+
+  else if (to == ADDR_SPACE_GENERIC && from == ADDR_SPACE_EA)
+    {
+      reg = gen_reg_rtx (mode);
+      emit_insn (gen_from_ea (reg, op));
+      return reg;
+    }
+
+  else if (to == ADDR_SPACE_EA && from == ADDR_SPACE_GENERIC)
+    {
+      reg = gen_reg_rtx (mode);
+      emit_insn (gen_to_ea (reg, op));
+      return reg;
+    }
+
+  else
+    gcc_unreachable ();
+
+  return 0;
+}
+
+static GTY(()) tree spu_ea_name;
+
+static tree
+spu_addr_space_section_name (addr_space_t addrspace)
+{
+  gcc_assert (addrspace == ADDR_SPACE_EA);
+
+  if (!spu_ea_name)
+    spu_ea_name = build_string (4, "._ea");
+
+  return spu_ea_name;
+}
+
+/* Return true if the tree contains any elements that require relocation that
+   would not be allowed to initialize a __ea memory address space.  */
+
+static bool
+spu_no_relocation (tree type, tree init)
+{
+  bool ret;
+  unsigned HOST_WIDE_INT idx;
+  tree value;
+  tree field;
+
+  switch (TREE_CODE (init))
+    {
+    default:
+      ret = false;
+      break;
+
+      /* Constants are not relocatable.  */
+    case REAL_CST:
+    case FIXED_CST:
+    case COMPLEX_CST:
+    case INTEGER_CST:
+      ret = true;
+      break;
+
+      /* Strings are ok if we are initializing a char array of some sort.  */
+    case STRING_CST:
+      ret = (type != NULL_TREE
+	     && TREE_CODE (type) == ARRAY_TYPE
+	     && TYPE_STRING_FLAG (TREE_TYPE (type)));
+      break;
+
+      /* Support a limited number of conversions.  */
+    case CONVERT_EXPR:
+    case NOP_EXPR:
+      ret = spu_no_relocation (type, TREE_OPERAND (init, 0));
+      break;
+
+      /* Decode the constructor.  */
+    case CONSTRUCTOR:
+      ret = true;
+      FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), idx, field, value)
+	{
+	  if (value && !spu_no_relocation (TREE_TYPE (field), value))
+	    {
+	      ret = false;
+	      break;
+	    }
+	}
+      break;
+    }
+
+  return ret;
+}
+
+static bool
+spu_addr_space_static_init_ok_p (tree type,
+				 tree init,
+				 addr_space_t as,
+				 addr_space_t as_ptr)
+{
+  bool ret;
+
+  if (init == error_mark_node)
+    ret = false;
+
+  /* Normal initializations are ok.  */
+  else if (as == ADDR_SPACE_GENERIC && as_ptr == ADDR_SPACE_GENERIC)
+    ret = true;
+
+  else
+    {
+      /* Don't allow things that need relocations in or pointing to the __ea
+	 address space.  */
+      gcc_assert (as == ADDR_SPACE_GENERIC || as == ADDR_SPACE_EA);
+      gcc_assert (as_ptr == ADDR_SPACE_GENERIC || as_ptr == ADDR_SPACE_EA);
+
+      ret = spu_no_relocation (type, init);
+    }
+
+  return ret;
+}
+
 /* An early place to adjust some flags after GCC has finished processing
  * them. */
 static void
@@ -6280,3 +6902,5 @@ asm_file_start (void)
   default_file_start ();
 }
 
+
+#include "gt-spu.h"
Index: gcc/config/spu/spu.h
===================================================================
--- gcc/config/spu/spu.h	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/config/spu/spu.h	(working copy)
@@ -423,12 +423,14 @@ targetm.resolve_overloaded_builtin = spu
 #endif
 
 #define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR)			\
-    { if (spu_legitimate_address (MODE, X, REG_OK_STRICT_FLAG))	\
+    { if (spu_legitimate_address (MODE, X, REG_OK_STRICT_FLAG,	\
+				  ADDR_SPACE_GENERIC))		\
 	goto ADDR;						\
     }
 
-#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \
-  {  rtx result = spu_legitimize_address (X, OLDX, MODE);	\
+#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN)			\
+  {  rtx result = spu_legitimize_address (X, OLDX, MODE,	\
+					  ADDR_SPACE_GENERIC);	\
      if (result != NULL_RTX)					\
        {							\
 	 (X) = result;						\
@@ -454,9 +456,9 @@ targetm.resolve_overloaded_builtin = spu
 
 /* Sections */
 
-#define TEXT_SECTION_ASM_OP ".text"
+#define TEXT_SECTION_ASM_OP "\t.text"
 
-#define DATA_SECTION_ASM_OP ".data"
+#define DATA_SECTION_ASM_OP "\t.data"
 
 #define JUMP_TABLES_IN_TEXT_SECTION 1
 
@@ -497,6 +499,17 @@ targetm.resolve_overloaded_builtin = spu
 #define ASM_OUTPUT_LABELREF(FILE, NAME) \
   asm_fprintf (FILE, "%U%s", default_strip_name_encoding (NAME))
 
+#define ASM_OUTPUT_SYMBOL_REF(FILE, X) \
+  do									\
+    {									\
+      tree decl;							\
+      assemble_name (FILE, XSTR (X, 0));				\
+      if ((decl = SYMBOL_REF_DECL (X)) != 0				\
+	  && TREE_CODE (decl) == VAR_DECL				\
+	  && TYPE_ADDR_SPACE (strip_array_types (TREE_TYPE (decl))))	\
+	fputs ("@ppu", FILE);					\
+    } while (0)
+
 
 /* Instruction Output */
 #define REGISTER_NAMES \
@@ -622,3 +635,10 @@ targetm.resolve_overloaded_builtin = spu
 extern GTY(()) rtx spu_compare_op0;
 extern GTY(()) rtx spu_compare_op1;
 
+/* Address spaces */
+#define ADDR_SPACE_GENERIC	0
+#define ADDR_SPACE_EA		1
+#define ADDR_SPACE_BAD		255
+
+/* Named address space keywords.  */
+#define TARGET_ADDR_SPACE_KEYWORDS  ADDR_SPACE_KEYWORD("__ea", ADDR_SPACE_EA)
Index: gcc/config/spu/spu-elf.h
===================================================================
--- gcc/config/spu/spu-elf.h	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/config/spu/spu-elf.h	(working copy)
@@ -66,10 +66,26 @@
 
 #define EH_FRAME_IN_DATA_SECTION 1
 
+#define DRIVER_SELF_SPECS "\
+  %{mcache-size=128   : -lgcc_cache128k ; \
+    mcache-size=64    : -lgcc_cache64k ; \
+    mcache-size=32    : -lgcc_cache32k ; \
+    mcache-size=16    : -lgcc_cache16k ; \
+    mcache-size=8     : -lgcc_cache8k ; \
+    		      : -lgcc_cache64k } \
+  %<mcache-size=* \
+  %{mno-atomic-updates:-lgcc_cachemgr_nonatomic; :-lgcc_cachemgr} \
+  %<matomic-updates %<mno-atomic-updates"
+
 #define LINK_SPEC "%{mlarge-mem: --defsym __stack=0xfffffff0 }"
 
-#define LIB_SPEC \
-	"-( %{!shared:%{g*:-lg}} -lc -lgloss -)"
+/* Match each of the mutually exclusive cache<n>k libraries because
+   lgcc_cache* did not seem to work -- perhaps a bug in the specs
+   handling?  */
+#define LIB_SPEC "-( %{!shared:%{g*:-lg}} -lc -lgloss -) \
+    %{lgcc_cachemgr*:-lgcc_cachemgr%*} \
+    %{lgcc_cache128k} %{lgcc_cache64k} %{lgcc_cache32k} \
+    %{lgcc_cache16k} %{lgcc_cache8k}"
 
 /* Turn off warnings in the assembler too. */
 #undef ASM_SPEC
Index: gcc/config/spu/spu.md
===================================================================
--- gcc/config/spu/spu.md	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/config/spu/spu.md	(working copy)
@@ -5238,3 +5238,45 @@ DONE;
    (set_attr "type" "multi1")]
 )
 
+(define_expand "to_ea"
+  [(use (match_operand 0 "" ""))
+   (use (match_operand 1 "" ""))]
+  ""
+{
+  rtx ls_mem, op0, op1;
+  enum machine_mode mode = (spu_ea_model == 32) ? Pmode : DImode;
+
+  ls_mem = gen_rtx_MEM (DImode, gen_rtx_SYMBOL_REF (Pmode, "__ea_local_store"));
+
+  op0 = force_reg (mode, operands[0]);
+  op1 = force_reg (Pmode, operands[1]);
+
+  if (mode == Pmode)
+    emit_insn (gen_addsi3 (op0, op1, force_reg (mode, gen_lowpart (mode, ls_mem))));
+  else
+    {
+      rtx tmp = gen_reg_rtx (DImode);
+      emit_move_insn (tmp, gen_rtx_ZERO_EXTEND (DImode, op1));
+      emit_insn (gen_adddi3 (op0, tmp, force_reg (mode, ls_mem)));
+    }
+  DONE;
+})
+
+(define_expand "from_ea"
+  [(use (match_operand 0 "" ""))
+   (use (match_operand 1 "" ""))]
+  ""
+{
+  rtx ls_mem, ls, op0, op1, tmp;
+  enum machine_mode mode = (spu_ea_model == 32) ? Pmode : DImode;
+
+  ls_mem = gen_rtx_MEM (DImode, gen_rtx_SYMBOL_REF (Pmode, "__ea_local_store"));
+  ls = force_reg (Pmode, gen_lowpart (Pmode, ls_mem));
+
+  op0 = force_reg (Pmode, operands[0]);
+  op1 = force_reg (mode, operands[1]);
+  tmp = (mode == Pmode) ? op1 : force_reg (Pmode, gen_lowpart (Pmode, op1));
+
+  emit_insn (gen_subsi3 (op0, tmp, ls));
+  DONE;
+})
Index: gcc/config/spu/spu-c.c
===================================================================
--- gcc/config/spu/spu-c.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/config/spu/spu-c.c	(working copy)
@@ -198,6 +198,17 @@ spu_cpu_cpp_builtins (struct cpp_reader 
   if (spu_arch == PROCESSOR_CELLEDP)
     builtin_define_std ("__SPU_EDP__");
   builtin_define_std ("__vector=__attribute__((__spu_vector__))");
+  switch (spu_ea_model)
+    {
+    case 32:
+      builtin_define_std ("__EA32__");
+      break;
+    case 64:
+      builtin_define_std ("__EA64__");
+      break;
+    default:
+       gcc_unreachable ();
+    }
 
   if (!flag_iso)
     {
Index: gcc/config/spu/spu.opt
===================================================================
--- gcc/config/spu/spu.opt	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/config/spu/spu.opt	(working copy)
@@ -82,3 +82,30 @@ Generate code for given CPU
 mtune=
 Target RejectNegative Joined Var(spu_tune_string)
 Schedule code for given CPU
+
+mea32
+Target Report RejectNegative Var(spu_ea_model,32) Init(32)
+Access variables in 32-bit PPU objects
+
+mea64
+Target Report RejectNegative Var(spu_ea_model,64) VarExists
+Access variables in 64-bit PPU objects
+
+mno-ea-to-generic-conversion
+Target Report RejectNegative Mask(NO_EA_TO_GENERIC_CONVERSION)
+Don't allow pointers in the __ea address space to be converted to generic pointers.
+
+mea-to-generic-conversion
+Target Report RejectNegative InverseMask(NO_EA_TO_GENERIC_CONVERSION)
+Allow pointers in the __ea address space to be converted to local pointers (default).
+
+mno-address-space-conversion
+Target Report RejectNegative Mask(NO_ADDRESS_SPACE_CONVERSION)
+Do not allow automatic conversion between pointers to different named address
+spaces (__ea and generic) without an explicit cast.
+
+maddress-space-conversion
+Target Report RejectNegative InverseMask(NO_ADDRESS_SPACE_CONVERSION)
+Allow automatic conversion between pointers to different named address spaces
+(__ea and generic) without an explicit cast.
+
Index: gcc/config/spu/t-spu-elf
===================================================================
--- gcc/config/spu/t-spu-elf	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/config/spu/t-spu-elf	(working copy)
@@ -62,13 +62,40 @@ fp-bit.c: $(srcdir)/config/fp-bit.c $(sr
 CRTSTUFF_T_CFLAGS =
 
 #MULTILIB_OPTIONS=mlarge-mem/mtest-abi
+MULTILIB_OPTIONS=mea64
 #MULTILIB_DIRNAMES=large-mem test-abi
 #MULTILIB_MATCHES=
 
 # Neither gcc or newlib seem to have a standard way to generate multiple
 # crt*.o files.  So we don't use the standard crt0.o name anymore.
 
-EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o
+EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o libgcc_cachemgr.a libgcc_cachemgr_nonatomic.a \
+	libgcc_cache8k.a libgcc_cache16k.a libgcc_cache32k.a libgcc_cache64k.a libgcc_cache128k.a
+
+$(T)cachemgr.o: $(srcdir)/config/spu/cachemgr.c
+	$(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(MULTILIB_CFLAGS) -c $< -o $@
+
+# Specialised rule to add a -D flag.
+$(T)cachemgr_nonatomic.o: $(srcdir)/config/spu/cachemgr.c
+	$(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(MULTILIB_CFLAGS) -DNONATOMIC -c $< -o $@
+
+$(T)libgcc_%.a: $(T)%.o
+	$(AR_FOR_TARGET) -rcs $@ $<
+
+$(T)cache8k.o: $(srcdir)/config/spu/cache.S
+	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -D__CACHE_SIZE__=8 -o $@ -c $<
+
+$(T)cache16k.o: $(srcdir)/config/spu/cache.S
+	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -D__CACHE_SIZE__=16 -o $@ -c $<
+
+$(T)cache32k.o: $(srcdir)/config/spu/cache.S
+	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -D__CACHE_SIZE__=32 -o $@ -c $<
+
+$(T)cache64k.o: $(srcdir)/config/spu/cache.S
+	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -D__CACHE_SIZE__=64 -o $@ -c $<
+
+$(T)cache128k.o: $(srcdir)/config/spu/cache.S
+	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -D__CACHE_SIZE__=128 -o $@ -c $<
 
 LIBGCC = stmp-multilib
 INSTALL_LIBGCC = install-multilib
Index: gcc/targhooks.c
===================================================================
--- gcc/targhooks.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/targhooks.c	(working copy)
@@ -712,6 +712,152 @@ default_builtin_vector_alignment_reachab
   return true;
 }
 
+/* Determine whether or not a pointer mode is valid. Assume defaults
+   of ptr_mode or Pmode - can be overridden.  */
+bool
+default_valid_pointer_mode (enum machine_mode mode)
+{
+  return (mode == ptr_mode || mode == Pmode);
+}
+
+/* Return the mode for a pointer to a given ADDRSPACE, defaulting to ptr_mode
+   for the generic address space only.  */
+
+enum machine_mode
+default_addr_space_pointer_mode (addr_space_t addrspace ATTRIBUTE_UNUSED)
+{
+  gcc_assert (addrspace == 0);
+  return ptr_mode;
+}
+
+/* Return the integer mode for subtracting two pointers to named address
+   spaces.  */
+
+tree
+default_addr_space_minus_type (addr_space_t as1 ATTRIBUTE_UNUSED,
+			       addr_space_t as2 ATTRIBUTE_UNUSED)
+{
+  gcc_assert (as1 == 0 && as2 == 0);
+  return ptrdiff_type_node;
+}
+
+/* The default hook for TARGET_ADDR_SPACE_NAME.  This hook should
+   never be called for targets with only a generic address space.  */
+
+const char *
+default_addr_space_name (addr_space_t addrspace ATTRIBUTE_UNUSED)
+{
+  gcc_unreachable ();
+}
+
+/* Named address space version of memory_address_p.  */
+
+bool
+default_addr_space_memory_address_p (enum machine_mode mode, rtx mem,
+				     addr_space_t as)
+{
+  if (!as)
+    return memory_address_p (mode, mem);
+
+  gcc_unreachable ();
+}
+
+/* Named address space version of strict_memory_address_p.  */
+
+bool
+default_addr_space_strict_memory_address_p (enum machine_mode mode, rtx mem,
+					    addr_space_t as)
+{
+  if (!as)
+    return strict_memory_address_p (mode, mem);
+
+  gcc_unreachable ();
+}
+
+/* Named address space version of LEGITIMIZE_ADDRESS.  */
+
+rtx
+default_addr_space_legitimize_address (rtx x ATTRIBUTE_UNUSED,
+				       rtx oldx ATTRIBUTE_UNUSED,
+				       enum machine_mode mode ATTRIBUTE_UNUSED,
+				       addr_space_t as ATTRIBUTE_UNUSED)
+{
+  return NULL_RTX;
+}
+
+/* The default hook for determining whether you can convert from one address
+   space to another.  */
+
+bool
+default_addr_space_can_convert_p (addr_space_t to_addr, addr_space_t from_addr)
+{
+  return to_addr == from_addr;
+}
+
+/* The default hook for determining whether convert from one address space to
+   another is a NOP.  */
+
+bool
+default_addr_space_nop_convert_p (addr_space_t to_addr, addr_space_t from_addr)
+{
+  return to_addr == from_addr;
+}
+
+/* The default hook for determining if one named address space is a subset of
+   another and to return which address space to use as the common address
+   space.  */
+
+bool
+default_addr_space_subset_p (addr_space_t as1,
+			     addr_space_t as2,
+			     addr_space_t *common_as)
+{
+  if (as1 == as2)
+    {
+      *common_as = as1;
+      return true;
+    }
+  else
+    {
+      *common_as = 0;
+      return false;
+    }
+}
+
+/* The default hook for TARGET_ADDR_SPACE_CONVERT. This hook should never be
+   called for targets with only a generic address space.  */
+
+rtx 
+default_addr_space_convert (rtx op ATTRIBUTE_UNUSED,
+			    enum machine_mode mode ATTRIBUTE_UNUSED,
+			    addr_space_t from ATTRIBUTE_UNUSED,
+			    addr_space_t to ATTRIBUTE_UNUSED)
+{
+  gcc_unreachable ();
+}
+
+/* The default hook for returning the section name to be used for static and
+   global items in a named address space.  This hook should never be called for
+   targets with only a generic address space.  */
+
+tree
+default_addr_space_section_name (addr_space_t addrspace ATTRIBUTE_UNUSED)
+{
+  gcc_unreachable ();
+}
+
+/* The default hook for determining if a static initialization inside of or
+   pointing to a named address space is ok.  */
+
+bool
+default_addr_space_static_init_ok_p (tree ARG_UNUSED (type),
+				     tree ARG_UNUSED (init),
+				     addr_space_t as,
+				     addr_space_t as_ptr)
+{
+  return (as == 0 && as_ptr == 0);
+}
+
 bool
 default_hard_regno_scratch_ok (unsigned int regno ATTRIBUTE_UNUSED)
 {
Index: gcc/targhooks.h
===================================================================
--- gcc/targhooks.h	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/targhooks.h	(working copy)
@@ -104,3 +104,22 @@ extern bool default_hard_regno_scratch_o
 extern bool default_target_option_valid_attribute_p (tree, tree, tree, int);
 extern bool default_target_option_pragma_parse (tree, tree);
 extern bool default_target_option_can_inline_p (tree, tree);
+extern bool default_valid_pointer_mode (enum machine_mode);
+extern enum machine_mode default_addr_space_pointer_mode (addr_space_t);
+extern tree default_addr_space_minus_type (addr_space_t, addr_space_t);
+extern const char *default_addr_space_name (addr_space_t);
+extern rtx default_addr_space_convert (rtx, enum machine_mode, addr_space_t,
+				       addr_space_t);
+extern bool default_addr_space_memory_address_p (enum machine_mode, rtx,
+						 addr_space_t);
+extern bool default_addr_space_strict_memory_address_p (enum machine_mode, rtx,
+							addr_space_t);
+extern rtx default_addr_space_legitimize_address (rtx, rtx, enum machine_mode,
+						  addr_space_t);
+extern bool default_addr_space_can_convert_p (addr_space_t, addr_space_t);
+extern bool default_addr_space_nop_convert_p (addr_space_t, addr_space_t);
+extern bool default_addr_space_subset_p (addr_space_t, addr_space_t,
+					 addr_space_t *);
+extern tree default_addr_space_section_name (addr_space_t);
+extern bool default_addr_space_static_init_ok_p (tree, tree, addr_space_t,
+						 addr_space_t);
Index: gcc/tree-pretty-print.c
===================================================================
--- gcc/tree-pretty-print.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/tree-pretty-print.c	(working copy)
@@ -36,6 +36,8 @@ along with GCC; see the file COPYING3.  
 #include "fixed-value.h"
 #include "value-prof.h"
 #include "predict.h"
+#include "target.h"
+#include "target-def.h"
 
 /* Local functions, macros and variables.  */
 static const char *op_symbol (const_tree);
@@ -527,6 +529,13 @@ dump_generic_node (pretty_printer *buffe
 	else if (quals & TYPE_QUAL_RESTRICT)
 	  pp_string (buffer, "restrict ");
 
+	if (TYPE_ADDR_SPACE (node))
+	  {
+	    const char *as = targetm.addr_space.name (TYPE_ADDR_SPACE (node));
+	    pp_string (buffer, as);
+	    pp_space (buffer);
+	  }
+
 	tclass = TREE_CODE_CLASS (TREE_CODE (node));
 
 	if (tclass == tcc_declaration)
@@ -603,6 +612,13 @@ dump_generic_node (pretty_printer *buffe
 	  if (quals & TYPE_QUAL_RESTRICT)
 	    pp_string (buffer, " restrict");
 
+	  if (TYPE_ADDR_SPACE (node))
+	    {
+	      const char *as = targetm.addr_space.name (TYPE_ADDR_SPACE (node));
+	      pp_string (buffer, as);
+	      pp_space (buffer);
+	    }
+	  
 	  if (TYPE_REF_CAN_ALIAS_ALL (node))
 	    pp_string (buffer, " {ref-all}");
 	}
Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/tree.c	(working copy)
@@ -1478,8 +1478,7 @@ integer_pow2p (const_tree expr)
   if (TREE_CODE (expr) != INTEGER_CST)
     return 0;
 
-  prec = (POINTER_TYPE_P (TREE_TYPE (expr))
-	  ? POINTER_SIZE : TYPE_PRECISION (TREE_TYPE (expr)));
+  prec = int_or_pointer_precision (TREE_TYPE (expr));
   high = TREE_INT_CST_HIGH (expr);
   low = TREE_INT_CST_LOW (expr);
 
@@ -1543,9 +1542,7 @@ tree_log2 (const_tree expr)
   if (TREE_CODE (expr) == COMPLEX_CST)
     return tree_log2 (TREE_REALPART (expr));
 
-  prec = (POINTER_TYPE_P (TREE_TYPE (expr))
-	  ? POINTER_SIZE : TYPE_PRECISION (TREE_TYPE (expr)));
-
+  prec = int_or_pointer_precision (TREE_TYPE (expr));
   high = TREE_INT_CST_HIGH (expr);
   low = TREE_INT_CST_LOW (expr);
 
@@ -1581,9 +1578,7 @@ tree_floor_log2 (const_tree expr)
   if (TREE_CODE (expr) == COMPLEX_CST)
     return tree_log2 (TREE_REALPART (expr));
 
-  prec = (POINTER_TYPE_P (TREE_TYPE (expr))
-	  ? POINTER_SIZE : TYPE_PRECISION (TREE_TYPE (expr)));
-
+  prec = int_or_pointer_precision (TREE_TYPE (expr));
   high = TREE_INT_CST_HIGH (expr);
   low = TREE_INT_CST_LOW (expr);
 
@@ -4185,6 +4180,7 @@ set_type_quals (tree type, int type_qual
   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_ADDR_SPACE (type) = DECODE_QUAL_ADDR_SPACE (type_quals);
 }
 
 /* Returns true iff CAND is equivalent to BASE with TYPE_QUALS.  */
@@ -4192,7 +4188,7 @@ set_type_quals (tree type, int type_qual
 bool
 check_qualified_type (const_tree cand, const_tree base, int type_quals)
 {
-  return (TYPE_QUALS (cand) == type_quals
+  return (TYPE_QUALS (CONST_CAST_TREE (cand)) == type_quals
 	  && TYPE_NAME (cand) == TYPE_NAME (base)
 	  /* Apparently this is needed for Objective-C.  */
 	  && TYPE_CONTEXT (cand) == TYPE_CONTEXT (base)
@@ -5546,7 +5542,17 @@ build_pointer_type_for_mode (tree to_typ
 tree
 build_pointer_type (tree to_type)
 {
-  return build_pointer_type_for_mode (to_type, ptr_mode, false);
+  addr_space_t addr_space;
+  enum machine_mode mode;
+
+  if (to_type == error_mark_node)
+    return error_mark_node;
+
+  addr_space = TYPE_ADDR_SPACE (to_type);
+  mode = ((addr_space)
+	  ? targetm.addr_space.pointer_mode (addr_space)
+	  : ptr_mode);
+  return build_pointer_type_for_mode (to_type, mode, false);
 }
 
 /* Same as build_pointer_type_for_mode, but for REFERENCE_TYPE.  */
@@ -5610,7 +5616,17 @@ build_reference_type_for_mode (tree to_t
 tree
 build_reference_type (tree to_type)
 {
-  return build_reference_type_for_mode (to_type, ptr_mode, false);
+  addr_space_t addr_space;
+  enum machine_mode mode;
+
+  if (to_type == error_mark_node)
+    return error_mark_node;
+
+  addr_space = TYPE_ADDR_SPACE (to_type);
+  mode = ((addr_space)
+	  ? targetm.addr_space.pointer_mode (addr_space)
+	  : ptr_mode);
+  return build_reference_type_for_mode (to_type, mode, false);
 }
 
 /* Build a type that is compatible with t but has no cv quals anywhere
@@ -5753,6 +5769,7 @@ build_array_type (tree elt_type, tree in
   t = make_node (ARRAY_TYPE);
   TREE_TYPE (t) = elt_type;
   TYPE_DOMAIN (t) = index_type;
+  TYPE_ADDR_SPACE (t) = TYPE_ADDR_SPACE (elt_type);
   
   if (index_type == 0)
     {
@@ -8317,7 +8334,19 @@ signed_or_unsigned_type_for (int unsigne
 {
   tree t = type;
   if (POINTER_TYPE_P (type))
-    t = size_type_node;
+    {
+      /* If the pointer points to the normal address space, use the
+	 size_type_node.  Otherwise use an appropriate size for the pointer
+	 based on the named address space it points to.  */
+      if (!TYPE_ADDR_SPACE (TREE_TYPE (t)))
+	t = size_type_node;
+
+      else
+	{
+	  int prec = int_or_pointer_precision (t);
+	  return lang_hooks.types.type_for_size (prec, unsignedp);
+	}
+    }
 
   if (!INTEGRAL_TYPE_P (t) || TYPE_UNSIGNED (t) == unsignedp)
     return t;
@@ -9199,4 +9228,43 @@ build_target_option_node (void)
   return t;
 }
 
+/* Return the size in bits of an integer or pointer type.  TYPE_PRECISION
+   contains the bits, but in the past it was not set in some cases and there
+   was special purpose code that checked for POINTER_TYPE_P or OFFSET_TYPE, so
+   check that it is consitant when assertion checking is used.  */
+
+unsigned int
+int_or_pointer_precision (const_tree type)
+{
+#if ENABLE_ASSERT_CHECKING
+  unsigned int prec;
+
+  if (POINTER_TYPE_P (type))
+    {
+      addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (type));
+      if (!as)
+	prec = POINTER_SIZE;
+      else
+	prec = GET_MODE_BITSIZE (targetm.addr_space.pointer_mode (as));
+
+      gcc_assert (prec == TYPE_PRECISION (type));
+    }
+  else if (TREE_CODE (type) == OFFSET_TYPE)
+    {
+      prec = POINTER_SIZE;
+      gcc_assert (prec == POINTER_SIZE);
+    }
+  else
+    {
+      prec = TYPE_PRECISION (type);
+      gcc_assert (prec != 0);
+    }
+
+  return prec;
+
+#else
+  return TYPE_PRECISION (type);
+#endif
+}
+
 #include "gt-tree.h"
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/tree.h	(working copy)
@@ -2182,6 +2182,9 @@ extern enum machine_mode vector_type_mod
    the term.  */
 #define TYPE_RESTRICT(NODE) (TYPE_CHECK (NODE)->type.restrict_flag)
 
+/* If nonzero, this type is in the extended address space.  */
+#define TYPE_ADDR_SPACE(NODE) (TYPE_CHECK (NODE)->type.address_space)
+
 /* There is a TYPE_QUAL value for each type qualifier.  They can be
    combined by bitwise-or to form the complete set of qualifiers for a
    type.  */
@@ -2191,10 +2194,29 @@ extern enum machine_mode vector_type_mod
 #define TYPE_QUAL_VOLATILE 0x2
 #define TYPE_QUAL_RESTRICT 0x4
 
+/* Encode/decode the named memory support as part of the qualifier.  If more
+   than 8 qualifiers are added, these macros need to be adjusted.  */
+#define ENCODE_QUAL_ADDR_SPACE(NUM) ((NUM & 0xFF) << 8)
+#define DECODE_QUAL_ADDR_SPACE(X) (((X) >> 8) & 0xFF)
+
+/* Return all qualifiers except for the address space qualifiers.  */
+#define CLEAR_QUAL_ADDR_SPACE(X) ((X) & ~0xFF00)
+
+/* Only keep the address space out of the qualifiers and discard the other
+   qualifiers.  */
+#define KEEP_QUAL_ADDR_SPACE(X) ((X) & 0xFF00)
+
 /* The set of type qualifiers for this type.  */
 #define TYPE_QUALS(NODE)					\
   ((TYPE_READONLY (NODE) * TYPE_QUAL_CONST)			\
    | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE)		\
+   | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT)		\
+   | (ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (NODE))))
+
+/* The same as TYPE_QUALS without the address space qualifications.  */
+#define TYPE_QUALS_NO_ADDR_SPACE(NODE)				\
+  ((TYPE_READONLY (NODE) * TYPE_QUAL_CONST)			\
+   | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE)		\
    | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT))
 
 /* These flags are available for each language front end to use internally.  */
@@ -2287,7 +2309,10 @@ struct tree_type GTY(())
   unsigned lang_flag_6 : 1;
   unsigned user_align : 1;
 
+  addr_space_t address_space;
   unsigned int align;
+  alias_set_type alias_set;
+
   tree pointer_to;
   tree reference_to;
   union tree_type_symtab {
@@ -2304,7 +2329,6 @@ struct tree_type GTY(())
   tree binfo;
   tree context;
   tree canonical;
-  alias_set_type alias_set;
   /* Points to a structure whose details depend on the language in use.  */
   struct lang_type *lang_specific;
 };
@@ -4696,6 +4720,7 @@ extern bool stdarg_p (tree);
 extern bool prototype_p (tree);
 extern int function_args_count (tree);
 extern bool auto_var_in_fn_p (const_tree, const_tree);
+extern unsigned int int_or_pointer_precision (const_tree);
 
 /* In gimplify.c */
 extern tree unshare_expr (tree);
Index: gcc/target.h
===================================================================
--- gcc/target.h	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/target.h	(working copy)
@@ -662,6 +662,55 @@ struct gcc_target
   /* True if MODE is valid for a pointer in __attribute__((mode("MODE"))).  */
   bool (* valid_pointer_mode) (enum machine_mode mode);
 
+  /* Support for named address spaces.  */
+  struct addr_space {
+    /* MODE to use for a pointer into another address space.  */
+    enum machine_mode (* pointer_mode) (addr_space_t);
+
+    /* Tree type to use for pointer subtraction.  */
+    tree (* minus_type) (addr_space_t, addr_space_t);
+
+    /* Function to map an address space to a descriptive string.  */
+    const char * (* name) (addr_space_t);
+
+    /* True if an addrress is a valid memory address to a given named address
+       space for a given mode.  */
+    bool (* memory_address_p) (enum machine_mode, rtx, addr_space_t);
+
+    /* True if an addrress is a valid memory address for use after register
+       allocation to a given named address space for a given mode.  */
+    bool (* strict_memory_address_p) (enum machine_mode, rtx, addr_space_t);
+
+    /* Return an updated address to convert an invalid pointer to a named
+       address space to a valid one.  If NULL_RTX is returned use machine
+       independent methods to make the address valid.  */
+    rtx (* legitimize_address) (rtx, rtx, enum machine_mode, addr_space_t);
+
+    /* True if it is legal to convert a pointer of one address space to
+       another.  */
+    bool (* can_convert_p) (addr_space_t, addr_space_t);
+
+    /* True if converting a pointer of one address space to another is just a
+       NOP and can be optimized away by the compiler.  */
+    bool (* nop_convert_p) (addr_space_t, addr_space_t);
+
+    /* True if one named address space is a subset of another and if so, which
+       address space is the superset.  */
+    bool (* subset_p) (addr_space_t, addr_space_t, addr_space_t *);
+
+    /* Function to convert an rtl expression from one address space to
+       another.  */
+    rtx (* convert) (rtx, enum machine_mode, addr_space_t, addr_space_t);
+
+    /* Section name to use for a named address space.  */
+    tree (* section_name) (addr_space_t);
+
+    /* Return whether static initialization within a named address space or
+       pointing to a named address space is allowed.  */
+    bool (* static_init_ok_p) (tree, tree, addr_space_t, addr_space_t);
+
+  } addr_space;
+
   /* True if MODE is valid for the target.  By "valid", we mean able to
      be manipulated in non-trivial ways.  In particular, this means all
      the arithmetic is supported.  */
Index: gcc/fold-const.c
===================================================================
--- gcc/fold-const.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/fold-const.c	(working copy)
@@ -65,6 +65,7 @@ along with GCC; see the file COPYING3.  
 #include "hashtab.h"
 #include "langhooks.h"
 #include "md5.h"
+#include "target.h"
 #include "gimple.h"
 
 /* Nonzero if we are folding constants inside an initializer; zero
@@ -202,15 +203,9 @@ fit_double_type (unsigned HOST_WIDE_INT 
 {
   unsigned HOST_WIDE_INT low0 = l1;
   HOST_WIDE_INT high0 = h1;
-  unsigned int prec;
+  unsigned int prec = int_or_pointer_precision (type);
   int sign_extended_type;
 
-  if (POINTER_TYPE_P (type)
-      || TREE_CODE (type) == OFFSET_TYPE)
-    prec = POINTER_SIZE;
-  else
-    prec = TYPE_PRECISION (type);
-
   /* Size types *are* sign extended.  */
   sign_extended_type = (!TYPE_UNSIGNED (type)
 			|| (TREE_CODE (type) == INTEGER_TYPE
@@ -2398,7 +2393,9 @@ fold_convert_const (enum tree_code code,
   if (TREE_TYPE (arg1) == type)
     return arg1;
 
-  if (POINTER_TYPE_P (type) || INTEGRAL_TYPE_P (type)
+  if (POINTER_TYPE_P (type) && TYPE_ADDR_SPACE (TREE_TYPE (type)))
+    return NULL_TREE;
+  else if (POINTER_TYPE_P (type) || INTEGRAL_TYPE_P (type)
       || TREE_CODE (type) == OFFSET_TYPE)
     {
       if (TREE_CODE (arg1) == INTEGER_CST)
Index: gcc/auto-inc-dec.c
===================================================================
--- gcc/auto-inc-dec.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk/gcc/auto-inc-dec.c)	(revision 143352)
+++ gcc/auto-inc-dec.c	(.../gcc/auto-inc-dec.c)	(working copy)
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3.  
 #include "tree-pass.h"
 #include "df.h"
 #include "dbgcnt.h"
+#include "target.h"
 
 /* This pass was originally removed from flow.c. However there is
    almost nothing that remains of that code.
@@ -651,6 +652,7 @@ try_merge (void)
   /* The width of the mem being accessed.  */
   int size = GET_MODE_SIZE (GET_MODE (mem));
   rtx last_insn = NULL;
+  enum machine_mode reg_mode = GET_MODE (inc_reg);
 
   switch (inc_insn.form)
     {
@@ -705,33 +707,33 @@ try_merge (void)
     case SIMPLE_PRE_INC:     /* ++size  */
       if (dump_file)
 	fprintf (dump_file, "trying SIMPLE_PRE_INC\n");
-      return attempt_change (gen_rtx_PRE_INC (Pmode, inc_reg), inc_reg);
+      return attempt_change (gen_rtx_PRE_INC (reg_mode, inc_reg), inc_reg);
       break;
       
     case SIMPLE_POST_INC:    /* size++  */
       if (dump_file)
 	fprintf (dump_file, "trying SIMPLE_POST_INC\n");
-      return attempt_change (gen_rtx_POST_INC (Pmode, inc_reg), inc_reg);
+      return attempt_change (gen_rtx_POST_INC (reg_mode, inc_reg), inc_reg);
       break;
       
     case SIMPLE_PRE_DEC:     /* --size  */
       if (dump_file)
 	fprintf (dump_file, "trying SIMPLE_PRE_DEC\n");
-      return attempt_change (gen_rtx_PRE_DEC (Pmode, inc_reg), inc_reg);
+      return attempt_change (gen_rtx_PRE_DEC (reg_mode, inc_reg), inc_reg);
       break;
       
     case SIMPLE_POST_DEC:    /* size--  */
       if (dump_file)
 	fprintf (dump_file, "trying SIMPLE_POST_DEC\n");
-      return attempt_change (gen_rtx_POST_DEC (Pmode, inc_reg), inc_reg);
+      return attempt_change (gen_rtx_POST_DEC (reg_mode, inc_reg), inc_reg);
       break;
       
     case DISP_PRE:           /* ++con   */
       if (dump_file)
 	fprintf (dump_file, "trying DISP_PRE\n");
-      return attempt_change (gen_rtx_PRE_MODIFY (Pmode, 
+      return attempt_change (gen_rtx_PRE_MODIFY (reg_mode, 
 						 inc_reg,
-						 gen_rtx_PLUS (Pmode,
+						 gen_rtx_PLUS (reg_mode,
 							       inc_reg,
 							       inc_insn.reg1)),
 			     inc_reg);
@@ -740,9 +742,9 @@ try_merge (void)
     case DISP_POST:          /* con++   */
       if (dump_file)
 	fprintf (dump_file, "trying POST_DISP\n");
-      return attempt_change (gen_rtx_POST_MODIFY (Pmode,
+      return attempt_change (gen_rtx_POST_MODIFY (reg_mode,
 						  inc_reg,
-						  gen_rtx_PLUS (Pmode,
+						  gen_rtx_PLUS (reg_mode,
 								inc_reg,
 								inc_insn.reg1)),
 			     inc_reg);
@@ -751,9 +753,9 @@ try_merge (void)
     case REG_PRE:            /* ++reg   */
       if (dump_file)
 	fprintf (dump_file, "trying PRE_REG\n");
-      return attempt_change (gen_rtx_PRE_MODIFY (Pmode, 
+      return attempt_change (gen_rtx_PRE_MODIFY (reg_mode, 
 						 inc_reg,
-						 gen_rtx_PLUS (Pmode,
+						 gen_rtx_PLUS (reg_mode,
 							       inc_reg,
 							       inc_insn.reg1)),
 			     inc_reg);
@@ -762,9 +764,9 @@ try_merge (void)
     case REG_POST:            /* reg++   */
       if (dump_file)
 	fprintf (dump_file, "trying POST_REG\n");
-      return attempt_change (gen_rtx_POST_MODIFY (Pmode, 
+      return attempt_change (gen_rtx_POST_MODIFY (reg_mode, 
 						  inc_reg,
-						  gen_rtx_PLUS (Pmode,
+						  gen_rtx_PLUS (reg_mode,
 								inc_reg,
 								inc_insn.reg1)),
 			     inc_reg);
@@ -1127,7 +1129,7 @@ find_inc (bool first_try)
 		     we are going to increment the result of the add insn.
 		     For this trick to be correct, the result reg of
 		     the inc must be a valid addressing reg.  */
-		  if (GET_MODE (inc_insn.reg_res) != Pmode)
+		  if (targetm.valid_pointer_mode (GET_MODE (inc_insn.reg_res)))
 		    {
 		      if (dump_file)
 			fprintf (dump_file, "base reg mode failure.\n");
@@ -1176,7 +1178,7 @@ find_inc (bool first_try)
 	{
 	  /* For this trick to be correct, the result reg of the inc
 	     must be a valid addressing reg.  */
-	  if (GET_MODE (inc_insn.reg_res) != Pmode)
+	  if (targetm.valid_pointer_mode (GET_MODE (inc_insn.reg_res)))
 	    {
 	      if (dump_file)
 		fprintf (dump_file, "base reg mode failure.\n");
Index: gcc/c-tree.h
===================================================================
--- gcc/c-tree.h	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/c-tree.h	(working copy)
@@ -287,6 +287,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.  */
@@ -517,6 +519,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/dwarf2out.c
===================================================================
--- gcc/dwarf2out.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/dwarf2out.c	(working copy)
@@ -9567,6 +9567,9 @@ modified_type_die (tree type, int is_con
       add_AT_unsigned (mod_type_die, DW_AT_byte_size,
 		       simple_type_size_in_bits (type) / BITS_PER_UNIT);
       item_type = TREE_TYPE (type);
+      if (TYPE_ADDR_SPACE (item_type))
+	add_AT_unsigned (mod_type_die, DW_AT_address_class,
+			 TYPE_ADDR_SPACE (item_type));
     }
   else if (code == REFERENCE_TYPE)
     {
@@ -9574,6 +9577,9 @@ modified_type_die (tree type, int is_con
       add_AT_unsigned (mod_type_die, DW_AT_byte_size,
 		       simple_type_size_in_bits (type) / BITS_PER_UNIT);
       item_type = TREE_TYPE (type);
+      if (TYPE_ADDR_SPACE (item_type))
+	add_AT_unsigned (mod_type_die, DW_AT_address_class,
+			 TYPE_ADDR_SPACE (item_type));
     }
   else if (is_subrange_type (type))
     {
Index: gcc/expr.c
===================================================================
--- gcc/expr.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/expr.c	(working copy)
@@ -3430,12 +3430,14 @@ emit_move_insn (rtx x, rtx y)
   /* If X or Y are memory references, verify that their addresses are valid
      for the machine.  */
   if (MEM_P (x)
-      && (! memory_address_p (GET_MODE (x), XEXP (x, 0))
+      && (! memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0),
+					 MEM_ADDR_SPACE (x))
 	  && ! push_operand (x, GET_MODE (x))))
     x = validize_mem (x);
 
   if (MEM_P (y)
-      && ! memory_address_p (GET_MODE (y), XEXP (y, 0)))
+      && ! memory_address_addr_space_p (GET_MODE (y), XEXP (y, 0),
+					MEM_ADDR_SPACE (y)))
     y = validize_mem (y);
 
   gcc_assert (mode != BLKmode);
@@ -6919,17 +6921,27 @@ expand_expr_addr_expr (tree exp, rtx tar
 		       enum expand_modifier modifier)
 {
   enum machine_mode rmode;
+  enum machine_mode addrmode;
+  enum machine_mode local_ptr_mode = ptr_mode;
   rtx result;
 
   /* Target mode of VOIDmode says "whatever's natural".  */
   if (tmode == VOIDmode)
     tmode = TYPE_MODE (TREE_TYPE (exp));
 
+  addrmode = Pmode;
+  if (POINTER_TYPE_P (TREE_TYPE (exp)))
+    {
+      addr_space_t addr_space = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp)));
+      if (addr_space)
+	local_ptr_mode = addrmode = targetm.addr_space.pointer_mode (addr_space);
+    }
+
   /* We can get called with some Weird Things if the user does silliness
      like "(short) &a".  In that case, convert_memory_address won't do
      the right thing, so ignore the given target mode.  */
-  if (tmode != Pmode && tmode != ptr_mode)
-    tmode = Pmode;
+  if (tmode != addrmode && tmode != local_ptr_mode)
+    tmode = addrmode;
 
   result = expand_expr_addr_expr_1 (TREE_OPERAND (exp, 0), target,
 				    tmode, modifier);
@@ -7167,6 +7179,7 @@ expand_expr_real_1 (tree exp, rtx target
   int ignore;
   tree context, subexp0, subexp1;
   bool reduce_bit_field;
+
 #define REDUCE_BIT_FIELD(expr)	(reduce_bit_field			  \
 				 ? reduce_to_bit_field_precision ((expr), \
 								  target, \
@@ -7330,7 +7343,9 @@ expand_expr_real_1 (tree exp, rtx target
 	  decl_rtl = use_anchored_address (decl_rtl);
 	  if (modifier != EXPAND_CONST_ADDRESS
 	      && modifier != EXPAND_SUM
-	      && !memory_address_p (DECL_MODE (exp), XEXP (decl_rtl, 0)))
+	      && !memory_address_addr_space_p (DECL_MODE (exp),
+					       XEXP (decl_rtl, 0),
+					       MEM_ADDR_SPACE (decl_rtl)))
 	    temp = replace_equiv_address (decl_rtl,
 					  copy_rtx (XEXP (decl_rtl, 0)));
 	}
@@ -7452,7 +7467,8 @@ expand_expr_real_1 (tree exp, rtx target
       if (modifier != EXPAND_CONST_ADDRESS
 	  && modifier != EXPAND_INITIALIZER
 	  && modifier != EXPAND_SUM
-	  && ! memory_address_p (mode, XEXP (temp, 0)))
+	  && ! memory_address_addr_space_p (mode, XEXP (temp, 0),
+					    MEM_ADDR_SPACE (temp)))
 	return replace_equiv_address (temp,
 				      copy_rtx (XEXP (temp, 0)));
       return temp;
@@ -7512,6 +7528,8 @@ expand_expr_real_1 (tree exp, rtx target
     case INDIRECT_REF:
       {
 	tree exp1 = TREE_OPERAND (exp, 0);
+	addr_space_t as = 0;
+	enum machine_mode mem_Pmode = Pmode;
 
 	if (modifier != EXPAND_WRITE)
 	  {
@@ -7522,20 +7540,30 @@ expand_expr_real_1 (tree exp, rtx target
 	      return expand_expr (t, target, tmode, modifier);
 	  }
 
+	if (POINTER_TYPE_P (TREE_TYPE (exp1)))
+	  {
+	    as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp1)));
+	    if (as)
+	      mem_Pmode = targetm.addr_space.pointer_mode (as);
+	  }
+
 	op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
-	op0 = memory_address (mode, op0);
+	op0 = memory_address_addr_space (mode, op0, as);
 
 	if (code == ALIGN_INDIRECT_REF)
 	  {
 	    int align = TYPE_ALIGN_UNIT (type);
-	    op0 = gen_rtx_AND (Pmode, op0, GEN_INT (-align));
-	    op0 = memory_address (mode, op0);
+	    op0 = gen_rtx_AND (mem_Pmode, op0, GEN_INT (-align));
+	    op0 = memory_address_addr_space (mode, op0, as);
 	  }
 
 	temp = gen_rtx_MEM (mode, op0);
 
 	set_mem_attributes (temp, exp, 0);
 
+	if (as)
+	  set_mem_addr_space (temp, as);
+
 	/* Resolve the misalignment now, so that we don't have to remember
 	   to resolve it later.  Of course, this only works for reads.  */
 	/* ??? When we get around to supporting writes, we'll have to handle
@@ -8131,6 +8159,25 @@ expand_expr_real_1 (tree exp, rtx target
 	  return target;
 	}
 
+      /* Handle casts of pointers to/from address space qualified
+	 pointers.  */
+      subexp0 = TREE_OPERAND (exp, 0);
+      if (POINTER_TYPE_P (type) && POINTER_TYPE_P (TREE_TYPE (subexp0)))
+	{
+	  tree subexp0_type = TREE_TYPE (subexp0);
+	  addr_space_t as_to = TYPE_ADDR_SPACE (TREE_TYPE (type));
+	  addr_space_t as_from = TYPE_ADDR_SPACE (TREE_TYPE (subexp0_type));
+
+	  if (as_to != as_from)
+	    {
+	      op0 = expand_expr (subexp0, NULL_RTX, VOIDmode, modifier);
+	      return targetm.addr_space.convert (op0,
+						 TYPE_MODE (type),
+						 as_from,
+						 as_to);
+	    }
+	}
+
       if (mode == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
 	{
 	  op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode,
Index: gcc/expr.h
===================================================================
--- gcc/expr.h	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/expr.h	(working copy)
@@ -635,9 +635,14 @@ extern rtx force_label_rtx (tree);
    The constant terms are added and stored via a second arg.  */
 extern rtx eliminate_constant_term (rtx, rtx *);
 
-/* Convert arg to a valid memory address for specified machine mode,
-   by emitting insns to perform arithmetic if nec.  */
-extern rtx memory_address (enum machine_mode, rtx);
+/* Convert arg to a valid memory address for specified machine mode that points
+   to a specific named address space, by emitting insns to perform arithmetic
+   if necessary.  */
+extern rtx memory_address_addr_space (enum machine_mode, rtx, addr_space_t);
+
+/* Like memory_address_addr_space, except assume the memory address points to
+   the generic named address space.  */
+#define memory_address(MODE,RTX) memory_address_addr_space (MODE, RTX, 0)
 
 /* Return a memory reference like MEMREF, but with its mode changed
    to MODE and its address changed to ADDR.
@@ -645,6 +650,11 @@ extern rtx memory_address (enum machine_
    NULL for ADDR means don't change the address.)  */
 extern rtx change_address (rtx, enum machine_mode, rtx);
 
+/* Like change_address, except we change the address space of the memory
+   returned.  */
+extern rtx change_address_addr_space (rtx, enum machine_mode, rtx,
+				      addr_space_t);
+
 /* Return a memory reference like MEMREF, but with its mode changed
    to MODE and its address offset by OFFSET bytes.  */
 #define adjust_address(MEMREF, MODE, OFFSET) \
Index: gcc/recog.c
===================================================================
--- gcc/recog.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/recog.c	(working copy)
@@ -1253,6 +1253,17 @@ memory_address_p (enum machine_mode mode
   return 1;
 }
 
+/* Like memory_address_p, expect for a distinct named address space.  */
+
+int
+memory_address_addr_space_p (enum machine_mode mode, rtx addr, addr_space_t as)
+{
+  if (!as)
+    return memory_address_p (mode, addr);
+  else
+    return targetm.addr_space.memory_address_p (mode, addr, as);
+}
+
 /* Return 1 if OP is a valid memory reference with mode MODE,
    including a valid address.
 
Index: gcc/recog.h
===================================================================
--- gcc/recog.h	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/recog.h	(working copy)
@@ -85,7 +85,10 @@ extern void cancel_changes (int);
 extern int constrain_operands (int);
 extern int constrain_operands_cached (int);
 extern int memory_address_p (enum machine_mode, rtx);
+extern int memory_address_addr_space_p (enum machine_mode, rtx, addr_space_t);
 extern int strict_memory_address_p (enum machine_mode, rtx);
+extern int strict_memory_address_addr_space_p (enum machine_mode, rtx,
+					       addr_space_t);
 extern int validate_replace_rtx (rtx, rtx, rtx);
 extern int validate_replace_rtx_part (rtx, rtx, rtx *, rtx);
 extern int validate_replace_rtx_part_nosimplify (rtx, rtx, rtx *, rtx);
Index: gcc/c-decl.c
===================================================================
--- gcc/c-decl.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/c-decl.c	(working copy)
@@ -62,6 +62,7 @@ along with GCC; see the file COPYING3.  
 #include "except.h"
 #include "langhooks-def.h"
 #include "pointer-set.h"
+#include "targhooks.h"
 #include "gimple.h"
 
 /* In grokdeclarator, distinguish syntactic contexts of declarators.  */
@@ -1245,8 +1246,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",
+			   targetm.addr_space.name (old_addr), newdecl);
+		  else if (!old_addr)
+		    error ("conflicting named address spaces (%s vs generic) "
+			   "for %q+D",
+			   targetm.addr_space.name (new_addr), newdecl);
+		  else
+		    error ("conflicting named address spaces (%s vs %s) "
+			   "for %q+D",
+			   targetm.addr_space.name (new_addr),
+			   targetm.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);
@@ -2918,7 +2946,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,
@@ -2989,7 +3018,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;
@@ -3012,7 +3042,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
@@ -3165,6 +3196,7 @@ start_decl (struct c_declarator *declara
   tree decl;
   tree tem;
   enum deprecated_states deprecated_state = DEPRECATED_NORMAL;
+  addr_space_t addrspace;
 
   /* An object declared as __attribute__((deprecated)) suppresses
      warnings of uses of other deprecated items.  */
@@ -3272,6 +3304,17 @@ start_decl (struct c_declarator *declara
       && !flag_no_common)
     DECL_COMMON (decl) = 1;
 
+  if (TREE_CODE (decl) == VAR_DECL
+      && TREE_TYPE (decl) != error_mark_node
+      && (addrspace = TYPE_ADDR_SPACE (TREE_TYPE (decl)))
+      && targetm.have_named_sections
+      && (declspecs->storage_class == csc_static
+	  || (declspecs->storage_class == csc_none
+	      && !current_function_scope)
+	  || (declspecs->storage_class == csc_extern
+	      && initialized)))
+    DECL_SECTION_NAME (decl) = targetm.addr_space.section_name (addrspace);
+
   /* Set attributes here so if duplicate decl, will have proper attributes.  */
   decl_attributes (&decl, attributes, 0);
 
@@ -3990,6 +4033,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;
 
   if (decl_context == FUNCDEF)
     funcdef_flag = true, decl_context = NORMAL;
@@ -4090,6 +4134,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)
@@ -4099,11 +4147,27 @@ grokdeclarator (const struct c_declarato
       if (volatilep > 1)
 	pedwarn (input_location, OPT_pedantic, "duplicate %<volatile%>");
     }
+
+  if (as1 > 0 && as2 > 0 && as1 != as2)
+    {
+      if (!as1)
+	error ("conflicting named address spaces (generic vs %s)",
+	       targetm.addr_space.name (as1));
+      else if (!as2)
+	error ("conflicting named address spaces (%s vs generic),",
+	       targetm.addr_space.name (as2));
+      else
+	error ("conflicting named address spaces (%s vs %s)",
+	       targetm.addr_space.name (as1),
+	       targetm.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.).  */
@@ -4433,7 +4497,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)
 	      {
@@ -4521,6 +4592,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 %qs",
+		       targetm.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)
@@ -4564,7 +4644,7 @@ grokdeclarator (const struct c_declarato
 	       for the pointer.  */
 
 	    if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
-		&& type_quals)
+		&& CLEAR_QUAL_ADDR_SPACE (type_quals))
 	      pedwarn (input_location, OPT_pedantic,
 		       "ISO C forbids qualified function types");
 	    if (type_quals)
@@ -4623,6 +4703,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 %qs",
+		     targetm.addr_space.name (address_space), name);
+	      break;
+	    case csc_register:
+	      error ("%qs combined with %<register%> qualifier for %qs",
+		     targetm.addr_space.name (address_space), name);
+	      break;
+	    case csc_none:
+	      if (current_function_scope)
+		{
+		  error ("%qs specified for auto variable %qs",
+			 targetm.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 %qs",
+	       targetm.addr_space.name (address_space), name);
+      else if (decl_context == FIELD)
+	error ("%qs specified for structure field %qs",
+	       targetm.addr_space.name (address_space), name);
+    }
+
   /* Check the type and width of a bit-field.  */
   if (bitfield)
     check_bitfield_type_and_width (&type, width, orig_name);
@@ -4646,7 +4767,7 @@ grokdeclarator (const struct c_declarato
     {
       tree decl;
       if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
-	  && type_quals)
+	  && CLEAR_QUAL_ADDR_SPACE (type_quals))
 	pedwarn (input_location, OPT_pedantic,
 		 "ISO C forbids qualified function types");
       if (type_quals)
@@ -4670,7 +4791,7 @@ grokdeclarator (const struct c_declarato
       gcc_assert (storage_class == csc_none && !threadp
 		  && !declspecs->inline_p);
       if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
-	  && type_quals)
+	  && CLEAR_QUAL_ADDR_SPACE (type_quals))
 	pedwarn (input_location, OPT_pedantic,
 		 "ISO C forbids const or volatile function types");
       if (type_quals)
@@ -4736,7 +4857,7 @@ grokdeclarator (const struct c_declarato
 	  }
 	else if (TREE_CODE (type) == FUNCTION_TYPE)
 	  {
-	    if (type_quals)
+	    if (CLEAR_QUAL_ADDR_SPACE (type_quals))
 	      pedwarn (input_location, OPT_pedantic,
 		       "ISO C forbids qualified function types");
 	    if (type_quals)
@@ -4825,7 +4946,8 @@ grokdeclarator (const struct c_declarato
 	DECL_SOURCE_LOCATION (decl) = declarator->id_loc;
 	decl = build_decl_attribute_variant (decl, decl_attr);
 
-	if (pedantic && type_quals && !DECL_IN_SYSTEM_HEADER (decl))
+	if (pedantic && CLEAR_QUAL_ADDR_SPACE (type_quals)
+	    && !DECL_IN_SYSTEM_HEADER (decl))
 	  pedwarn (input_location, OPT_pedantic,
 		   "ISO C forbids qualified function types");
 
@@ -4972,8 +5094,8 @@ grokdeclarator (const struct c_declarato
 	C_DECL_REGISTER (decl) = was_reg;
       }
 
-  /* This is the earliest point at which we might know the assembler
-     name of a variable.  Thus, if it's known before this, die horribly.  */
+    /* This is the earliest point at which we might know the assembler name of
+       a variable.  Thus, if it's known before this, die horribly.  */
     gcc_assert (!DECL_ASSEMBLER_NAME_SET_P (decl));
 
     return decl;
@@ -7134,9 +7256,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",
+	   targetm.addr_space.name (as),
+	   targetm.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/c-pretty-print.c
===================================================================
--- gcc/c-pretty-print.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/c-pretty-print.c	(working copy)
@@ -29,6 +29,8 @@ along with GCC; see the file COPYING3.  
 #include "c-tree.h"
 #include "tree-iterator.h"
 #include "diagnostic.h"
+#include "target.h"
+#include "target-def.h"
 
 /* The pretty-printer code is primarily designed to closely follow
    (GNU) C and C++ grammars.  That is to be contrasted with spaghetti
@@ -220,7 +222,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)
@@ -240,6 +246,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 = targetm.addr_space.name (TYPE_ADDR_SPACE (t));
+      pp_c_identifier (pp, as);
+    }
 }
 
 /* pointer:
Index: gcc/langhooks.c
===================================================================
--- gcc/langhooks.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/langhooks.c	(working copy)
@@ -272,7 +272,7 @@ lhd_tree_dump_dump_tree (void *di ATTRIB
 int
 lhd_tree_dump_type_quals (const_tree t)
 {
-  return TYPE_QUALS (t);
+  return TYPE_QUALS (CONST_CAST_TREE (t));
 }
 
 /* lang_hooks.expr_size: Determine the size of the value of an expression T
Index: gcc/print-rtl.c
===================================================================
--- gcc/print-rtl.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/print-rtl.c	(working copy)
@@ -556,6 +556,9 @@ print_rtx (const_rtx in_rtx)
       if (MEM_ALIGN (in_rtx) != 1)
 	fprintf (outfile, " A%u", MEM_ALIGN (in_rtx));
 
+      if (MEM_ADDR_SPACE (in_rtx))
+	fprintf (outfile, " AS%u", MEM_ADDR_SPACE (in_rtx));
+
       fputc (']', outfile);
       break;
 
Index: gcc/stor-layout.c
===================================================================
--- gcc/stor-layout.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/stor-layout.c	(working copy)
@@ -1685,6 +1685,7 @@ layout_type (tree type)
       /* A pointer might be MODE_PARTIAL_INT,
 	 but ptrdiff_t must be integral.  */
       SET_TYPE_MODE (type, mode_for_size (POINTER_SIZE, MODE_INT, 0));
+      TYPE_PRECISION (type) = POINTER_SIZE;
       break;
 
     case FUNCTION_TYPE:
Index: gcc/c-typeck.c
===================================================================
--- gcc/c-typeck.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/c-typeck.c	(working copy)
@@ -91,7 +91,8 @@ static void push_member_name (tree);
 static int spelling_length (void);
 static char *print_spelling (char *);
 static void warning_init (int, const char *);
-static tree digest_init (tree, tree, bool, int);
+static bool digest_init_addr_space_ok_p (tree, tree, addr_space_t);
+static tree digest_init (tree, tree, bool, int, addr_space_t);
 static void output_init_element (tree, bool, tree, tree, int, bool);
 static void output_pending_init_elements (int);
 static int set_designator (int);
@@ -106,7 +107,9 @@ static int lvalue_p (const_tree);
 static void record_maybe_used_decl (tree);
 static int comptypes_internal (const_tree, const_tree);
 
-/* Return true if EXP is a null pointer constant, false otherwise.  */
+/* Return true if EXP is a null pointer constant, false otherwise.  If
+   different named address spaces are available, a null pointer to one address
+   space can be converted as a null pointer to another address space.  */
 
 static bool
 null_pointer_constant_p (const_tree expr)
@@ -120,7 +123,8 @@ null_pointer_constant_p (const_tree expr
 	  && (INTEGRAL_TYPE_P (type)
 	      || (TREE_CODE (type) == POINTER_TYPE
 		  && VOID_TYPE_P (TREE_TYPE (type))
-		  && TYPE_QUALS (TREE_TYPE (type)) == TYPE_UNQUALIFIED)));
+		  && (TYPE_QUALS_NO_ADDR_SPACE (TREE_TYPE (type))
+		      == TYPE_UNQUALIFIED))));
 }
 /* This is a cache to hold if two types are compatible or not.  */
 
@@ -248,8 +252,27 @@ c_type_promotes_to (tree type)
 static tree
 qualify_type (tree type, tree like)
 {
+  int quals = (TYPE_QUALS_NO_ADDR_SPACE (type)
+	       | TYPE_QUALS_NO_ADDR_SPACE (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 (as_type == as_like)
+    as_common = as_type;
+
+  /* Two different named address spaces, check for one being a subset of the
+     other, and if there isn't a common superset address space, raise an
+     error.  */
+  else if (!targetm.addr_space.subset_p (as_type, as_like, &as_common))
+    {
+      as_common = 0;
+      error ("%qT and %qT are in different named address spaces",
+	     type, like);
+    }
+
   return c_build_qualified_type (type,
-				 TYPE_QUALS (type) | TYPE_QUALS (like));
+				 quals | ENCODE_QUAL_ADDR_SPACE (as_common));
 }
 
 /* Return true iff the given tree T is a variable length array.  */
@@ -328,7 +351,8 @@ composite_type (tree t1, tree t2)
 	bool d1_zero, d2_zero;
 
 	/* 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));
 
 	d1_zero = d1 == 0 || !TYPE_MAX_VALUE (d1);
 	d2_zero = d2 == 0 || !TYPE_MAX_VALUE (d2);
@@ -530,6 +554,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.  */
 
@@ -561,10 +587,26 @@ 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);
+
+  /* Determine the address space to use if the pointers point to different
+     named address spaces and if so, whether one address space is a subset of
+     the other.  */
+  as1 = TYPE_ADDR_SPACE (pointed_to_1);
+  as2 = TYPE_ADDR_SPACE (pointed_to_2);
+  if (as1 == as2)
+    as_common = as1;
+  else if (!targetm.addr_space.subset_p (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);
 }
@@ -916,7 +958,7 @@ comptypes_internal (const_tree type1, co
 
   /* Qualifiers must match. C99 6.7.3p9 */
 
-  if (TYPE_QUALS (t1) != TYPE_QUALS (t2))
+  if (TYPE_QUALS (CONST_CAST_TREE (t1)) != TYPE_QUALS (CONST_CAST_TREE (t2)))
     return 0;
 
   /* Allow for two different type nodes which have essentially the same
@@ -1019,19 +1061,29 @@ 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 (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 = 0;
+
+  /* See if the pointers point to different address spaces.  */
+  if (asl != asr
+      && !targetm.addr_space.subset_p (asl, asr, &as_common)
+      && (asl != 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)
@@ -2817,7 +2869,11 @@ parser_build_binary_op (location_t locat
 static tree
 pointer_diff (tree op0, tree op1)
 {
-  tree restype = ptrdiff_type_node;
+  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 restype = ((as0 == 0 && as1 == 0)
+		  ? ptrdiff_type_node
+		  : targetm.addr_space.minus_type (as0, as1));
 
   tree target_type = TREE_TYPE (TREE_TYPE (op0));
   tree con0, con1, lit0, lit1;
@@ -3502,12 +3558,26 @@ build_conditional_expr (tree ifexp, tree
     }
   else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
     {
+      addr_space_t as1;
+      addr_space_t as2;
+      addr_space_t as_common = 0;
+
       if (comp_target_types (type1, type2))
 	result_type = common_pointer_type (type1, type2);
       else if (null_pointer_constant_p (orig_op1))
 	result_type = qualify_type (type2, type1);
       else if (null_pointer_constant_p (orig_op2))
 	result_type = qualify_type (type1, type2);
+      else if (((as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1)))
+		!= (as2 = TYPE_ADDR_SPACE (TREE_TYPE (type2))))
+	       && (TYPE_MAIN_VARIANT (TREE_TYPE (type1))
+		   == TYPE_MAIN_VARIANT (TREE_TYPE (type2)))
+	       && !targetm.addr_space.subset_p (as1, as2, &as_common))
+	{
+	  error ("pointers to incompatible address spaces used in conditional "
+		 "expression");
+	  result_type = type1;
+	}
       else if (VOID_TYPE_P (TREE_TYPE (type1)))
 	{
 	  if (TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE)
@@ -3682,7 +3752,7 @@ build_c_cast (tree type, tree expr)
 		   "ISO C forbids casts to union type");
 	  t = digest_init (type,
 			   build_constructor_single (type, field, value),
-			   true, 0);
+			   true, 0, 0);
 	  TREE_CONSTANT (t) = TREE_CONSTANT (value);
 	  return t;
 	}
@@ -3724,9 +3794,11 @@ build_c_cast (tree type, tree expr)
 		 are added, not when they're 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);
@@ -3740,6 +3812,37 @@ build_c_cast (tree type, tree expr)
 	    warning (OPT_Wcast_qual, "cast discards qualifiers from pointer target type");
 	}
 
+      /* Determine whether a pointer to one named address space can be
+	 converted to a pointer to another named address. */
+      if (TREE_CODE (type) == POINTER_TYPE
+	  && TREE_CODE (otype) == POINTER_TYPE)
+	{
+	  addr_space_t as_to = TYPE_ADDR_SPACE (TREE_TYPE (type));
+	  addr_space_t as_from = TYPE_ADDR_SPACE (TREE_TYPE (otype));
+
+	  if (as_to != as_from
+	      && !targetm.addr_space.can_convert_p (as_from, as_to))
+	    {
+	      if (!as_from)
+		error ("cast to %s address space pointer from generic address "
+		       "space pointer",
+		       targetm.addr_space.name (as_to));
+
+	      else if (!as_to)
+		error ("cast to generic address space pointer from %s address "
+		       "space pointer",
+		       targetm.addr_space.name (as_from));
+
+	      else
+		error ("cast to %s address space pointer from %s address "
+		       "space pointer",
+		       targetm.addr_space.name (as_to),
+		       targetm.addr_space.name (as_from));
+
+	      return error_mark_node;
+	    }
+	}
+
       /* Warn about possible alignment problems.  */
       if (STRICT_ALIGNMENT
 	  && TREE_CODE (type) == POINTER_TYPE
@@ -4201,7 +4304,8 @@ convert_for_assignment (tree type, tree 
 		     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 (input_location, 0,
 					 G_("passing argument %d of %qE "
 					    "makes qualified function "
@@ -4215,7 +4319,8 @@ convert_for_assignment (tree type, tree 
 					 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 (input_location, 0,
 				     G_("passing argument %d of %qE discards "
 					"qualifiers from pointer target type"),
@@ -4248,6 +4353,9 @@ convert_for_assignment (tree type, tree 
       tree mvr = ttr;
       bool is_opaque_pointer;
       int target_cmp = 0;   /* Cache comp_target_types () result.  */
+      addr_space_t asl;
+      addr_space_t asr;
+      addr_space_t as_common;
 
       if (TREE_CODE (mvl) != ARRAY_TYPE)
 	mvl = TYPE_MAIN_VARIANT (mvl);
@@ -4267,6 +4375,38 @@ convert_for_assignment (tree type, tree 
 	warning (OPT_Wc___compat, "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);
+      as_common = 0;
+      if ((asl != asr)
+	  && !null_pointer_constant_p (rhs)
+	  && !targetm.addr_space.subset_p (asl, asr, &as_common)
+	  && asl != as_common)
+	{
+	  switch (errtype)
+	    {
+	    case ic_argpass:
+	      error ("passing argument %d of %qE is a pointer to an "
+		     "incompatible address space", parmnum, rname);
+	      break;
+	    case ic_assign:
+	      error ("assignment to a pointer to an incompatible address "
+		     "space");
+	      break;
+	    case ic_init:
+	      error ("initialization of a pointer to an incompatible address "
+		     "space");
+	      break;
+	    case ic_return:
+	      error ("return of a pointer to an incompatible 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
@@ -4330,7 +4470,8 @@ convert_for_assignment (tree type, tree 
 	  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
@@ -4370,7 +4511,8 @@ convert_for_assignment (tree type, tree 
 		 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 (input_location, 0,
 				     G_("passing argument %d of %qE makes "
 					"qualified function pointer "
@@ -4505,7 +4647,8 @@ store_init_value (tree decl, tree init)
 
   /* Digest the specified initializer into an expression.  */
 
-  value = digest_init (type, init, true, TREE_STATIC (decl));
+  value = digest_init (type, init, true, TREE_STATIC (decl),
+		       TYPE_ADDR_SPACE (TREE_TYPE (decl)));
 
   /* Store the expression if valid; else report error.  */
 
@@ -4733,6 +4876,41 @@ maybe_warn_string_init (tree type, struc
 		  "array initialized from parenthesized string constant");
 }
 
+/* Subroutine of digest_init to allow the backend to restrict what type of
+   static initializations are allowed for named address spaces.  Return true if
+   the initialization is valid.  */
+
+static bool
+digest_init_addr_space_ok_p (tree type, tree init, addr_space_t as)
+{
+  addr_space_t ptr_as = 0;
+
+  if (init == error_mark_node)
+    return false;
+
+  if (POINTER_TYPE_P (TREE_TYPE (init)))
+    ptr_as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (init)));
+
+  /* See if initializing elements in a named address space is ok.  */
+  if (as && !targetm.addr_space.static_init_ok_p (type, init, as, ptr_as))
+    {
+      error_init ("initializer element is not allowed in named address space");
+      return false;
+    }
+
+  /* Check for initializing pointers to a named address space.  */
+  else if (ptr_as
+	   && !targetm.addr_space.static_init_ok_p (type, init, as, ptr_as))
+    {
+      error_init ("initializer element pointing to a named address space "
+		  "is not allowed");
+      return false;
+    }
+
+  else
+    return true;
+}
+
 /* Digest the parser output INIT as an initializer for type TYPE.
    Return a C expression of type TYPE to represent the initial value.
 
@@ -4741,10 +4919,13 @@ maybe_warn_string_init (tree type, struc
    For other types of INIT, STRICT_STRING is not used.
 
    REQUIRE_CONSTANT requests an error if non-constant initializers or
-   elements are seen.  */
+   elements are seen.
+
+   AS is non-zero if the declaration is in a named address space.  */
 
 static tree
-digest_init (tree type, tree init, bool strict_string, int require_constant)
+digest_init (tree type, tree init, bool strict_string, int require_constant,
+	     addr_space_t as)
 {
   enum tree_code code = TREE_CODE (type);
   tree inside_init = init;
@@ -4784,6 +4965,10 @@ digest_init (tree type, tree init, bool 
 	  expr.original_code = (strict_string ? STRING_CST : ERROR_MARK);
 	  maybe_warn_string_init (type, expr);
 
+	  if (require_constant
+	      && !digest_init_addr_space_ok_p (type, inside_init, as))
+	    return error_mark_node;
+
 	  if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
 			 TYPE_MAIN_VARIANT (type)))
 	    return inside_init;
@@ -4844,6 +5029,10 @@ digest_init (tree type, tree init, bool 
       && vector_types_convertible_p (TREE_TYPE (inside_init), type, true)
       && TREE_CONSTANT (inside_init))
     {
+      if (require_constant
+	  && !digest_init_addr_space_ok_p (type, inside_init, as))
+	return error_mark_node;
+
       if (TREE_CODE (inside_init) == VECTOR_CST
 	  && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
 			TYPE_MAIN_VARIANT (type)))
@@ -4954,6 +5143,9 @@ digest_init (tree type, tree init, bool 
 	  error_init ("initializer element is not constant");
 	  inside_init = error_mark_node;
 	}
+      else if (require_constant
+	       && !digest_init_addr_space_ok_p (type, inside_init, as))
+	inside_init = error_mark_node;
 
       /* Added to enable additional -Wmissing-format-attribute warnings.  */
       if (TREE_CODE (TREE_TYPE (inside_init)) == POINTER_TYPE)
@@ -4991,6 +5183,9 @@ digest_init (tree type, tree init, bool 
 	  error_init ("initializer element is not computable at load time");
 	  inside_init = error_mark_node;
 	}
+      else if (require_constant
+	       && !digest_init_addr_space_ok_p (type, inside_init, as))
+	inside_init = error_mark_node;
 
       return inside_init;
     }
@@ -6385,7 +6580,8 @@ output_init_element (tree value, bool st
 		  || TREE_CHAIN (field)))))
     return;
 
-  value = digest_init (type, value, strict_string, require_constant_value);
+  value = digest_init (type, value, strict_string, require_constant_value,
+		       TYPE_ADDR_SPACE (type));
   if (value == error_mark_node)
     {
       constructor_erroneous = 1;
@@ -8286,6 +8482,8 @@ build_binary_op (location_t location, en
 	{
 	  tree tt0 = TREE_TYPE (type0);
 	  tree tt1 = TREE_TYPE (type1);
+	  addr_space_t as;
+
 	  /* Anything compares with void *.  void * compares with anything.
 	     Otherwise, the targets must be compatible
 	     and both must be object or both incomplete.  */
@@ -8299,6 +8497,17 @@ build_binary_op (location_t location, en
 		  && TREE_CODE (tt1) == FUNCTION_TYPE)
 		pedwarn (location, OPT_pedantic, "ISO C forbids "
 			 "comparison of %<void *%> with function pointer");
+
+	      /* If this operand is a pointer into another address
+		 space, make the result of the comparison such a
+		 pointer also.  */
+	      if (POINTER_TYPE_P (type0)
+		  && (as = TYPE_ADDR_SPACE (TREE_TYPE (type0))))
+		{
+		  int qual = ENCODE_QUAL_ADDR_SPACE (as);
+		  result_type = build_pointer_type
+		    (build_qualified_type (void_type_node, qual));
+		}
 	    }
 	  else if (VOID_TYPE_P (tt1))
 	    {
@@ -8306,6 +8515,17 @@ build_binary_op (location_t location, en
 		  && TREE_CODE (tt0) == FUNCTION_TYPE)
 		pedwarn (location, OPT_pedantic, "ISO C forbids "
 			 "comparison of %<void *%> with function pointer");
+
+	      /* If this operand is a pointer into another address
+		 space, make the result of the comparison such a
+		 pointer also.  */
+	      if (POINTER_TYPE_P (type1)
+		  && (as = TYPE_ADDR_SPACE (TREE_TYPE (type1))))
+		{
+		  int qual = ENCODE_QUAL_ADDR_SPACE (as);
+		  result_type = build_pointer_type
+		    (build_qualified_type (void_type_node, qual));
+		}
 	    }
 	  else
 	    /* Avoid warning about the volatile ObjC EH puts on decls.  */
Index: gcc/coretypes.h
===================================================================
--- gcc/coretypes.h	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/coretypes.h	(working copy)
@@ -62,6 +62,9 @@ struct gimple_seq_node_d;
 typedef struct gimple_seq_node_d *gimple_seq_node;
 typedef const struct gimple_seq_node_d *const_gimple_seq_node;
 
+/* Address space number for named address space support.  */
+typedef unsigned char addr_space_t;
+
 /* The major intermediate representations of GCC.  */
 enum ir_type {
   IR_GIMPLE,
Index: gcc/emit-rtl.c
===================================================================
--- gcc/emit-rtl.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/emit-rtl.c	(working copy)
@@ -58,6 +58,7 @@ along with GCC; see the file COPYING3.  
 #include "langhooks.h"
 #include "tree-pass.h"
 #include "df.h"
+#include "target.h"
 
 /* Commonly used modes.  */
 
@@ -179,7 +180,7 @@ static GTY ((if_marked ("ggc_marked_p"),
 #define first_label_num (crtl->emit.x_first_label_num)
 
 static rtx make_call_insn_raw (rtx);
-static rtx change_address_1 (rtx, enum machine_mode, rtx, int);
+static rtx change_address_1 (rtx, enum machine_mode, rtx, int, addr_space_t);
 static void set_used_decls (tree);
 static void mark_label_nuses (rtx);
 static hashval_t const_int_htab_hash (const void *);
@@ -193,7 +194,7 @@ static rtx lookup_const_fixed (rtx);
 static hashval_t mem_attrs_htab_hash (const void *);
 static int mem_attrs_htab_eq (const void *, const void *);
 static mem_attrs *get_mem_attrs (alias_set_type, tree, rtx, rtx, unsigned int,
-				 enum machine_mode);
+				 addr_space_t, enum machine_mode);
 static hashval_t reg_attrs_htab_hash (const void *);
 static int reg_attrs_htab_eq (const void *, const void *);
 static reg_attrs *get_reg_attrs (tree, int);
@@ -293,6 +294,7 @@ mem_attrs_htab_hash (const void *x)
   const mem_attrs *const p = (const mem_attrs *) x;
 
   return (p->alias ^ (p->align * 1000)
+	  ^ (p->addrspace * 4000)
 	  ^ ((p->offset ? INTVAL (p->offset) : 0) * 50000)
 	  ^ ((p->size ? INTVAL (p->size) : 0) * 2500000)
 	  ^ (size_t) iterative_hash_expr (p->expr, 0));
@@ -310,6 +312,7 @@ mem_attrs_htab_eq (const void *x, const 
 
   return (p->alias == q->alias && p->offset == q->offset
 	  && p->size == q->size && p->align == q->align
+	  && p->addrspace == q->addrspace
 	  && (p->expr == q->expr
 	      || (p->expr != NULL_TREE && q->expr != NULL_TREE
 		  && operand_equal_p (p->expr, q->expr, 0))));
@@ -321,7 +324,7 @@ mem_attrs_htab_eq (const void *x, const 
 
 static mem_attrs *
 get_mem_attrs (alias_set_type alias, tree expr, rtx offset, rtx size,
-	       unsigned int align, enum machine_mode mode)
+	       unsigned int align, addr_space_t addrspace, enum machine_mode mode)
 {
   mem_attrs attrs;
   void **slot;
@@ -329,7 +332,7 @@ get_mem_attrs (alias_set_type alias, tre
   /* If everything is the default, we can just return zero.
      This must match what the corresponding MEM_* macros return when the
      field is not present.  */
-  if (alias == 0 && expr == 0 && offset == 0
+  if (alias == 0 && expr == 0 && offset == 0 && addrspace == 0
       && (size == 0
 	  || (mode != BLKmode && GET_MODE_SIZE (mode) == INTVAL (size)))
       && (STRICT_ALIGNMENT && mode != BLKmode
@@ -341,6 +344,7 @@ get_mem_attrs (alias_set_type alias, tre
   attrs.offset = offset;
   attrs.size = size;
   attrs.align = align;
+  attrs.addrspace = addrspace;
 
   slot = htab_find_slot (mem_attrs_htab, &attrs, INSERT);
   if (*slot == 0)
@@ -1838,7 +1842,9 @@ set_mem_attributes_minus_bitpos (rtx ref
 
   /* Now set the attributes we computed above.  */
   MEM_ATTRS (ref)
-    = get_mem_attrs (alias, expr, offset, size, align, GET_MODE (ref));
+    = get_mem_attrs (alias, expr, offset, size, align,
+		     TYPE_ADDR_SPACE (type),
+		     GET_MODE (ref));
 
   /* If this is already known to be a scalar or aggregate, we are done.  */
   if (MEM_IN_STRUCT_P (ref) || MEM_SCALAR_P (ref))
@@ -1866,7 +1872,7 @@ set_mem_attrs_from_reg (rtx mem, rtx reg
   MEM_ATTRS (mem)
     = get_mem_attrs (MEM_ALIAS_SET (mem), REG_EXPR (reg),
 		     GEN_INT (REG_OFFSET (reg)),
-		     MEM_SIZE (mem), MEM_ALIGN (mem), GET_MODE (mem));
+		     MEM_SIZE (mem), MEM_ALIGN (mem), MEM_ADDR_SPACE (mem), GET_MODE (mem));
 }
 
 /* Set the alias set of MEM to SET.  */
@@ -1880,17 +1886,27 @@ set_mem_alias_set (rtx mem, alias_set_ty
 #endif
 
   MEM_ATTRS (mem) = get_mem_attrs (set, MEM_EXPR (mem), MEM_OFFSET (mem),
-				   MEM_SIZE (mem), MEM_ALIGN (mem),
+				   MEM_SIZE (mem), MEM_ALIGN (mem), MEM_ADDR_SPACE (mem),
 				   GET_MODE (mem));
 }
 
+/* Set the address space of MEM to ADDRSPACE (target-defined).  */
+
+void
+set_mem_addr_space (rtx mem, addr_space_t addrspace)
+{
+  MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem),
+				   MEM_OFFSET (mem), MEM_SIZE (mem), MEM_ALIGN (mem),
+				   addrspace, GET_MODE (mem));
+}
+
 /* Set the alignment of MEM to ALIGN bits.  */
 
 void
 set_mem_align (rtx mem, unsigned int align)
 {
   MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem),
-				   MEM_OFFSET (mem), MEM_SIZE (mem), align,
+				   MEM_OFFSET (mem), MEM_SIZE (mem), align, MEM_ADDR_SPACE (mem),
 				   GET_MODE (mem));
 }
 
@@ -1901,7 +1917,7 @@ set_mem_expr (rtx mem, tree expr)
 {
   MEM_ATTRS (mem)
     = get_mem_attrs (MEM_ALIAS_SET (mem), expr, MEM_OFFSET (mem),
-		     MEM_SIZE (mem), MEM_ALIGN (mem), GET_MODE (mem));
+		     MEM_SIZE (mem), MEM_ALIGN (mem), MEM_ADDR_SPACE (mem), GET_MODE (mem));
 }
 
 /* Set the offset of MEM to OFFSET.  */
@@ -1910,7 +1926,7 @@ void
 set_mem_offset (rtx mem, rtx offset)
 {
   MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem),
-				   offset, MEM_SIZE (mem), MEM_ALIGN (mem),
+				   offset, MEM_SIZE (mem), MEM_ALIGN (mem), MEM_ADDR_SPACE (mem),
 				   GET_MODE (mem));
 }
 
@@ -1920,7 +1936,7 @@ void
 set_mem_size (rtx mem, rtx size)
 {
   MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem),
-				   MEM_OFFSET (mem), size, MEM_ALIGN (mem),
+				   MEM_OFFSET (mem), size, MEM_ALIGN (mem), MEM_ADDR_SPACE (mem),
 				   GET_MODE (mem));
 }
 
@@ -1931,7 +1947,8 @@ set_mem_size (rtx mem, rtx size)
    attributes are not changed.  */
 
 static rtx
-change_address_1 (rtx memref, enum machine_mode mode, rtx addr, int validate)
+change_address_1 (rtx memref, enum machine_mode mode, rtx addr, int validate,
+		  addr_space_t as)
 {
   rtx new_rtx;
 
@@ -1941,15 +1958,15 @@ change_address_1 (rtx memref, enum machi
   if (addr == 0)
     addr = XEXP (memref, 0);
   if (mode == GET_MODE (memref) && addr == XEXP (memref, 0)
-      && (!validate || memory_address_p (mode, addr)))
+      && (!validate || memory_address_addr_space_p (mode, addr, as)))
     return memref;
 
   if (validate)
     {
       if (reload_in_progress || reload_completed)
-	gcc_assert (memory_address_p (mode, addr));
+	gcc_assert (memory_address_addr_space_p (mode, addr, as));
       else
-	addr = memory_address (mode, addr);
+	addr = memory_address_addr_space (mode, addr, as);
     }
 
   if (rtx_equal_p (addr, XEXP (memref, 0)) && mode == GET_MODE (memref))
@@ -1957,16 +1974,23 @@ change_address_1 (rtx memref, enum machi
 
   new_rtx = gen_rtx_MEM (mode, addr);
   MEM_COPY_ATTRIBUTES (new_rtx, memref);
+
+  if (as != MEM_ADDR_SPACE (memref))
+    set_mem_addr_space (new_rtx, as);
+
   return new_rtx;
 }
 
-/* Like change_address_1 with VALIDATE nonzero, but we are not saying in what
-   way we are changing MEMREF, so we only preserve the alias set.  */
+/* Like change_address_1 with VALIDATE nonzero, and the address space set, but
+   we are not saying in what way we are changing MEMREF, so we only preserve
+   the alias set.  */
 
 rtx
-change_address (rtx memref, enum machine_mode mode, rtx addr)
+change_address_addr_space (rtx memref, enum machine_mode mode, rtx addr,
+			   addr_space_t as)
 {
-  rtx new_rtx = change_address_1 (memref, mode, addr, 1), size;
+  rtx new_rtx = change_address_1 (memref, mode, addr, 1, as);
+  rtx size;
   enum machine_mode mmode = GET_MODE (new_rtx);
   unsigned int align;
 
@@ -1980,19 +2004,33 @@ change_address (rtx memref, enum machine
 	  || (MEM_EXPR (memref) == NULL
 	      && MEM_OFFSET (memref) == NULL
 	      && MEM_SIZE (memref) == size
+	      && MEM_ADDR_SPACE (memref) == as
 	      && MEM_ALIGN (memref) == align))
 	return new_rtx;
 
       new_rtx = gen_rtx_MEM (mmode, XEXP (memref, 0));
       MEM_COPY_ATTRIBUTES (new_rtx, memref);
+
+      if (as != MEM_ADDR_SPACE (new_rtx))
+	set_mem_addr_space (new_rtx, as);
     }
 
   MEM_ATTRS (new_rtx)
-    = get_mem_attrs (MEM_ALIAS_SET (memref), 0, 0, size, align, mmode);
+    = get_mem_attrs (MEM_ALIAS_SET (memref), 0, 0, size, align, as, mmode);
 
   return new_rtx;
 }
 
+/* Like change_address_addr_space, except we don't change the named address
+   space.  */
+
+rtx
+change_address (rtx memref, enum machine_mode mode, rtx addr)
+{
+  return change_address_addr_space (memref, mode, addr,
+				    MEM_ADDR_SPACE (memref));
+}
+
 /* Return a memory reference like MEMREF, but with its mode changed
    to MODE and its address offset by OFFSET bytes.  If VALIDATE is
    nonzero, the memory address is forced to be valid.
@@ -2008,10 +2046,14 @@ adjust_address_1 (rtx memref, enum machi
   rtx memoffset = MEM_OFFSET (memref);
   rtx size = 0;
   unsigned int memalign = MEM_ALIGN (memref);
+  addr_space_t as = MEM_ADDR_SPACE (memref);
+  enum machine_mode mem_Pmode = (!as
+				 ? Pmode
+				 : targetm.addr_space.pointer_mode (as));
 
   /* If there are no changes, just return the original memory reference.  */
   if (mode == GET_MODE (memref) && !offset
-      && (!validate || memory_address_p (mode, addr)))
+      && (!validate || memory_address_addr_space_p (mode, addr, as)))
     return memref;
 
   /* ??? Prefer to create garbage instead of creating shared rtl.
@@ -2027,13 +2069,13 @@ adjust_address_1 (rtx memref, enum machi
 	  && offset >= 0
 	  && (unsigned HOST_WIDE_INT) offset
 	      < GET_MODE_ALIGNMENT (GET_MODE (memref)) / BITS_PER_UNIT)
-	addr = gen_rtx_LO_SUM (Pmode, XEXP (addr, 0),
+	addr = gen_rtx_LO_SUM (mem_Pmode, XEXP (addr, 0),
 			       plus_constant (XEXP (addr, 1), offset));
       else
 	addr = plus_constant (addr, offset);
     }
 
-  new_rtx = change_address_1 (memref, mode, addr, validate);
+  new_rtx = change_address_1 (memref, mode, addr, validate, as);
 
   /* Compute the new values of the memory attributes due to this adjustment.
      We add the offsets and update the alignment.  */
@@ -2055,7 +2097,8 @@ adjust_address_1 (rtx memref, enum machi
     size = plus_constant (MEM_SIZE (memref), -offset);
 
   MEM_ATTRS (new_rtx) = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_EXPR (memref),
-				   memoffset, size, memalign, GET_MODE (new_rtx));
+				       memoffset, size, memalign, as,
+				       GET_MODE (new_rtx));
 
   /* At some point, we should validate that this offset is within the object,
      if all the appropriate values are known.  */
@@ -2071,7 +2114,8 @@ rtx
 adjust_automodify_address_1 (rtx memref, enum machine_mode mode, rtx addr,
 			     HOST_WIDE_INT offset, int validate)
 {
-  memref = change_address_1 (memref, VOIDmode, addr, validate);
+  memref = change_address_1 (memref, VOIDmode, addr, validate,
+			     MEM_ADDR_SPACE (memref));
   return adjust_address_1 (memref, mode, offset, validate, 0);
 }
 
@@ -2083,8 +2127,12 @@ rtx
 offset_address (rtx memref, rtx offset, unsigned HOST_WIDE_INT pow2)
 {
   rtx new_rtx, addr = XEXP (memref, 0);
+  addr_space_t as = MEM_ADDR_SPACE (memref);
+  enum machine_mode mem_Pmode = (!as
+				 ? Pmode
+				 : targetm.addr_space.pointer_mode (as));
 
-  new_rtx = simplify_gen_binary (PLUS, Pmode, addr, offset);
+  new_rtx = simplify_gen_binary (PLUS, mem_Pmode, addr, offset);
 
   /* At this point we don't know _why_ the address is invalid.  It
      could have secondary memory references, multiplies or anything.
@@ -2093,16 +2141,17 @@ offset_address (rtx memref, rtx offset, 
      being able to recognize the magic around pic_offset_table_rtx.
      This stuff is fragile, and is yet another example of why it is
      bad to expose PIC machinery too early.  */
-  if (! memory_address_p (GET_MODE (memref), new_rtx)
+  if (! memory_address_addr_space_p (GET_MODE (memref), new_rtx, as)
       && GET_CODE (addr) == PLUS
       && XEXP (addr, 0) == pic_offset_table_rtx)
     {
       addr = force_reg (GET_MODE (addr), addr);
-      new_rtx = simplify_gen_binary (PLUS, Pmode, addr, offset);
+      new_rtx = simplify_gen_binary (PLUS, mem_Pmode, addr, offset);
     }
 
   update_temp_slot_address (XEXP (memref, 0), new_rtx);
-  new_rtx = change_address_1 (memref, VOIDmode, new_rtx, 1);
+  new_rtx = change_address_1 (memref, VOIDmode, new_rtx, 1,
+			      MEM_ADDR_SPACE (memref));
 
   /* If there are no changes, just return the original memory reference.  */
   if (new_rtx == memref)
@@ -2113,7 +2162,7 @@ offset_address (rtx memref, rtx offset, 
   MEM_ATTRS (new_rtx)
     = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_EXPR (memref), 0, 0,
 		     MIN (MEM_ALIGN (memref), pow2 * BITS_PER_UNIT),
-		     GET_MODE (new_rtx));
+		     as, GET_MODE (new_rtx));
   return new_rtx;
 }
 
@@ -2128,7 +2177,8 @@ replace_equiv_address (rtx memref, rtx a
   /* change_address_1 copies the memory attribute structure without change
      and that's exactly what we want here.  */
   update_temp_slot_address (XEXP (memref, 0), addr);
-  return change_address_1 (memref, VOIDmode, addr, 1);
+  return change_address_1 (memref, VOIDmode, addr, 1,
+			   MEM_ADDR_SPACE (memref));
 }
 
 /* Likewise, but the reference is not required to be valid.  */
@@ -2136,7 +2186,7 @@ replace_equiv_address (rtx memref, rtx a
 rtx
 replace_equiv_address_nv (rtx memref, rtx addr)
 {
-  return change_address_1 (memref, VOIDmode, addr, 0);
+  return change_address_1 (memref, VOIDmode, addr, 0, MEM_ADDR_SPACE (memref));
 }
 
 /* Return a memory reference like MEMREF, but with its mode widened to
@@ -2217,7 +2267,7 @@ widen_memory_access (rtx memref, enum ma
   /* ??? Maybe use get_alias_set on any remaining expression.  */
 
   MEM_ATTRS (new_rtx) = get_mem_attrs (0, expr, memoffset, GEN_INT (size),
-				   MEM_ALIGN (new_rtx), mode);
+				   MEM_ALIGN (new_rtx), MEM_ADDR_SPACE (new_rtx), mode);
 
   return new_rtx;
 }
@@ -2244,7 +2294,7 @@ get_spill_slot_decl (bool force_build_p)
   rd = gen_rtx_MEM (BLKmode, frame_pointer_rtx);
   MEM_NOTRAP_P (rd) = 1;
   MEM_ATTRS (rd) = get_mem_attrs (new_alias_set (), d, const0_rtx,
-				  NULL_RTX, 0, BLKmode);
+				  NULL_RTX, 0, 0, BLKmode);
   SET_DECL_RTL (d, rd);
 
   return d;
@@ -2277,7 +2327,7 @@ set_mem_attrs_for_spill (rtx mem)
 
   MEM_ATTRS (mem) = get_mem_attrs (alias, expr, offset,
 				   MEM_SIZE (mem), MEM_ALIGN (mem),
-				   GET_MODE (mem));
+				   0, GET_MODE (mem));
   MEM_NOTRAP_P (mem) = 1;
 }
 
Index: gcc/emit-rtl.h
===================================================================
--- gcc/emit-rtl.h	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/emit-rtl.h	(working copy)
@@ -26,6 +26,9 @@ extern void set_mem_alias_set (rtx, alia
 /* Set the alignment of MEM to ALIGN bits.  */
 extern void set_mem_align (rtx, unsigned int);
 
+/* Set the address space of MEM to ADDRSPACE.  */
+extern void set_mem_addr_space (rtx, addr_space_t);
+
 /* Set the expr for MEM to EXPR.  */
 extern void set_mem_expr (rtx, tree);
 
Index: gcc/explow.c
===================================================================
--- gcc/explow.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/explow.c	(working copy)
@@ -306,7 +306,7 @@ break_out_memory_refs (rtx x)
       rtx op1 = break_out_memory_refs (XEXP (x, 1));
 
       if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
-	x = simplify_gen_binary (GET_CODE (x), Pmode, op0, op1);
+	x = simplify_gen_binary (GET_CODE (x), GET_MODE (x), op0, op1);
     }
 
   return x;
@@ -405,21 +405,25 @@ convert_memory_address (enum machine_mod
 #endif /* defined(POINTERS_EXTEND_UNSIGNED) */
 }
 
-/* Return something equivalent to X but valid as a memory address
-   for something of mode MODE.  When X is not itself valid, this
-   works by copying X or subexpressions of it into registers.  */
+/* Return something equivalent to X but valid as a memory address for something
+   of mode MODE in the named address space AS.  When X is not itself valid,
+   this works by copying X or subexpressions of it into registers.  */
 
 rtx
-memory_address (enum machine_mode mode, rtx x)
+memory_address_addr_space (enum machine_mode mode, rtx x, addr_space_t as)
 {
   rtx oldx = x;
+  enum machine_mode mem_Pmode = ((!as)
+				 ? Pmode
+				 : targetm.addr_space.pointer_mode (as));
 
-  x = convert_memory_address (Pmode, x);
+  if (MEM_P (x) && GET_MODE (x) != mem_Pmode)
+    x = convert_memory_address (mem_Pmode, x);
 
   /* By passing constant addresses through registers
      we get a chance to cse them.  */
   if (! cse_not_expected && CONSTANT_P (x) && CONSTANT_ADDRESS_P (x))
-    x = force_reg (Pmode, x);
+    x = force_reg (mem_Pmode, x);
 
   /* We get better cse by rejecting indirect addressing at this stage.
      Let the combiner create indirect addresses where appropriate.
@@ -431,12 +435,12 @@ memory_address (enum machine_mode mode, 
 	x = break_out_memory_refs (x);
 
       /* At this point, any valid address is accepted.  */
-      if (memory_address_p (mode, x))
+      if (memory_address_addr_space_p (mode, x, as))
 	goto done;
 
       /* If it was valid before but breaking out memory refs invalidated it,
 	 use it the old way.  */
-      if (memory_address_p (mode, oldx))
+      if (memory_address_addr_space_p (mode, oldx, as))
 	{
 	  x = oldx;
 	  goto done;
@@ -446,7 +450,19 @@ memory_address (enum machine_mode mode, 
 	 in certain cases.  This is not necessary since the code
 	 below can handle all possible cases, but machine-dependent
 	 transformations can make better code.  */
-      LEGITIMIZE_ADDRESS (x, oldx, mode, done);
+      if (!as)
+	{
+	  LEGITIMIZE_ADDRESS (x, oldx, mode, done);
+	}
+      else
+	{
+	  rtx y = targetm.addr_space.legitimize_address (x, oldx, mode, as);
+	  if (y)
+	    {
+	      x = y;
+	      goto done;
+	    }
+	}
 
       /* PLUS and MULT can appear in special ways
 	 as the result of attempts to make an address usable for indexing.
@@ -462,12 +478,12 @@ memory_address (enum machine_mode mode, 
 	  rtx constant_term = const0_rtx;
 	  rtx y = eliminate_constant_term (x, &constant_term);
 	  if (constant_term == const0_rtx
-	      || ! memory_address_p (mode, y))
+	      || ! memory_address_addr_space_p (mode, y, as))
 	    x = force_operand (x, NULL_RTX);
 	  else
 	    {
 	      y = gen_rtx_PLUS (GET_MODE (x), copy_to_reg (y), constant_term);
-	      if (! memory_address_p (mode, y))
+	      if (! memory_address_addr_space_p (mode, y, as))
 		x = force_operand (x, NULL_RTX);
 	      else
 		x = y;
@@ -484,13 +500,12 @@ memory_address (enum machine_mode mode, 
 
       /* Last resort: copy the value to a register, since
 	 the register is a valid address.  */
-      else
-	x = force_reg (Pmode, x);
+      x = force_reg (mem_Pmode, x);
     }
 
  done:
 
-  gcc_assert (memory_address_p (mode, x));
+  gcc_assert (memory_address_addr_space_p (mode, x, as));
   /* If we didn't change the address, we are done.  Otherwise, mark
      a reg as a pointer if we have REG or REG + CONST_INT.  */
   if (oldx == x)
@@ -515,14 +530,21 @@ memory_address (enum machine_mode mode, 
 rtx
 validize_mem (rtx ref)
 {
+  addr_space_t as;
+  enum machine_mode mode;
+  rtx mem;
+
   if (!MEM_P (ref))
     return ref;
   ref = use_anchored_address (ref);
-  if (memory_address_p (GET_MODE (ref), XEXP (ref, 0)))
+  mode = GET_MODE (ref);
+  mem = XEXP (ref, 0);
+  as = MEM_ADDR_SPACE (ref);
+  if (memory_address_addr_space_p (mode, mem, as))
     return ref;
 
   /* Don't alter REF itself, since that is probably a stack slot.  */
-  return replace_equiv_address (ref, XEXP (ref, 0));
+  return replace_equiv_address (ref, mem);
 }
 
 /* If X is a memory reference to a member of an object block, try rewriting
Index: gcc/print-tree.c
===================================================================
--- gcc/print-tree.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/print-tree.c	(working copy)
@@ -110,6 +110,8 @@ print_node_brief (FILE *file, const char
 	    fprintf (file, " %s",
 		     IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node))));
 	}
+      if (TYPE_ADDR_SPACE (node))
+	fprintf (file, " address-space-%d", TYPE_ADDR_SPACE (node));
     }
   if (TREE_CODE (node) == IDENTIFIER_NODE)
     fprintf (file, " %s", IDENTIFIER_POINTER (node));
@@ -299,6 +301,9 @@ print_node (FILE *file, const char *pref
   else if (TYPE_P (node) && TYPE_SIZES_GIMPLIFIED (node))
     fputs (" sizes-gimplified", file);
 
+  if (TYPE_P (node) && TYPE_ADDR_SPACE (node))
+    fprintf (file, " address-space-%d", TYPE_ADDR_SPACE (node));
+
   if (TREE_ADDRESSABLE (node))
     fputs (" addressable", file);
   if (TREE_THIS_VOLATILE (node))
Index: gcc/tree-ssa-forwprop.c
===================================================================
--- gcc/tree-ssa-forwprop.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/tree-ssa-forwprop.c	(working copy)
@@ -732,13 +732,28 @@ forward_propagate_addr_expr_1 (tree name
 	  || useless_type_conversion_p (TREE_TYPE (TREE_OPERAND (def_rhs, 0)),
 					TREE_TYPE (rhs))))
     {
-      *lhsp = unshare_expr (TREE_OPERAND (def_rhs, 0));
-      fold_stmt_inplace (use_stmt);
-      tidy_after_forward_propagate_addr (use_stmt);
+      bool valid = true;
+      if (lhsp == gimple_assign_lhs_ptr (use_stmt)
+	  && !useless_type_conversion_p (TREE_TYPE (TREE_OPERAND (def_rhs, 0)),
+					 TREE_TYPE (rhs))
+	  && !CONVERT_EXPR_CODE_P (rhs_code))
+	{
+	  if (rhs_code == SSA_NAME)
+	    gimple_assign_set_rhs_code (use_stmt, NOP_EXPR);
+	  else
+	    valid = false;
+	}
+      if (valid)
+	{
+	  *lhsp = unshare_expr (TREE_OPERAND (def_rhs, 0));
+	  fold_stmt_inplace (use_stmt);
+	  tidy_after_forward_propagate_addr (use_stmt);
 
-      /* Continue propagating into the RHS if this was not the only use.  */
-      if (single_use_p)
-	return true;
+	  /* Continue propagating into the RHS if this was not the only
+	     use.  */
+	  if (single_use_p)
+	    return true;
+	}
     }
 
   /* Strip away any outer COMPONENT_REF, ARRAY_REF or ADDR_EXPR
Index: gcc/varasm.c
===================================================================
--- gcc/varasm.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/varasm.c	(working copy)
@@ -1284,6 +1284,7 @@ make_decl_rtl (tree decl)
   const char *name = 0;
   int reg_number;
   rtx x;
+  enum machine_mode addrmode;
 
   /* Check that we are not being given an automatic variable.  */
   gcc_assert (TREE_CODE (decl) != PARM_DECL
@@ -1428,7 +1429,19 @@ make_decl_rtl (tree decl)
   if (use_object_blocks_p () && use_blocks_for_decl_p (decl))
     x = create_block_symbol (name, get_block_for_decl (decl), -1);
   else
-    x = gen_rtx_SYMBOL_REF (Pmode, name);
+    {
+      if (TREE_TYPE (decl) == error_mark_node)
+	addrmode = Pmode;
+      else
+	{
+	  addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (decl));
+	  addrmode = ((as == 0)
+		      ? Pmode
+		      : targetm.addr_space.pointer_mode (as));
+	}
+
+      x = gen_rtx_SYMBOL_REF (addrmode, name);
+    }
   SYMBOL_REF_WEAK (x) = DECL_WEAK (decl);
   SET_SYMBOL_REF_DECL (x, decl);
 
@@ -6329,14 +6342,6 @@ default_binds_local_p_1 (const_tree exp,
   return local_p;
 }
 
-/* Determine whether or not a pointer mode is valid. Assume defaults
-   of ptr_mode or Pmode - can be overridden.  */
-bool
-default_valid_pointer_mode (enum machine_mode mode)
-{
-  return (mode == ptr_mode || mode == Pmode);
-}
-
 /* Default function to output code that will globalize a label.  A
    target must define GLOBAL_ASM_OP or provide its own function to
    globalize a label.  */
Index: gcc/tree-ssa.c
===================================================================
--- gcc/tree-ssa.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/tree-ssa.c	(working copy)
@@ -1147,6 +1147,12 @@ useless_type_conversion_p_1 (tree outer_
 	  && TYPE_VOLATILE (TREE_TYPE (outer_type)))
 	return false;
 
+      /* Do not lose casts between pointers in different address
+	 spaces.  */
+      if (TYPE_ADDR_SPACE (TREE_TYPE (inner_type))
+	  != TYPE_ADDR_SPACE (TREE_TYPE (outer_type)))
+	return false;
+
       /* Do not lose casts between pointers with different
 	 TYPE_REF_CAN_ALIAS_ALL setting or alias sets.  */
       if ((TYPE_REF_CAN_ALIAS_ALL (inner_type)
@@ -1229,12 +1235,14 @@ useless_type_conversion_p_1 (tree outer_
 bool
 useless_type_conversion_p (tree outer_type, tree inner_type)
 {
-  /* If the outer type is (void *), then the conversion is not
-     necessary.  We have to make sure to not apply this while
-     recursing though.  */
+  /* If the outer type is (void *) and the pointers point to the same named
+     address space, then the conversion is not necessary.  We have to make sure
+     to not apply this while recursing though.  */
   if (POINTER_TYPE_P (inner_type)
       && POINTER_TYPE_P (outer_type)
-      && TREE_CODE (TREE_TYPE (outer_type)) == VOID_TYPE)
+      && TREE_CODE (TREE_TYPE (outer_type)) == VOID_TYPE
+      && (TYPE_ADDR_SPACE (TREE_TYPE (inner_type))
+	  == TYPE_ADDR_SPACE (TREE_TYPE (outer_type))))
     return true;
 
   return useless_type_conversion_p_1 (outer_type, inner_type);
Index: gcc/target-def.h
===================================================================
--- gcc/target-def.h	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/target-def.h	(working copy)
@@ -457,6 +457,72 @@
 #define TARGET_VALID_POINTER_MODE default_valid_pointer_mode
 #endif
 
+#ifndef TARGET_ADDR_SPACE_POINTER_MODE
+#define TARGET_ADDR_SPACE_POINTER_MODE default_addr_space_pointer_mode
+#endif
+
+#ifndef TARGET_ADDR_SPACE_MINUS_TYPE
+#define TARGET_ADDR_SPACE_MINUS_TYPE default_addr_space_minus_type
+#endif
+
+#ifndef TARGET_ADDR_SPACE_NAME
+#define TARGET_ADDR_SPACE_NAME default_addr_space_name
+#endif
+
+#ifndef TARGET_ADDR_SPACE_MEMORY_ADDRESS_P
+#define TARGET_ADDR_SPACE_MEMORY_ADDRESS_P default_addr_space_memory_address_p
+#endif
+
+#ifndef TARGET_ADDR_SPACE_STRICT_MEMORY_ADDRESS_P
+#define TARGET_ADDR_SPACE_STRICT_MEMORY_ADDRESS_P \
+  default_addr_space_strict_memory_address_p
+#endif
+
+#ifndef TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS
+#define TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS \
+  default_addr_space_legitimize_address
+#endif
+
+#ifndef TARGET_ADDR_SPACE_CAN_CONVERT_P
+#define TARGET_ADDR_SPACE_CAN_CONVERT_P default_addr_space_can_convert_p
+#endif
+
+#ifndef TARGET_ADDR_SPACE_NOP_CONVERT_P
+#define TARGET_ADDR_SPACE_NOP_CONVERT_P default_addr_space_nop_convert_p
+#endif
+
+#ifndef TARGET_ADDR_SPACE_SUBSET_P
+#define TARGET_ADDR_SPACE_SUBSET_P default_addr_space_subset_p
+#endif
+
+#ifndef TARGET_ADDR_SPACE_CONVERT
+#define TARGET_ADDR_SPACE_CONVERT default_addr_space_convert
+#endif
+
+#ifndef TARGET_ADDR_SPACE_SECTION_NAME
+#define TARGET_ADDR_SPACE_SECTION_NAME default_addr_space_section_name
+#endif
+
+#ifndef TARGET_ADDR_SPACE_STATIC_INIT_OK_P
+#define TARGET_ADDR_SPACE_STATIC_INIT_OK_P default_addr_space_static_init_ok_p
+#endif
+
+#define TARGET_ADDR_SPACE_HOOKS			\
+  {						\
+    TARGET_ADDR_SPACE_POINTER_MODE,		\
+    TARGET_ADDR_SPACE_MINUS_TYPE,		\
+    TARGET_ADDR_SPACE_NAME,			\
+    TARGET_ADDR_SPACE_MEMORY_ADDRESS_P,		\
+    TARGET_ADDR_SPACE_STRICT_MEMORY_ADDRESS_P,	\
+    TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS,	\
+    TARGET_ADDR_SPACE_CAN_CONVERT_P,		\
+    TARGET_ADDR_SPACE_NOP_CONVERT_P,		\
+    TARGET_ADDR_SPACE_SUBSET_P,			\
+    TARGET_ADDR_SPACE_CONVERT,			\
+    TARGET_ADDR_SPACE_SECTION_NAME,		\
+    TARGET_ADDR_SPACE_STATIC_INIT_OK_P,		\
+  }
+
 #ifndef TARGET_SCALAR_MODE_SUPPORTED_P
 #define TARGET_SCALAR_MODE_SUPPORTED_P default_scalar_mode_supported_p
 #endif
@@ -879,6 +945,7 @@
   TARGET_MIN_DIVISIONS_FOR_RECIP_MUL,		\
   TARGET_MODE_REP_EXTENDED,			\
   TARGET_VALID_POINTER_MODE,                    \
+  TARGET_ADDR_SPACE_HOOKS,			\
   TARGET_SCALAR_MODE_SUPPORTED_P,		\
   TARGET_VECTOR_MODE_SUPPORTED_P,               \
   TARGET_VECTOR_OPAQUE_P,			\
Index: gcc/rtl.h
===================================================================
--- gcc/rtl.h	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/rtl.h	(working copy)
@@ -142,10 +142,11 @@ typedef struct
 typedef struct mem_attrs GTY(())
 {
   alias_set_type alias;		/* Memory alias set.  */
+  unsigned int align;		/* Alignment of MEM in bits.  */
   tree expr;			/* expr corresponding to MEM.  */
   rtx offset;			/* Offset from start of DECL, as CONST_INT.  */
   rtx size;			/* Size in bytes, as a CONST_INT.  */
-  unsigned int align;		/* Alignment of MEM in bits.  */
+  unsigned char addrspace;	/* Address space (0 for generic).  */
 } mem_attrs;
 
 /* Structure used to describe the attributes of a REG in similar way as
@@ -1209,6 +1210,10 @@ do {						\
    RTX that is always a CONST_INT.  */
 #define MEM_OFFSET(RTX) (MEM_ATTRS (RTX) == 0 ? 0 : MEM_ATTRS (RTX)->offset)
 
+/* For a MEM rtx, the address space.  If 0, the MEM belongs to the
+   generic address space.  */
+#define MEM_ADDR_SPACE(RTX) (MEM_ATTRS (RTX) == 0 ? 0 : MEM_ATTRS (RTX)->addrspace)
+
 /* For a MEM rtx, the size in bytes of the MEM, if known, as an RTX that
    is always a CONST_INT.  */
 #define MEM_SIZE(RTX)							\
Index: gcc/output.h
===================================================================
--- gcc/output.h	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/output.h	(working copy)
@@ -619,6 +619,7 @@ extern void default_internal_label (FILE
 extern void default_file_start (void);
 extern void file_end_indicate_exec_stack (void);
 extern bool default_valid_pointer_mode (enum machine_mode);
+extern enum machine_mode default_addr_space_pointer_mode (addr_space_t);
 
 extern void default_elf_asm_output_external (FILE *file, tree,
 					     const char *);
Index: gcc/c-common.c
===================================================================
--- gcc/c-common.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/c-common.c	(working copy)
@@ -748,6 +748,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 =
@@ -7763,7 +7768,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/c-common.h
===================================================================
--- gcc/c-common.h	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/c-common.h	(working copy)
@@ -118,6 +118,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,
@@ -227,6 +251,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[];
 
Index: gcc/config.gcc
===================================================================
--- gcc/config.gcc	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/config.gcc	(working copy)
@@ -2294,7 +2294,7 @@ sparc64-*-netbsd*)
 spu-*-elf*)
 	tm_file="dbxelf.h elfos.h spu/spu-elf.h spu/spu.h"
 	tmake_file="spu/t-spu-elf"
-	extra_headers="spu_intrinsics.h spu_internals.h vmx2spu.h spu_mfcio.h vec_types.h"
+	extra_headers="spu_intrinsics.h spu_internals.h vmx2spu.h spu_mfcio.h vec_types.h spu_cache.h"
 	extra_modes=spu/spu-modes.def
 	c_target_objs="${c_target_objs} spu-c.o"
 	cxx_target_objs="${cxx_target_objs} spu-c.o"
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk/gcc/Makefile.in)	(revision 143352)
+++ gcc/Makefile.in	(.../gcc/Makefile.in)	(working copy)
@@ -1832,7 +1832,7 @@ c-decl.o : c-decl.c $(CONFIG_H) $(SYSTEM
     opts.h $(C_PRAGMA_H) gt-c-decl.h $(CGRAPH_H) $(HASHTAB_H) libfuncs.h \
     except.h $(LANGHOOKS_DEF_H) $(TREE_DUMP_H) $(C_COMMON_H) $(CPPLIB_H) \
     $(DIAGNOSTIC_H) $(INPUT_H) langhooks.h $(GIMPLE_H) tree-mudflap.h  \
-    pointer-set.h $(BASIC_BLOCK_H) $(GIMPLE_H) tree-iterator.h
+    pointer-set.h $(BASIC_BLOCK_H) $(GIMPLE_H) tree-iterator.h targhooks.h
 c-typeck.o : c-typeck.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
     $(TREE_H) $(C_TREE_H) $(TARGET_H) $(FLAGS_H) intl.h output.h $(EXPR_H) \
     $(RTL_H) $(TOPLEV_H) $(TM_P_H) langhooks.h $(GGC_H) $(TREE_FLOW_H) \
@@ -1902,7 +1902,8 @@ c-common.o : c-common.c $(CONFIG_H) $(SY
 
 c-pretty-print.o : c-pretty-print.c $(C_PRETTY_PRINT_H) \
 	$(C_TREE_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(REAL_H) \
-	$(DIAGNOSTIC_H) tree-iterator.h fixed-value.h
+	$(DIAGNOSTIC_H) tree-iterator.h fixed-value.h $(TARGET_DEF_H) \
+	$(TARGET_H)
 
 c-opts.o : c-opts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H)		\
         $(TREE_H) $(C_PRAGMA_H) $(FLAGS_H) $(TOPLEV_H) langhooks.h		\
@@ -2053,8 +2054,9 @@ prefix.o: prefix.c $(CONFIG_H) $(SYSTEM_
 	-DPREFIX=\"$(prefix)\" -DBASEVER=$(BASEVER_s) \
 	  -c $(srcdir)/prefix.c $(OUTPUT_OPTION)
 
-convert.o: convert.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
-   $(FLAGS_H) convert.h $(TOPLEV_H) langhooks.h $(REAL_H) fixed-value.h
+convert.o: convert.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
+   $(TREE_H) $(FLAGS_H) convert.h $(TOPLEV_H) langhooks.h $(REAL_H) \
+   fixed-value.h $(TARGET_H)
 
 double-int.o: double-int.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H)
 
@@ -2426,11 +2428,11 @@ tree-nomudflap.o : $(CONFIG_H) $(SYSTEM_
 tree-pretty-print.o : tree-pretty-print.c $(CONFIG_H) $(SYSTEM_H) \
    $(TREE_H) $(DIAGNOSTIC_H) $(REAL_H) $(HASHTAB_H) $(TREE_FLOW_H) \
    $(TM_H) coretypes.h tree-iterator.h tree-chrec.h langhooks.h tree-pass.h \
-   value-prof.h fixed-value.h output.h
+   value-prof.h fixed-value.h output.h $(TARGET_H) $(TARGET_DEF_H)
 fold-const.o : fold-const.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(TREE_H) $(FLAGS_H) $(REAL_H) $(TOPLEV_H) $(HASHTAB_H) $(EXPR_H) $(RTL_H) \
    $(GGC_H) $(TM_P_H) langhooks.h $(MD5_H) intl.h fixed-value.h $(TARGET_H) \
-   $(GIMPLE_H)
+   $(GIMPLE_H) $(TARGET_H)
 diagnostic.o : diagnostic.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(TREE_H) version.h $(TM_P_H) $(FLAGS_H) $(INPUT_H) $(TOPLEV_H) intl.h \
    $(DIAGNOSTIC_H) langhooks.h $(LANGHOOKS_DEF_H) diagnostic.def opts.h
@@ -2571,7 +2573,7 @@ emit-rtl.o : emit-rtl.c $(CONFIG_H) $(SY
    $(TREE_H) $(FLAGS_H) $(FUNCTION_H) $(REGS_H) insn-config.h $(RECOG_H) \
    $(GGC_H) $(EXPR_H) hard-reg-set.h $(BITMAP_H) $(TOPLEV_H) $(BASIC_BLOCK_H) \
    $(HASHTAB_H) $(TM_P_H) debug.h langhooks.h tree-pass.h gt-emit-rtl.h \
-   $(REAL_H) $(DF_H)
+   $(REAL_H) $(DF_H) $(TARGET_H)
 real.o : real.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
    $(TOPLEV_H) $(TM_P_H) $(REAL_H) dfp.h
 dfp.o : dfp.c dfp.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H)	$(TREE_H) \
@@ -2779,7 +2781,7 @@ alloc-pool.o : alloc-pool.c $(CONFIG_H) 
 auto-inc-dec.o : auto-inc-dec.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(TREE_H) $(RTL_H) $(TM_P_H) hard-reg-set.h $(BASIC_BLOCK_H) insn-config.h \
    $(REGS_H) $(FLAGS_H) output.h $(FUNCTION_H) except.h $(TOPLEV_H) $(RECOG_H) \
-   $(EXPR_H) $(TIMEVAR_H) tree-pass.h $(DF_H) $(DBGCNT_H)
+   $(EXPR_H) $(TIMEVAR_H) tree-pass.h $(DF_H) $(DBGCNT_H) $(TARGET_H)
 cfg.o : cfg.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(FLAGS_H) \
    $(REGS_H) hard-reg-set.h output.h $(TOPLEV_H) $(FUNCTION_H) except.h $(GGC_H) \
    $(TM_P_H) $(TIMEVAR_H) $(OBSTACK_H) $(TREE_H) alloc-pool.h \
Index: gcc/convert.c
===================================================================
--- gcc/convert.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk)	(revision 143348)
+++ gcc/convert.c	(working copy)
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.  
 #include "langhooks.h"
 #include "real.h"
 #include "fixed-value.h"
+#include "target.h"
 
 /* Convert EXPR to some pointer or reference type TYPE.
    EXPR must be pointer, reference, integer, enumeral, or literal zero;
@@ -42,6 +43,11 @@ along with GCC; see the file COPYING3.  
 tree
 convert_to_pointer (tree type, tree expr)
 {
+  addr_space_t to_as = TYPE_ADDR_SPACE (TREE_TYPE (type));
+  addr_space_t from_as;
+  enum tree_code tcode;
+  int pointer_size;
+
   if (TREE_TYPE (expr) == type)
     return expr;
 
@@ -53,15 +59,48 @@ convert_to_pointer (tree type, tree expr
     {
     case POINTER_TYPE:
     case REFERENCE_TYPE:
-      return fold_build1 (NOP_EXPR, type, expr);
+      /* If the pointers point to different address spaces, see if we can do the
+	 convert, and if we can do the convert, whether the conversion is a NOP
+	 or not.  */
+      tcode = NOP_EXPR;
+      from_as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (expr)));
+      if (to_as != from_as)
+	{
+	  if (! targetm.addr_space.can_convert_p (from_as, to_as))
+	    {
+	      if (!from_as)
+		error ("cannot convert generic address space pointers to "
+		       "%s address space pointers",
+		       targetm.addr_space.name (to_as));
+	      else if (!to_as)
+		error ("cannot convert %s address space pointers to "
+		       "generic address space pointers",
+		       targetm.addr_space.name (from_as));
+	      else
+		error ("cannot convert %s address space pointers to "
+		       "%s address space pointers",
+		       targetm.addr_space.name (from_as),
+		       targetm.addr_space.name (to_as));
+
+	      return convert_to_pointer (type, integer_zero_node);
+	    }
+
+	  if (! targetm.addr_space.nop_convert_p (from_as, to_as))
+	    tcode = CONVERT_EXPR;
+	}
+      return fold_build1 (tcode, type, expr);
 
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
-      if (TYPE_PRECISION (TREE_TYPE (expr)) != POINTER_SIZE)
-	expr = fold_build1 (NOP_EXPR,
-                            lang_hooks.types.type_for_size (POINTER_SIZE, 0),
-			    expr);
+      /* Figure out the native pointer size, depending on the address space.  */
+      pointer_size = (!to_as
+		      ? POINTER_SIZE
+		      : GET_MODE_BITSIZE (targetm.addr_space.pointer_mode (to_as))); 
+
+      if (TYPE_PRECISION (TREE_TYPE (expr)) != pointer_size)
+	expr = fold_build1 (NOP_EXPR, lang_hooks.types.type_for_size (pointer_size, 0), expr);
+
       return fold_build1 (CONVERT_EXPR, type, expr);
 
 
@@ -480,15 +519,30 @@ convert_to_integer (tree type, tree expr
     {
     case POINTER_TYPE:
     case REFERENCE_TYPE:
-      if (integer_zerop (expr))
-	return build_int_cst (type, 0);
+      {
+ 	int pointer_size;
+	addr_space_t as;
+
+ 	if (integer_zerop (expr))
+ 	  return build_int_cst (type, 0);
 
-      /* Convert to an unsigned integer of the correct width first,
-	 and from there widen/truncate to the required type.  */
-      expr = fold_build1 (CONVERT_EXPR,
-			  lang_hooks.types.type_for_size (POINTER_SIZE, 0),
-			  expr);
-      return fold_convert (type, expr);
+ 	/* Convert to an unsigned integer of the correct width first,
+ 	   and from there widen/truncate to the required type.  */
+	as = TYPE_ADDR_SPACE (TREE_TYPE (intype));
+	if (!as)
+	  pointer_size = POINTER_SIZE;
+
+	else
+	  {
+	    enum machine_mode mode = targetm.addr_space.pointer_mode (as);
+	    pointer_size = GET_MODE_BITSIZE (mode);
+	  }
+
+ 	expr = fold_build1 (CONVERT_EXPR,
+ 			    lang_hooks.types.type_for_size (pointer_size, 0),
+ 			    expr);
+ 	return fold_build1 (NOP_EXPR, type, expr);
+      }
 
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:

Property changes on: .
___________________________________________________________________
Name: svnmerge-integrated
   + /trunk:1-143346


-- 
Michael Meissner, IBM
4 Technology Place Drive, MS 2203A, Westford, MA, 01886, USA
meissner@linux.vnet.ibm.com



More information about the Gcc-patches mailing list