+extern tree last_assemble_variable_decl;
+extern int size_directive_output;
+
+/* A version of asm_output_aligned_bss() that copes with the special
+ data areas of the v850. */
+void
+v850_output_aligned_bss (file, decl, name, size, align)
+ FILE * file;
+ tree decl;
+ const char * name;
+ int size;
+ int align;
+{
+ ASM_GLOBALIZE_LABEL (file, name);
+
+ switch (v850_get_data_area (decl))
+ {
+ case DATA_AREA_ZDA:
+ zbss_section ();
+ break;
+
+ case DATA_AREA_SDA:
+ sbss_section ();
+ break;
+
+ case DATA_AREA_TDA:
+ tdata_section ();
+
+ default:
+ bss_section ();
+ break;
+ }
+
+ ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
+#ifdef ASM_DECLARE_OBJECT_NAME
+ last_assemble_variable_decl = decl;
+ ASM_DECLARE_OBJECT_NAME (file, name, decl);
+#else
+ /* Standard thing is just output label for the object. */
+ ASM_OUTPUT_LABEL (file, name);
+#endif /* ASM_DECLARE_OBJECT_NAME */
+ ASM_OUTPUT_SKIP (file, size ? size : 1);
+}
+
+/* Called via the macro ASM_OUTPUT_DECL_COMMON */
+void
+v850_output_common (file, decl, name, size, align)
+ FILE * file;
+ tree decl;
+ const char * name;
+ int size;
+ int align;
+{
+ if (decl == NULL_TREE)
+ {
+ fprintf (file, "%s", COMMON_ASM_OP);
+ }
+ else
+ {
+ switch (v850_get_data_area (decl))
+ {
+ case DATA_AREA_ZDA:
+ fprintf (file, "%s", ZCOMMON_ASM_OP);
+ break;
+
+ case DATA_AREA_SDA:
+ fprintf (file, "%s", SCOMMON_ASM_OP);
+ break;
+
+ case DATA_AREA_TDA:
+ fprintf (file, "%s", TCOMMON_ASM_OP);
+ break;
+
+ default:
+ fprintf (file, "%s", COMMON_ASM_OP);
+ break;
+ }
+ }
+
+ assemble_name (file, name);
+ fprintf (file, ",%u,%u\n", size, align / BITS_PER_UNIT);
+}
+
+/* Called via the macro ASM_OUTPUT_DECL_LOCAL */
+void
+v850_output_local (file, decl, name, size, align)
+ FILE * file;
+ tree decl;
+ const char * name;
+ int size;
+ int align;
+{
+ fprintf (file, "%s", LOCAL_ASM_OP);
+ assemble_name (file, name);
+ fprintf (file, "\n");
+
+ ASM_OUTPUT_ALIGNED_DECL_COMMON (file, decl, name, size, align);
+}
+
+/* Add data area to the given declaration if a ghs data area pragma is
+ currently in effect (#pragma ghs startXXX/endXXX). */
+static void
+v850_insert_attributes (decl, attr_ptr)
+ tree decl;
+ tree *attr_ptr ATTRIBUTE_UNUSED;
+{
+ if (data_area_stack
+ && data_area_stack->data_area
+ && current_function_decl == NULL_TREE
+ && (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == CONST_DECL)
+ && v850_get_data_area (decl) == DATA_AREA_NORMAL)
+ v850_set_data_area (decl, data_area_stack->data_area);
+
+ /* Initialise the default names of the v850 specific sections,
+ if this has not been done before. */
+
+ if (GHS_default_section_names [(int) GHS_SECTION_KIND_SDATA] == NULL)
+ {
+ GHS_default_section_names [(int) GHS_SECTION_KIND_SDATA]
+ = build_string (sizeof (".sdata")-1, ".sdata");
+
+ GHS_default_section_names [(int) GHS_SECTION_KIND_ROSDATA]
+ = build_string (sizeof (".rosdata")-1, ".rosdata");
+
+ GHS_default_section_names [(int) GHS_SECTION_KIND_TDATA]
+ = build_string (sizeof (".tdata")-1, ".tdata");
+
+ GHS_default_section_names [(int) GHS_SECTION_KIND_ZDATA]
+ = build_string (sizeof (".zdata")-1, ".zdata");
+
+ GHS_default_section_names [(int) GHS_SECTION_KIND_ROZDATA]
+ = build_string (sizeof (".rozdata")-1, ".rozdata");
+ }
+
+ if (current_function_decl == NULL_TREE
+ && (TREE_CODE (decl) == VAR_DECL
+ || TREE_CODE (decl) == CONST_DECL
+ || TREE_CODE (decl) == FUNCTION_DECL)
+ && (!DECL_EXTERNAL (decl) || DECL_INITIAL (decl))
+ && !DECL_SECTION_NAME (decl))
+ {
+ enum GHS_section_kind kind = GHS_SECTION_KIND_DEFAULT;
+ tree chosen_section;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ kind = GHS_SECTION_KIND_TEXT;
+ else
+ {
+ /* First choose a section kind based on the data area of the decl. */
+ switch (v850_get_data_area (decl))
+ {
+ default:
+ abort ();
+
+ case DATA_AREA_SDA:
+ kind = ((TREE_READONLY (decl))
+ ? GHS_SECTION_KIND_ROSDATA
+ : GHS_SECTION_KIND_SDATA);
+ break;
+
+ case DATA_AREA_TDA:
+ kind = GHS_SECTION_KIND_TDATA;
+ break;
+
+ case DATA_AREA_ZDA:
+ kind = ((TREE_READONLY (decl))
+ ? GHS_SECTION_KIND_ROZDATA
+ : GHS_SECTION_KIND_ZDATA);
+ break;
+
+ case DATA_AREA_NORMAL: /* default data area */
+ if (TREE_READONLY (decl))
+ kind = GHS_SECTION_KIND_RODATA;
+ else if (DECL_INITIAL (decl))
+ kind = GHS_SECTION_KIND_DATA;
+ else
+ kind = GHS_SECTION_KIND_BSS;
+ }
+ }
+
+ /* Now, if the section kind has been explicitly renamed,
+ then attach a section attribute. */
+ chosen_section = GHS_current_section_names [(int) kind];
+
+ /* Otherwise, if this kind of section needs an explicit section
+ attribute, then also attach one. */
+ if (chosen_section == NULL)
+ chosen_section = GHS_default_section_names [(int) kind];
+
+ if (chosen_section)
+ {
+ /* Only set the section name if specified by a pragma, because
+ otherwise it will force those variables to get allocated storage
+ in this module, rather than by the linker. */
+ DECL_SECTION_NAME (decl) = chosen_section;
+ }
+ }
+}
+\f
+/* Implement `va_arg'. */
+
+rtx
+v850_va_arg (valist, type)
+ tree valist, type;
+{
+ HOST_WIDE_INT size, rsize;
+ tree addr, incr;
+ rtx addr_rtx;
+ int indirect;
+
+ /* Round up sizeof(type) to a word. */
+ size = int_size_in_bytes (type);
+ rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
+ indirect = 0;
+
+ if (size > 8)
+ {
+ size = rsize = UNITS_PER_WORD;
+ indirect = 1;
+ }
+
+ addr = save_expr (valist);
+ incr = fold (build (PLUS_EXPR, ptr_type_node, addr,
+ build_int_2 (rsize, 0)));
+
+ incr = build (MODIFY_EXPR, ptr_type_node, valist, incr);
+ TREE_SIDE_EFFECTS (incr) = 1;
+ expand_expr (incr, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ addr_rtx = expand_expr (addr, NULL, Pmode, EXPAND_NORMAL);
+
+ if (indirect)
+ {
+ addr_rtx = force_reg (Pmode, addr_rtx);
+ addr_rtx = gen_rtx_MEM (Pmode, addr_rtx);
+ set_mem_alias_set (addr_rtx, get_varargs_alias_set ());
+ }
+
+ return addr_rtx;
+}
+\f
+/* Return an RTX indicating where the return address to the
+ calling function can be found. */
+
+rtx
+v850_return_addr (count)
+ int count;
+{
+ if (count != 0)
+ return const0_rtx;
+
+ return get_hard_reg_initial_val (Pmode, LINK_POINTER_REGNUM);
+}
+\f
+static void
+v850_select_section (exp, reloc, align)
+ tree exp;
+ int reloc;
+ unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
+{
+ if (TREE_CODE (exp) == VAR_DECL)
+ {
+ int is_const;
+ if (!TREE_READONLY (exp)
+ || TREE_SIDE_EFFECTS (exp)
+ || !DECL_INITIAL (exp)
+ || (DECL_INITIAL (exp) != error_mark_node
+ && !TREE_CONSTANT (DECL_INITIAL (exp))))
+ is_const = FALSE;
+ else
+ is_const = TRUE;
+
+ switch (v850_get_data_area (exp))
+ {
+ case DATA_AREA_ZDA:
+ if (is_const)
+ rozdata_section ();
+ else
+ zdata_section ();
+ break;
+
+ case DATA_AREA_TDA:
+ tdata_section ();
+ break;
+
+ case DATA_AREA_SDA:
+ if (is_const)
+ rosdata_section ();
+ else
+ sdata_section ();
+ break;
+
+ default:
+ if (is_const)
+ readonly_data_section ();
+ else
+ data_section ();
+ break;
+ }
+ }
+ else if (TREE_CODE (exp) == STRING_CST)
+ {
+ if (! flag_writable_strings)
+ readonly_data_section ();
+ else
+ data_section ();
+ }
+ else
+ readonly_data_section ();
+}