/* Output routines for GCC for ARM.
Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl)
and Martin Simmons (@harleqn.co.uk).
More major hacks by Richard Earnshaw (rearnsha@arm.com).
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
+ by the Free Software Foundation; either version 3, or (at your
option) any later version.
GCC is distributed in the hope that it will be useful, but WITHOUT
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. */
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
const struct attribute_spec arm_attribute_table[];
+void (*arm_lang_output_object_attributes_hook)(void);
+
/* Forward function declarations. */
static arm_stack_offsets *arm_get_frame_offsets (void);
static void arm_add_gc_roots (void);
static unsigned long thumb1_compute_save_reg_mask (void);
static int const_ok_for_op (HOST_WIDE_INT, enum rtx_code);
static rtx emit_sfm (int, int);
-static int arm_size_return_regs (void);
-#ifndef AOF_ASSEMBLER
+static unsigned arm_size_return_regs (void);
static bool arm_assemble_integer (rtx, unsigned int, int);
-#endif
static const char *fp_const_from_val (REAL_VALUE_TYPE *);
static arm_cc get_arm_condition_code (rtx);
static HOST_WIDE_INT int_log2 (HOST_WIDE_INT);
static void arm_output_function_epilogue (FILE *, HOST_WIDE_INT);
static void arm_output_function_prologue (FILE *, HOST_WIDE_INT);
static void thumb1_output_function_prologue (FILE *, HOST_WIDE_INT);
-static int arm_comp_type_attributes (tree, tree);
+static int arm_comp_type_attributes (const_tree, const_tree);
static void arm_set_default_type_attributes (tree);
static int arm_adjust_cost (rtx, rtx, rtx, int);
static int count_insns_for_constant (HOST_WIDE_INT, int);
static void arm_file_end (void);
static void arm_file_start (void);
-#ifdef AOF_ASSEMBLER
-static void aof_globalize_label (FILE *, const char *);
-static void aof_dump_imports (FILE *);
-static void aof_dump_pic_table (FILE *);
-static void aof_file_start (void);
-static void aof_file_end (void);
-static void aof_asm_init_sections (void);
-#endif
static void arm_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
tree, int *, int);
static bool arm_pass_by_reference (CUMULATIVE_ARGS *,
- enum machine_mode, tree, bool);
-static bool arm_promote_prototypes (tree);
+ enum machine_mode, const_tree, bool);
+static bool arm_promote_prototypes (const_tree);
static bool arm_default_short_enums (void);
static bool arm_align_anon_bitfield (void);
-static bool arm_return_in_msb (tree);
-static bool arm_must_pass_in_stack (enum machine_mode, tree);
+static bool arm_return_in_msb (const_tree);
+static bool arm_must_pass_in_stack (enum machine_mode, const_tree);
#ifdef TARGET_UNWIND_INFO
static void arm_unwind_emit (FILE *, rtx);
static bool arm_output_ttype (rtx);
#undef TARGET_ASM_FILE_END
#define TARGET_ASM_FILE_END arm_file_end
-#ifdef AOF_ASSEMBLER
-#undef TARGET_ASM_BYTE_OP
-#define TARGET_ASM_BYTE_OP "\tDCB\t"
-#undef TARGET_ASM_ALIGNED_HI_OP
-#define TARGET_ASM_ALIGNED_HI_OP "\tDCW\t"
-#undef TARGET_ASM_ALIGNED_SI_OP
-#define TARGET_ASM_ALIGNED_SI_OP "\tDCD\t"
-#undef TARGET_ASM_GLOBALIZE_LABEL
-#define TARGET_ASM_GLOBALIZE_LABEL aof_globalize_label
-#undef TARGET_ASM_FILE_START
-#define TARGET_ASM_FILE_START aof_file_start
-#undef TARGET_ASM_FILE_END
-#define TARGET_ASM_FILE_END aof_file_end
-#else
#undef TARGET_ASM_ALIGNED_SI_OP
#define TARGET_ASM_ALIGNED_SI_OP NULL
#undef TARGET_ASM_INTEGER
#define TARGET_ASM_INTEGER arm_assemble_integer
-#endif
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE arm_output_function_prologue
#define TARGET_INIT_LIBFUNCS arm_init_libfuncs
#undef TARGET_PROMOTE_FUNCTION_ARGS
-#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
+#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true
#undef TARGET_PROMOTE_FUNCTION_RETURN
-#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
+#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
#undef TARGET_PROMOTE_PROTOTYPES
#define TARGET_PROMOTE_PROTOTYPES arm_promote_prototypes
#undef TARGET_PASS_BY_REFERENCE
/* Define how to find the value returned by a function. */
rtx
-arm_function_value(tree type, tree func ATTRIBUTE_UNUSED)
+arm_function_value(const_tree type, const_tree func ATTRIBUTE_UNUSED)
{
enum machine_mode mode;
int unsignedp ATTRIBUTE_UNUSED;
or in a register (false). This is called by the macro
RETURN_IN_MEMORY. */
int
-arm_return_in_memory (tree type)
+arm_return_in_memory (const_tree type)
{
HOST_WIDE_INT size;
static bool
arm_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
enum machine_mode mode ATTRIBUTE_UNUSED,
- tree type, bool named ATTRIBUTE_UNUSED)
+ const_tree type, bool named ATTRIBUTE_UNUSED)
{
return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
}
are compatible, and 2 if they are nearly compatible (which causes a
warning to be generated). */
static int
-arm_comp_type_attributes (tree type1, tree type2)
+arm_comp_type_attributes (const_tree type1, const_tree type2)
{
int l1, l2, s1, s2;
if (GET_CODE (orig) == SYMBOL_REF
|| GET_CODE (orig) == LABEL_REF)
{
-#ifndef AOF_ASSEMBLER
rtx pic_ref, address;
-#endif
rtx insn;
int subregs = 0;
subregs = 1;
}
-#ifdef AOF_ASSEMBLER
- /* The AOF assembler can generate relocations for these directly, and
- understands that the PIC register has to be added into the offset. */
- insn = emit_insn (gen_pic_load_addr_based (reg, orig));
-#else
if (subregs)
address = gen_reg_rtx (Pmode);
else
}
insn = emit_move_insn (reg, pic_ref);
-#endif
+
/* Put a REG_EQUAL note on this insn, so that it can be optimized
by loop. */
set_unique_reg_note (insn, REG_EQUAL, orig);
void
arm_load_pic_register (unsigned long saved_regs ATTRIBUTE_UNUSED)
{
-#ifndef AOF_ASSEMBLER
rtx l1, labelno, pic_tmp, pic_tmp2, pic_rtx, pic_reg;
rtx global_offset_table;
/* Need to emit this whether or not we obey regdecls,
since setjmp/longjmp can cause life info to screw up. */
emit_insn (gen_rtx_USE (VOIDmode, pic_reg));
-#endif /* AOF_ASSEMBLER */
}
return -1;
/* Sign, mantissa and exponent are now in the correct form to plug into the
- formulae described in the comment above. */
+ formula described in the comment above. */
return (sign << 7) | ((exponent ^ 3) << 4) | (mantissa - 16);
}
{
unsigned HOST_WIDE_INT imm = 0;
- /* Un-invert bytes of recognized vector, if neccessary. */
+ /* Un-invert bytes of recognized vector, if necessary. */
if (invmask != 0)
for (i = 0; i < idx; i++)
bytes[i] ^= invmask;
}
}
-/* Initialise a vector with non-constant elements. FIXME: We can do better
+/* Initialize a vector with non-constant elements. FIXME: We can do better
than the current implementation (building a vector on the stack and then
loading it) in many cases. See rs6000.c. */
emit_move_insn (target, mem);
}
+/* Ensure OPERAND lies between LOW (inclusive) and HIGH (exclusive). Raise
+ ERR if it doesn't. FIXME: NEON bounds checks occur late in compilation, so
+ reported source locations are bogus. */
+
+static void
+bounds_check (rtx operand, HOST_WIDE_INT low, HOST_WIDE_INT high,
+ const char *err)
+{
+ HOST_WIDE_INT lane;
+
+ gcc_assert (GET_CODE (operand) == CONST_INT);
+
+ lane = INTVAL (operand);
+
+ if (lane < low || lane >= high)
+ error (err);
+}
+
+/* Bounds-check lanes. */
+
+void
+neon_lane_bounds (rtx operand, HOST_WIDE_INT low, HOST_WIDE_INT high)
+{
+ bounds_check (operand, low, high, "lane out of range");
+}
+
+/* Bounds-check constants. */
+
+void
+neon_const_bounds (rtx operand, HOST_WIDE_INT low, HOST_WIDE_INT high)
+{
+ bounds_check (operand, low, high, "constant out of range");
+}
+
+HOST_WIDE_INT
+neon_element_bits (enum machine_mode mode)
+{
+ if (mode == DImode)
+ return GET_MODE_BITSIZE (mode);
+ else
+ return GET_MODE_BITSIZE (GET_MODE_INNER (mode));
+}
+
\f
/* Predicates for `match_operand' and `match_operator'. */
register. */
static bool
-arm_return_in_msb (tree valtype)
+arm_return_in_msb (const_tree valtype)
{
return (TARGET_AAPCS_BASED
&& BYTES_BIG_ENDIAN
(padded to the size of a word) should be passed in a register. */
static bool
-arm_must_pass_in_stack (enum machine_mode mode, tree type)
+arm_must_pass_in_stack (enum machine_mode mode, const_tree type)
{
if (TARGET_AAPCS_BASED)
return must_pass_in_stack_var_size (mode, type);
aggregate types are placed in the lowest memory address. */
bool
-arm_pad_arg_upward (enum machine_mode mode, tree type)
+arm_pad_arg_upward (enum machine_mode mode, const_tree type)
{
if (!TARGET_AAPCS_BASED)
return DEFAULT_FUNCTION_ARG_PADDING(mode, type) == upward;
{
Mfix * fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* fix));
-#ifdef AOF_ASSEMBLER
- /* PIC symbol references need to be converted into offsets into the
- based area. */
- /* XXX This shouldn't be done here. */
- if (flag_pic && GET_CODE (value) == SYMBOL_REF)
- value = aof_pic_entry (value);
-#endif /* AOF_ASSEMBLER */
-
fix->insn = insn;
fix->address = address;
fix->loc = loc;
if (current_function_calls_eh_return)
asm_fprintf (f, "\t@ Calls __builtin_eh_return.\n");
-#ifdef AOF_ASSEMBLER
- if (flag_pic)
- asm_fprintf (f, "\tmov\t%r, %r\n", IP_REGNUM, PIC_OFFSET_TABLE_REGNUM);
-#endif
-
return_used_this_function = 0;
}
}
/* Calculate the size of the return value that is passed in registers. */
-static int
+static unsigned
arm_size_return_regs (void)
{
enum machine_mode mode;
else
{
emit_insn (gen_movsi (hard_frame_pointer_rtx, GEN_INT (amount)));
- insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
- hard_frame_pointer_rtx,
- stack_pointer_rtx));
+ /* Thumb-2 RTL patterns expect sp as the first input. Thumb-1
+ expects the first two operands to be the same. */
+ if (TARGET_THUMB2)
+ {
+ insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
+ stack_pointer_rtx,
+ hard_frame_pointer_rtx));
+ }
+ else
+ {
+ insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
+ hard_frame_pointer_rtx,
+ stack_pointer_rtx));
+ }
dwarf = gen_rtx_SET (VOIDmode, hard_frame_pointer_rtx,
plus_constant (stack_pointer_rtx, amount));
RTX_FRAME_RELATED_P (dwarf) = 1;
break;
/* %# is a "break" sequence. It doesn't output anything, but is used to
- seperate e.g. operand numbers from following text, if that text consists
+ separate e.g. operand numbers from following text, if that text consists
of further digits which we don't want to be part of the operand
number. */
case '#':
}
}
\f
-#ifndef AOF_ASSEMBLER
/* Target hook for assembling integer objects. The ARM version needs to
handle word-sized values specially. */
static bool
{
arm_elf_asm_cdtor (symbol, priority, /*is_ctor=*/false);
}
-#endif
\f
/* A finite state machine takes care of noticing whether or not instructions
can be conditionally executed, and thus decrease execution time and code
static void
arm_init_tls_builtins (void)
{
- tree ftype;
- tree nothrow = tree_cons (get_identifier ("nothrow"), NULL, NULL);
- tree const_nothrow = tree_cons (get_identifier ("const"), NULL, nothrow);
+ tree ftype, decl;
ftype = build_function_type (ptr_type_node, void_list_node);
- add_builtin_function ("__builtin_thread_pointer", ftype,
- ARM_BUILTIN_THREAD_POINTER, BUILT_IN_MD,
- NULL, const_nothrow);
+ decl = add_builtin_function ("__builtin_thread_pointer", ftype,
+ ARM_BUILTIN_THREAD_POINTER, BUILT_IN_MD,
+ NULL, NULL_TREE);
+ TREE_NOTHROW (decl) = 1;
+ TREE_READONLY (decl) = 1;
}
typedef enum {
tree neon_intSI_type_node = make_signed_type (GET_MODE_PRECISION (SImode));
tree neon_intDI_type_node = make_signed_type (GET_MODE_PRECISION (DImode));
tree neon_float_type_node = make_node (REAL_TYPE);
- TYPE_PRECISION (neon_float_type_node) = FLOAT_TYPE_SIZE;
- layout_type (neon_float_type_node);
-
- /* Define typedefs which exactly correspond to the modes we are basing vector
- types on. If you change these names you'll need to change
- the table used by arm_mangle_type too. */
- (*lang_hooks.types.register_builtin_type) (neon_intQI_type_node,
- "__builtin_neon_qi");
- (*lang_hooks.types.register_builtin_type) (neon_intHI_type_node,
- "__builtin_neon_hi");
- (*lang_hooks.types.register_builtin_type) (neon_intSI_type_node,
- "__builtin_neon_si");
- (*lang_hooks.types.register_builtin_type) (neon_float_type_node,
- "__builtin_neon_sf");
- (*lang_hooks.types.register_builtin_type) (neon_intDI_type_node,
- "__builtin_neon_di");
-
- (*lang_hooks.types.register_builtin_type) (neon_polyQI_type_node,
- "__builtin_neon_poly8");
- (*lang_hooks.types.register_builtin_type) (neon_polyHI_type_node,
- "__builtin_neon_poly16");
tree intQI_pointer_node = build_pointer_type (neon_intQI_type_node);
tree intHI_pointer_node = build_pointer_type (neon_intHI_type_node);
tree intUSI_type_node = make_unsigned_type (GET_MODE_PRECISION (SImode));
tree intUDI_type_node = make_unsigned_type (GET_MODE_PRECISION (DImode));
- (*lang_hooks.types.register_builtin_type) (intUQI_type_node,
- "__builtin_neon_uqi");
- (*lang_hooks.types.register_builtin_type) (intUHI_type_node,
- "__builtin_neon_uhi");
- (*lang_hooks.types.register_builtin_type) (intUSI_type_node,
- "__builtin_neon_usi");
- (*lang_hooks.types.register_builtin_type) (intUDI_type_node,
- "__builtin_neon_udi");
-
/* Opaque integer types for structures of vectors. */
tree intEI_type_node = make_signed_type (GET_MODE_PRECISION (EImode));
tree intOI_type_node = make_signed_type (GET_MODE_PRECISION (OImode));
tree intCI_type_node = make_signed_type (GET_MODE_PRECISION (CImode));
tree intXI_type_node = make_signed_type (GET_MODE_PRECISION (XImode));
- (*lang_hooks.types.register_builtin_type) (intTI_type_node,
- "__builtin_neon_ti");
- (*lang_hooks.types.register_builtin_type) (intEI_type_node,
- "__builtin_neon_ei");
- (*lang_hooks.types.register_builtin_type) (intOI_type_node,
- "__builtin_neon_oi");
- (*lang_hooks.types.register_builtin_type) (intCI_type_node,
- "__builtin_neon_ci");
- (*lang_hooks.types.register_builtin_type) (intXI_type_node,
- "__builtin_neon_xi");
-
/* Pointers to vector types. */
tree V8QI_pointer_node = build_pointer_type (V8QI_type_node);
tree V4HI_pointer_node = build_pointer_type (V4HI_type_node);
tree reinterp_ftype_qreg[5][5];
tree dreg_types[5], qreg_types[5];
+ TYPE_PRECISION (neon_float_type_node) = FLOAT_TYPE_SIZE;
+ layout_type (neon_float_type_node);
+
+ /* Define typedefs which exactly correspond to the modes we are basing vector
+ types on. If you change these names you'll need to change
+ the table used by arm_mangle_type too. */
+ (*lang_hooks.types.register_builtin_type) (neon_intQI_type_node,
+ "__builtin_neon_qi");
+ (*lang_hooks.types.register_builtin_type) (neon_intHI_type_node,
+ "__builtin_neon_hi");
+ (*lang_hooks.types.register_builtin_type) (neon_intSI_type_node,
+ "__builtin_neon_si");
+ (*lang_hooks.types.register_builtin_type) (neon_float_type_node,
+ "__builtin_neon_sf");
+ (*lang_hooks.types.register_builtin_type) (neon_intDI_type_node,
+ "__builtin_neon_di");
+
+ (*lang_hooks.types.register_builtin_type) (neon_polyQI_type_node,
+ "__builtin_neon_poly8");
+ (*lang_hooks.types.register_builtin_type) (neon_polyHI_type_node,
+ "__builtin_neon_poly16");
+ (*lang_hooks.types.register_builtin_type) (intUQI_type_node,
+ "__builtin_neon_uqi");
+ (*lang_hooks.types.register_builtin_type) (intUHI_type_node,
+ "__builtin_neon_uhi");
+ (*lang_hooks.types.register_builtin_type) (intUSI_type_node,
+ "__builtin_neon_usi");
+ (*lang_hooks.types.register_builtin_type) (intUDI_type_node,
+ "__builtin_neon_udi");
+
+ (*lang_hooks.types.register_builtin_type) (intTI_type_node,
+ "__builtin_neon_ti");
+ (*lang_hooks.types.register_builtin_type) (intEI_type_node,
+ "__builtin_neon_ei");
+ (*lang_hooks.types.register_builtin_type) (intOI_type_node,
+ "__builtin_neon_oi");
+ (*lang_hooks.types.register_builtin_type) (intCI_type_node,
+ "__builtin_neon_ci");
+ (*lang_hooks.types.register_builtin_type) (intXI_type_node,
+ "__builtin_neon_xi");
+
dreg_types[0] = V8QI_type_node;
dreg_types[1] = V4HI_type_node;
dreg_types[2] = V2SI_type_node;
are used. However we don't have any easy way of figuring this out.
Conservatively record the setting that would have been used. */
- /* Tag_ABI_PCS_wchar_t. */
- asm_fprintf (asm_out_file, "\t.eabi_attribute 18, %d\n",
- (int)WCHAR_TYPE_SIZE / BITS_PER_UNIT);
-
/* Tag_ABI_FP_rounding. */
if (flag_rounding_math)
asm_fprintf (asm_out_file, "\t.eabi_attribute 19, 1\n");
else
val = 6;
asm_fprintf (asm_out_file, "\t.eabi_attribute 30, %d\n", val);
+
+ if (arm_lang_output_object_attributes_hook)
+ arm_lang_output_object_attributes_hook();
}
default_file_start();
}
}
}
-rtx aof_pic_label;
-
-#ifdef AOF_ASSEMBLER
-/* Special functions only needed when producing AOF syntax assembler. */
-
-struct pic_chain
-{
- struct pic_chain * next;
- const char * symname;
-};
-
-static struct pic_chain * aof_pic_chain = NULL;
-
-rtx
-aof_pic_entry (rtx x)
-{
- struct pic_chain ** chainp;
- int offset;
-
- if (aof_pic_label == NULL_RTX)
- {
- aof_pic_label = gen_rtx_SYMBOL_REF (Pmode, "x$adcons");
- }
-
- for (offset = 0, chainp = &aof_pic_chain; *chainp;
- offset += 4, chainp = &(*chainp)->next)
- if ((*chainp)->symname == XSTR (x, 0))
- return plus_constant (aof_pic_label, offset);
-
- *chainp = (struct pic_chain *) xmalloc (sizeof (struct pic_chain));
- (*chainp)->next = NULL;
- (*chainp)->symname = XSTR (x, 0);
- return plus_constant (aof_pic_label, offset);
-}
-
-void
-aof_dump_pic_table (FILE *f)
-{
- struct pic_chain * chain;
-
- if (aof_pic_chain == NULL)
- return;
-
- asm_fprintf (f, "\tAREA |%r$$adcons|, BASED %r\n",
- PIC_OFFSET_TABLE_REGNUM,
- PIC_OFFSET_TABLE_REGNUM);
- fputs ("|x$adcons|\n", f);
-
- for (chain = aof_pic_chain; chain; chain = chain->next)
- {
- fputs ("\tDCD\t", f);
- assemble_name (f, chain->symname);
- fputs ("\n", f);
- }
-}
-
-int arm_text_section_count = 1;
-
-/* A get_unnamed_section callback for switching to the text section. */
-
-static void
-aof_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED)
-{
- fprintf (asm_out_file, "\tAREA |C$$code%d|, CODE, READONLY",
- arm_text_section_count++);
- if (flag_pic)
- fprintf (asm_out_file, ", PIC, REENTRANT");
- fprintf (asm_out_file, "\n");
-}
-
-static int arm_data_section_count = 1;
-
-/* A get_unnamed_section callback for switching to the data section. */
-
-static void
-aof_output_data_section_asm_op (const void *data ATTRIBUTE_UNUSED)
-{
- fprintf (asm_out_file, "\tAREA |C$$data%d|, DATA\n",
- arm_data_section_count++);
-}
-
-/* Implement TARGET_ASM_INIT_SECTIONS.
-
- AOF Assembler syntax is a nightmare when it comes to areas, since once
- we change from one area to another, we can't go back again. Instead,
- we must create a new area with the same attributes and add the new output
- to that. Unfortunately, there is nothing we can do here to guarantee that
- two areas with the same attributes will be linked adjacently in the
- resulting executable, so we have to be careful not to do pc-relative
- addressing across such boundaries. */
-
-static void
-aof_asm_init_sections (void)
-{
- text_section = get_unnamed_section (SECTION_CODE,
- aof_output_text_section_asm_op, NULL);
- data_section = get_unnamed_section (SECTION_WRITE,
- aof_output_data_section_asm_op, NULL);
- readonly_data_section = text_section;
-}
-
-void
-zero_init_section (void)
-{
- static int zero_init_count = 1;
-
- fprintf (asm_out_file, "\tAREA |C$$zidata%d|,NOINIT\n", zero_init_count++);
- in_section = NULL;
-}
-
-/* The AOF assembler is religiously strict about declarations of
- imported and exported symbols, so that it is impossible to declare
- a function as imported near the beginning of the file, and then to
- export it later on. It is, however, possible to delay the decision
- until all the functions in the file have been compiled. To get
- around this, we maintain a list of the imports and exports, and
- delete from it any that are subsequently defined. At the end of
- compilation we spit the remainder of the list out before the END
- directive. */
-
-struct import
-{
- struct import * next;
- const char * name;
-};
-
-static struct import * imports_list = NULL;
-
-void
-aof_add_import (const char *name)
-{
- struct import * new;
-
- for (new = imports_list; new; new = new->next)
- if (new->name == name)
- return;
-
- new = (struct import *) xmalloc (sizeof (struct import));
- new->next = imports_list;
- imports_list = new;
- new->name = name;
-}
-
-void
-aof_delete_import (const char *name)
-{
- struct import ** old;
-
- for (old = &imports_list; *old; old = & (*old)->next)
- {
- if ((*old)->name == name)
- {
- *old = (*old)->next;
- return;
- }
- }
-}
-
-int arm_main_function = 0;
-
-static void
-aof_dump_imports (FILE *f)
-{
- /* The AOF assembler needs this to cause the startup code to be extracted
- from the library. Brining in __main causes the whole thing to work
- automagically. */
- if (arm_main_function)
- {
- switch_to_section (text_section);
- fputs ("\tIMPORT __main\n", f);
- fputs ("\tDCD __main\n", f);
- }
-
- /* Now dump the remaining imports. */
- while (imports_list)
- {
- fprintf (f, "\tIMPORT\t");
- assemble_name (f, imports_list->name);
- fputc ('\n', f);
- imports_list = imports_list->next;
- }
-}
-
-static void
-aof_globalize_label (FILE *stream, const char *name)
-{
- default_globalize_label (stream, name);
- if (! strcmp (name, "main"))
- arm_main_function = 1;
-}
-
-static void
-aof_file_start (void)
-{
- fputs ("__r0\tRN\t0\n", asm_out_file);
- fputs ("__a1\tRN\t0\n", asm_out_file);
- fputs ("__a2\tRN\t1\n", asm_out_file);
- fputs ("__a3\tRN\t2\n", asm_out_file);
- fputs ("__a4\tRN\t3\n", asm_out_file);
- fputs ("__v1\tRN\t4\n", asm_out_file);
- fputs ("__v2\tRN\t5\n", asm_out_file);
- fputs ("__v3\tRN\t6\n", asm_out_file);
- fputs ("__v4\tRN\t7\n", asm_out_file);
- fputs ("__v5\tRN\t8\n", asm_out_file);
- fputs ("__v6\tRN\t9\n", asm_out_file);
- fputs ("__sl\tRN\t10\n", asm_out_file);
- fputs ("__fp\tRN\t11\n", asm_out_file);
- fputs ("__ip\tRN\t12\n", asm_out_file);
- fputs ("__sp\tRN\t13\n", asm_out_file);
- fputs ("__lr\tRN\t14\n", asm_out_file);
- fputs ("__pc\tRN\t15\n", asm_out_file);
- fputs ("__f0\tFN\t0\n", asm_out_file);
- fputs ("__f1\tFN\t1\n", asm_out_file);
- fputs ("__f2\tFN\t2\n", asm_out_file);
- fputs ("__f3\tFN\t3\n", asm_out_file);
- fputs ("__f4\tFN\t4\n", asm_out_file);
- fputs ("__f5\tFN\t5\n", asm_out_file);
- fputs ("__f6\tFN\t6\n", asm_out_file);
- fputs ("__f7\tFN\t7\n", asm_out_file);
- switch_to_section (text_section);
-}
-
-static void
-aof_file_end (void)
-{
- if (flag_pic)
- aof_dump_pic_table (asm_out_file);
- arm_file_end ();
- aof_dump_imports (asm_out_file);
- fputs ("\tEND\n", asm_out_file);
-}
-#endif /* AOF_ASSEMBLER */
-
#ifndef ARM_PE
/* Symbols in the text segment can be accessed without indirecting via the
constant pool; it may take an extra binary operation, but this is still
static void
arm_encode_section_info (tree decl, rtx rtl, int first)
{
- /* This doesn't work with AOF syntax, since the string table may be in
- a different AREA. */
-#ifndef AOF_ASSEMBLER
if (optimize > 0 && TREE_CONSTANT (decl))
SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
-#endif
default_encode_section_info (decl, rtl, first);
}
static void
arm_setup_incoming_varargs (CUMULATIVE_ARGS *cum,
- enum machine_mode mode ATTRIBUTE_UNUSED,
- tree type ATTRIBUTE_UNUSED,
+ enum machine_mode mode,
+ tree type,
int *pretend_size,
int second_time ATTRIBUTE_UNUSED)
{
+ int nregs = cum->nregs;
+ if (nregs & 1
+ && ARM_DOUBLEWORD_ALIGN
+ && arm_needs_doubleword_align (mode, type))
+ nregs++;
+
cfun->machine->uses_anonymous_args = 1;
- if (cum->nregs < NUM_ARG_REGS)
- *pretend_size = (NUM_ARG_REGS - cum->nregs) * UNITS_PER_WORD;
+ if (nregs < NUM_ARG_REGS)
+ *pretend_size = (NUM_ARG_REGS - nregs) * UNITS_PER_WORD;
}
/* Return nonzero if the CONSUMER instruction (a store) does not need
using APCS or ATPCS. */
static bool
-arm_promote_prototypes (tree t ATTRIBUTE_UNUSED)
+arm_promote_prototypes (const_tree t ATTRIBUTE_UNUSED)
{
return !TARGET_AAPCS_BASED;
}
return TARGET_AAPCS_BASED ? integer_type_node : long_long_integer_type_node;
}
+/* Return non-zero if the consumer (a multiply-accumulate instruction)
+ has an accumulator dependency on the result of the producer (a
+ multiplication instruction) and no other dependency on that result. */
+int
+arm_mac_accumulator_is_mul_result (rtx producer, rtx consumer)
+{
+ rtx mul = PATTERN (producer);
+ rtx mac = PATTERN (consumer);
+ rtx mul_result;
+ rtx mac_op0, mac_op1, mac_acc;
+
+ if (GET_CODE (mul) == COND_EXEC)
+ mul = COND_EXEC_CODE (mul);
+ if (GET_CODE (mac) == COND_EXEC)
+ mac = COND_EXEC_CODE (mac);
+
+ /* Check that mul is of the form (set (...) (mult ...))
+ and mla is of the form (set (...) (plus (mult ...) (...))). */
+ if ((GET_CODE (mul) != SET || GET_CODE (XEXP (mul, 1)) != MULT)
+ || (GET_CODE (mac) != SET || GET_CODE (XEXP (mac, 1)) != PLUS
+ || GET_CODE (XEXP (XEXP (mac, 1), 0)) != MULT))
+ return 0;
+
+ mul_result = XEXP (mul, 0);
+ mac_op0 = XEXP (XEXP (XEXP (mac, 1), 0), 0);
+ mac_op1 = XEXP (XEXP (XEXP (mac, 1), 0), 1);
+ mac_acc = XEXP (XEXP (mac, 1), 1);
+
+ return (reg_overlap_mentioned_p (mul_result, mac_acc)
+ && !reg_overlap_mentioned_p (mul_result, mac_op0)
+ && !reg_overlap_mentioned_p (mul_result, mac_op1));
+}
+
/* The EABI says test the least significant bit of a guard variable. */
};
const char *
-arm_mangle_type (tree type)
+arm_mangle_type (const_tree type)
{
arm_mangle_map_entry *pos = arm_mangle_map;