This adds two hooks to determine address spaces for local and global variables, and changes various places in the compiler to ensure stuff goes to the right place.
If a type is given an address space in this way, the TYPE_QUAL_AS_IMPLICIT is set. Such a flag is needed to properly handle such types in situations like passing them to varargs and old-style functions, and to make typeof behave as expected. gcc/c-family/ * c-common.c (c_common_nodes_and_builtins): If globals need to go into a specific address space, rebuild the char array type nodes accordingly. gcc/c/ * c-decl.c (start_function): Make the result live in the for_frame address space. (build_compound_literal): Choose an appropriate address space. (grokdeclarator): If no address space is specified, use the frame or global address space implicitly. * c-parser.c (c_parser_typeof_specifier): If it is set, drop the address space from the returned type. * c-typeck.c (convert_arguments): If we have no type, and a pointer arg which points to a type with implicit address space, convert the pointer so as to point to the generic address space. gcc/ * target.def (for_frame, for_global): New hooks in addr_space. * cfgexpand.c (expand_one_stack_var_at): Use the frame address space. * emit-rtl.c (gen_frame_mem): Likewise. * function.c (assign_stack_local_1, assign_stack_temp_for_type): Likewise. (assign_parms_augmented_arg_list, assign_parms_find_data_types): Use build_pointer_type_in_frame. * calls.c (initialize_argument_information): When we make a copy, ensure the decl for it has the for_frame address space. * targhooks.c (std_gimplify_va_arg_expr): If an arg is passed by reference, assume it lives in the for_frame address space if that isn't the generic one. * tree-core.h (struct tree_base): Take a new as_implicit_flag out of spare0. (enum cv_qualifier): Add TYPE_QUAL_AS_IMPLICIT. * tree.h (build_pointer_type_in_frame): Declare. (TYPE_AS_IMPLICIT): New macro. (TYPE_QUALS): Take TYPE_QUAL_AS_IMPLICIT into account. * tree.c (set_type_quals): Likewise. (build_pointer_type_in_frame): New function. * targhooks.c (hook_return_generic_addr_space): New function. (hook_return_generic_addr_space_bool): New function. * targhooks.h (hook_return_generic_addr_space, (hook_return_generic_addr_space_bool): Declare. * tree-switch-conversion.c: Include "target.h". (build_one_array): Use the for_global hook to determine address space. * varasm.c (build_constant_desc): Likewise. * doc/tm.texi.in (TARGET_ADDR_SPACE_FOR_FRAME, TARGET_ADDR_SPACE_FOR_GLOBAL): Add hooks. * doc/tm.texi: Regenerate. ------------------------------------------------------------------------ Index: gcc/doc/tm.texi =================================================================== --- gcc/doc/tm.texi.orig +++ gcc/doc/tm.texi @@ -10330,6 +10330,17 @@ guaranteed that one of the two address s as determined by the @code{TARGET_ADDR_SPACE_SUBSET_P} target hook. @end deftypefn +@deftypefn {Target Hook} addr_space_t TARGET_ADDR_SPACE_FOR_FRAME (void) +Define this if memory locations in the stack frame should use a different +address space than the default. It returns the address space to use. +@end deftypefn + +@deftypefn {Target Hook} addr_space_t TARGET_ADDR_SPACE_FOR_GLOBAL (bool @var{constp}) +Define this if global memory locations should use a different +address space than the default. It returns the address space to use. +If @var{constp} is nonzero, the variable will be constant. +@end deftypefn + @node Misc @section Miscellaneous Parameters @cindex parameters, miscellaneous Index: gcc/doc/tm.texi.in =================================================================== --- gcc/doc/tm.texi.in.orig +++ gcc/doc/tm.texi.in @@ -7669,6 +7669,10 @@ c_register_addr_space ("__ea", ADDR_SPAC @hook TARGET_ADDR_SPACE_CONVERT +@hook TARGET_ADDR_SPACE_FOR_FRAME + +@hook TARGET_ADDR_SPACE_FOR_GLOBAL + @node Misc @section Miscellaneous Parameters @cindex parameters, miscellaneous Index: gcc/targhooks.c =================================================================== --- gcc/targhooks.c.orig +++ gcc/targhooks.c @@ -1642,7 +1642,17 @@ std_gimplify_va_arg_expr (tree valist, t indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false); if (indirect) - type = build_pointer_type (type); + { + /* We assume that if there is a frame address space, the caller makes + a copy. */ + addr_space_t as = targetm.addr_space.for_frame (); + if (!ADDR_SPACE_GENERIC_P (as)) + type + = build_qualified_type (type, + TYPE_QUALS_NO_ADDR_SPACE (type) + | ENCODE_QUAL_ADDR_SPACE (as)); + type = build_pointer_type (type); + } align = PARM_BOUNDARY / BITS_PER_UNIT; boundary = targetm.calls.function_arg_boundary (TYPE_MODE (type), type); @@ -1750,4 +1760,16 @@ can_use_doloop_if_innermost (double_int, return loop_depth == 1; } +addr_space_t +hook_return_generic_addr_space (void) +{ + return ADDR_SPACE_GENERIC; +} + +addr_space_t +hook_return_generic_addr_space_bool (bool) +{ + return ADDR_SPACE_GENERIC; +} + #include "gt-targhooks.h" Index: gcc/targhooks.h =================================================================== --- gcc/targhooks.h.orig +++ gcc/targhooks.h @@ -164,6 +164,9 @@ extern rtx default_addr_space_legitimize addr_space_t); extern bool default_addr_space_subset_p (addr_space_t, addr_space_t); extern rtx default_addr_space_convert (rtx, tree, tree); +extern addr_space_t hook_return_generic_addr_space (void); +extern addr_space_t hook_return_generic_addr_space_bool (bool); + extern unsigned int default_case_values_threshold (void); extern bool default_have_conditional_execution (void); Index: gcc/c-family/c-common.c =================================================================== --- gcc/c-family/c-common.c.orig +++ gcc/c-family/c-common.c @@ -5560,6 +5560,23 @@ c_common_nodes_and_builtins (void) char32_array_type_node = build_array_type (char32_type_node, array_domain_type); + addr_space_t as = targetm.addr_space.for_global (true); + if (!ADDR_SPACE_GENERIC_P (as)) + { + int quals = ENCODE_QUAL_ADDR_SPACE (as) | TYPE_QUAL_AS_IMPLICIT; + char_array_type_node + = build_array_type (build_qualified_type (char_type_node, quals), + array_domain_type); + char16_array_type_node + = build_array_type (build_qualified_type (char16_type_node, quals), + array_domain_type); + char32_array_type_node + = build_array_type (build_qualified_type (char32_type_node, quals), + array_domain_type); + wchar_array_type_node + = build_array_type (build_qualified_type (wchar_type_node, quals), + array_domain_type); + } wint_type_node = TREE_TYPE (identifier_global_value (get_identifier (WINT_TYPE))); Index: gcc/c/c-parser.c =================================================================== --- gcc/c/c-parser.c.orig +++ gcc/c/c-parser.c @@ -2994,6 +2994,9 @@ c_parser_typeof_specifier (c_parser *par error_at (here, "%<typeof%> applied to a bit-field"); mark_exp_read (expr.value); ret.spec = TREE_TYPE (expr.value); + if (ret.spec != error_mark_node && TYPE_AS_IMPLICIT (ret.spec)) + ret.spec = build_qualified_type (ret.spec, + TYPE_QUALS_NO_ADDR_SPACE (ret.spec)); was_vm = variably_modified_type_p (ret.spec, NULL_TREE); /* This is returned with the type so that when the type is evaluated, this can be evaluated. */ Index: gcc/c/c-typeck.c =================================================================== --- gcc/c/c-typeck.c.orig +++ gcc/c/c-typeck.c @@ -3312,8 +3312,19 @@ convert_arguments (tree typelist, vec<tr return -1; } else - /* Convert `short' and `char' to full-size `int'. */ - parmval = default_conversion (val); + { + if (POINTER_TYPE_P (valtype) + && TYPE_AS_IMPLICIT (TREE_TYPE (valtype))) + { + tree basetype = TREE_TYPE (valtype); + int quals = TYPE_QUALS_NO_ADDR_SPACE (basetype); + basetype = build_qualified_type (basetype, quals); + basetype = build_pointer_type (basetype); + val = convert (basetype, val); + } + /* Convert `short' and `char' to full-size `int'. */ + parmval = default_conversion (val); + } (*values)[parmnum] = parmval; if (parmval == error_mark_node) Index: gcc/c/c-decl.c =================================================================== --- gcc/c/c-decl.c.orig +++ gcc/c/c-decl.c @@ -4665,6 +4665,17 @@ build_compound_literal (location_t loc, || init == error_mark_node) return error_mark_node; + addr_space_t as; + if (current_function_decl) + as = targetm.addr_space.for_frame (); + else + as = targetm.addr_space.for_global (!non_const); + if (!ADDR_SPACE_GENERIC_P (as) + && ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (type))) + type = build_qualified_type (type, + (TYPE_QUALS_NO_ADDR_SPACE (type) + | ENCODE_QUAL_ADDR_SPACE (as))); + decl = build_decl (loc, VAR_DECL, NULL_TREE, type); DECL_EXTERNAL (decl) = 0; TREE_PUBLIC (decl) = 0; @@ -5850,6 +5861,33 @@ grokdeclarator (const struct c_declarato c_addr_space_name (address_space)); } } + else if ((current_function_scope + || (decl_context == PARM + && TREE_CODE (type) != ARRAY_TYPE + && TREE_CODE (type) != VOID_TYPE)) + && (storage_class == csc_auto || storage_class == csc_none) + && decl_context != TYPENAME) + { + addr_space_t new_as = targetm.addr_space.for_frame (); + if (!ADDR_SPACE_GENERIC_P (new_as)) + type_quals = (CLEAR_QUAL_ADDR_SPACE (type_quals) + | TYPE_QUAL_AS_IMPLICIT + | ENCODE_QUAL_ADDR_SPACE (new_as)); + } + else if ((!current_function_scope + || storage_class == csc_static + || storage_class == csc_extern) + && decl_context == NORMAL + && declarator->kind != cdk_function + && storage_class != csc_typedef) + { + bool is_const = (type_quals & TYPE_QUAL_CONST) != 0; + addr_space_t new_as = targetm.addr_space.for_global (is_const); + if (!ADDR_SPACE_GENERIC_P (new_as)) + type_quals = (CLEAR_QUAL_ADDR_SPACE (type_quals) + | TYPE_QUAL_AS_IMPLICIT + | ENCODE_QUAL_ADDR_SPACE (new_as)); + } /* Check the type and width of a bit-field. */ if (bitfield) @@ -8024,6 +8062,12 @@ start_function (struct c_declspecs *decl declare_parm_level (); restype = TREE_TYPE (TREE_TYPE (current_function_decl)); + addr_space_t as = targetm.addr_space.for_frame (); + if (!ADDR_SPACE_GENERIC_P (as)) + restype + = build_qualified_type (restype, + TYPE_QUALS_NO_ADDR_SPACE (restype) + | ENCODE_QUAL_ADDR_SPACE (as)); resdecl = build_decl (loc, RESULT_DECL, NULL_TREE, restype); DECL_ARTIFICIAL (resdecl) = 1; DECL_IGNORED_P (resdecl) = 1; Index: gcc/target.def =================================================================== --- gcc/target.def.orig +++ gcc/target.def @@ -3017,6 +3017,21 @@ as determined by the @code{TARGET_ADDR_S rtx, (rtx op, tree from_type, tree to_type), default_addr_space_convert) +DEFHOOK +(for_frame, + "Define this if memory locations in the stack frame should use a different\n\ +address space than the default. It returns the address space to use.", + addr_space_t, (void), + hook_return_generic_addr_space) + +DEFHOOK +(for_global, + "Define this if global memory locations should use a different\n\ +address space than the default. It returns the address space to use.\n\ +If @var{constp} is nonzero, the variable will be constant.", + addr_space_t, (bool constp), + hook_return_generic_addr_space_bool) + HOOK_VECTOR_END (addr_space) #undef HOOK_PREFIX Index: gcc/tree.c =================================================================== --- gcc/tree.c.orig +++ gcc/tree.c @@ -6078,6 +6078,7 @@ set_type_quals (tree type, int type_qual TYPE_VOLATILE (type) = (type_quals & TYPE_QUAL_VOLATILE) != 0; TYPE_RESTRICT (type) = (type_quals & TYPE_QUAL_RESTRICT) != 0; TYPE_ATOMIC (type) = (type_quals & TYPE_QUAL_ATOMIC) != 0; + TYPE_AS_IMPLICIT (type) = (type_quals & TYPE_QUAL_AS_IMPLICIT) != 0; TYPE_ADDR_SPACE (type) = DECODE_QUAL_ADDR_SPACE (type_quals); } @@ -7581,6 +7582,22 @@ build_pointer_type (tree to_type) return build_pointer_type_for_mode (to_type, pointer_mode, false); } +/* Like build_pointer_type, but adjust the address space of the resulting + pointer type as appropriate for an object living in the stack frame. */ + +tree +build_pointer_type_in_frame (tree to_type) +{ + tree type = build_pointer_type (to_type); + addr_space_t as = targetm.addr_space.for_frame (); + if (!ADDR_SPACE_GENERIC_P (as)) + type + = build_qualified_type (type, + TYPE_QUALS_NO_ADDR_SPACE (type) + | ENCODE_QUAL_ADDR_SPACE (as)); + return type; +} + /* Same as build_pointer_type_for_mode, but for REFERENCE_TYPE. */ tree Index: gcc/tree.h =================================================================== --- gcc/tree.h.orig +++ gcc/tree.h @@ -1628,6 +1628,11 @@ extern void protected_set_expr_location /* If nonzero, type's name shouldn't be emitted into debug info. */ #define TYPE_NAMELESS(NODE) (TYPE_CHECK (NODE)->base.u.bits.nameless_flag) +/* If nonzero, the address space was chosen implicitly due to target + requirements. */ +#define TYPE_AS_IMPLICIT(NODE) \ + (TYPE_CHECK (NODE)->base.u.bits.as_implicit_flag) + /* The address space the type is in. */ #define TYPE_ADDR_SPACE(NODE) (TYPE_CHECK (NODE)->base.u.bits.address_space) @@ -1649,6 +1654,7 @@ extern void protected_set_expr_location | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE) \ | (TYPE_ATOMIC (NODE) * TYPE_QUAL_ATOMIC) \ | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT) \ + | (TYPE_AS_IMPLICIT (NODE) * TYPE_QUAL_AS_IMPLICIT) \ | (ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (NODE))))) /* The same as TYPE_QUALS without the address space qualifications. */ @@ -3604,6 +3610,7 @@ extern tree unsigned_type_for (tree); extern tree truth_type_for (tree); extern tree build_pointer_type_for_mode (tree, enum machine_mode, bool); extern tree build_pointer_type (tree); +extern tree build_pointer_type_in_frame (tree); extern tree build_reference_type_for_mode (tree, enum machine_mode, bool); extern tree build_reference_type (tree); extern tree build_vector_type_for_mode (tree, enum machine_mode); Index: gcc/function.c =================================================================== --- gcc/function.c.orig +++ gcc/function.c @@ -478,6 +478,7 @@ assign_stack_local_1 (enum machine_mode x = gen_rtx_MEM (mode, addr); set_mem_align (x, alignment_in_bits); + set_mem_addr_space (x, targetm.addr_space.for_frame ()); MEM_NOTRAP_P (x) = 1; stack_slot_list @@ -886,6 +887,7 @@ assign_stack_temp_for_type (enum machine /* Create a new MEM rtx to avoid clobbering MEM flags of old slots. */ slot = gen_rtx_MEM (mode, XEXP (p->slot, 0)); + set_mem_addr_space (slot, targetm.addr_space.for_frame ()); stack_slot_list = gen_rtx_EXPR_LIST (VOIDmode, slot, stack_slot_list); /* If we know the alias set for the memory that will be used, use @@ -2299,7 +2301,7 @@ assign_parms_augmented_arg_list (struct && ! cfun->returns_pcc_struct && targetm.calls.struct_value_rtx (TREE_TYPE (fndecl), 1) == 0) { - tree type = build_pointer_type (TREE_TYPE (fntype)); + tree type = build_pointer_type_in_frame (TREE_TYPE (fntype)); tree decl; decl = build_decl (DECL_SOURCE_LOCATION (fndecl), @@ -2381,7 +2383,7 @@ assign_parm_find_data_types (struct assi if (pass_by_reference (&all->args_so_far_v, passed_mode, passed_type, data->named_arg)) { - passed_type = nominal_type = build_pointer_type (passed_type); + passed_type = nominal_type = build_pointer_type_in_frame (passed_type); data->passed_pointer = true; passed_mode = nominal_mode = TYPE_MODE (nominal_type); } Index: gcc/calls.c =================================================================== --- gcc/calls.c.orig +++ gcc/calls.c @@ -1270,6 +1270,13 @@ initialize_argument_information (int num if (!callee_copies && *ecf_flags & ECF_PURE) *ecf_flags &= ~(ECF_PURE | ECF_LOOPING_CONST_OR_PURE); + addr_space_t as = MEM_ADDR_SPACE (copy); + if (!ADDR_SPACE_GENERIC_P (as)) + type + = build_qualified_type (type, + TYPE_QUALS_NO_ADDR_SPACE (type) + | ENCODE_QUAL_ADDR_SPACE (as)); + args[i].tree_value = build_fold_addr_expr_loc (loc, make_tree (type, copy)); type = TREE_TYPE (args[i].tree_value); Index: gcc/emit-rtl.c =================================================================== --- gcc/emit-rtl.c.orig +++ gcc/emit-rtl.c @@ -662,12 +662,13 @@ gen_frame_mem (enum machine_mode mode, r rtx mem = gen_rtx_MEM (mode, addr); MEM_NOTRAP_P (mem) = 1; set_mem_alias_set (mem, get_frame_alias_set ()); + set_mem_addr_space (mem, targetm.addr_space.for_frame ()); return mem; } /* Generate a MEM referring to a temporary use of the stack, not part - of the fixed stack frame. For example, something which is pushed - by a target splitter. */ + of the fixed stack frame. For example, something which is pushed + by a target splitter. */ rtx gen_tmp_stack_mem (enum machine_mode mode, rtx addr) { Index: gcc/cfgexpand.c =================================================================== --- gcc/cfgexpand.c.orig +++ gcc/cfgexpand.c @@ -850,6 +850,7 @@ expand_one_stack_var_at (tree decl, rtx x = plus_constant (Pmode, base, offset); x = gen_rtx_MEM (DECL_MODE (SSAVAR (decl)), x); + set_mem_addr_space (x, targetm.addr_space.for_frame ()); if (TREE_CODE (decl) != SSA_NAME) { Index: gcc/varasm.c =================================================================== --- gcc/varasm.c.orig +++ gcc/varasm.c @@ -3205,9 +3205,14 @@ build_constant_desc (tree exp) labelno = const_labelno++; ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno); + tree type = TREE_TYPE (exp); + addr_space_t as = targetm.addr_space.for_global (true); + if (!ADDR_SPACE_GENERIC_P (as)) + type = build_qualified_type (type, (TYPE_QUALS_NO_ADDR_SPACE (type) + | ENCODE_QUAL_ADDR_SPACE (as))); + /* Construct the VAR_DECL associated with the constant. */ - decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (label), - TREE_TYPE (exp)); + decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (label), type); DECL_ARTIFICIAL (decl) = 1; DECL_IGNORED_P (decl) = 1; TREE_READONLY (decl) = 1; @@ -3244,6 +3249,7 @@ build_constant_desc (tree exp) rtl = gen_const_mem (TYPE_MODE (TREE_TYPE (exp)), symbol); set_mem_attributes (rtl, exp, 1); + set_mem_addr_space (rtl, as); set_mem_alias_set (rtl, 0); set_mem_alias_set (rtl, const_alias_set); Index: gcc/tree-switch-conversion.c =================================================================== --- gcc/tree-switch-conversion.c.orig +++ gcc/tree-switch-conversion.c @@ -46,6 +46,7 @@ Software Foundation, 51 Franklin Street, #include "tree-pass.h" #include "gimple-pretty-print.h" #include "cfgloop.h" +#include "target.h" /* ??? For lang_hooks.types.type_for_mode, but is there a word_mode type in the GIMPLE type system that is language-independent? */ @@ -1043,6 +1044,14 @@ build_one_array (gimple swtch, int num, default_type = TREE_TYPE (info->default_values[num]); value_type = array_value_type (swtch, default_type, num, info); + addr_space_t as = targetm.addr_space.for_global (true); + if (!ADDR_SPACE_GENERIC_P (as)) + { + value_type + = build_qualified_type (value_type, + TYPE_QUALS_NO_ADDR_SPACE (value_type) + | ENCODE_QUAL_ADDR_SPACE (as)); + } array_type = build_array_type (value_type, arr_index_type); if (default_type != value_type) { Index: gcc/tree-core.h =================================================================== --- gcc/tree-core.h.orig +++ gcc/tree-core.h @@ -369,7 +369,8 @@ enum cv_qualifier { TYPE_QUAL_CONST = 0x1, TYPE_QUAL_VOLATILE = 0x2, TYPE_QUAL_RESTRICT = 0x4, - TYPE_QUAL_ATOMIC = 0x8 + TYPE_QUAL_ATOMIC = 0x8, + TYPE_QUAL_AS_IMPLICIT = 0x10 }; /* Enumerate visibility settings. */ @@ -746,7 +747,8 @@ struct GTY(()) tree_base { unsigned user_align : 1; unsigned nameless_flag : 1; unsigned atomic_flag : 1; - unsigned spare0 : 3; + unsigned as_implicit_flag : 1; + unsigned spare0 : 2; unsigned spare1 : 8;