summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/config/arm
diff options
context:
space:
mode:
authorkan <kan@FreeBSD.org>2007-05-19 01:19:51 +0000
committerkan <kan@FreeBSD.org>2007-05-19 01:19:51 +0000
commit1f9ea4d0a40cca64d60cf4dab152349da7b9dddf (patch)
tree0cb530c9c38af219e6dda2994c078b6b2b9ad853 /contrib/gcc/config/arm
parent4895159b2b4f648051c1f139faa7b6dc50c2bfcb (diff)
downloadFreeBSD-src-1f9ea4d0a40cca64d60cf4dab152349da7b9dddf.zip
FreeBSD-src-1f9ea4d0a40cca64d60cf4dab152349da7b9dddf.tar.gz
GCC 4.2.0 release.
Diffstat (limited to 'contrib/gcc/config/arm')
-rw-r--r--contrib/gcc/config/arm/README-interworking2
-rw-r--r--contrib/gcc/config/arm/aof.h81
-rw-r--r--contrib/gcc/config/arm/aout.h48
-rw-r--r--contrib/gcc/config/arm/arm-cores.def117
-rw-r--r--contrib/gcc/config/arm/arm-generic.md152
-rw-r--r--contrib/gcc/config/arm/arm-modes.def14
-rw-r--r--contrib/gcc/config/arm/arm-protos.h113
-rw-r--r--contrib/gcc/config/arm/arm-tune.md5
-rw-r--r--contrib/gcc/config/arm/arm.c8969
-rw-r--r--contrib/gcc/config/arm/arm.h1509
-rw-r--r--contrib/gcc/config/arm/arm.md3383
-rw-r--r--contrib/gcc/config/arm/arm.opt155
-rw-r--r--contrib/gcc/config/arm/arm1020e.md388
-rw-r--r--contrib/gcc/config/arm/arm1026ejs.md241
-rw-r--r--contrib/gcc/config/arm/arm1136jfs.md377
-rw-r--r--contrib/gcc/config/arm/arm926ejs.md188
-rw-r--r--contrib/gcc/config/arm/bpabi.S95
-rw-r--r--contrib/gcc/config/arm/bpabi.c61
-rw-r--r--contrib/gcc/config/arm/bpabi.h118
-rw-r--r--contrib/gcc/config/arm/cirrus.md122
-rw-r--r--contrib/gcc/config/arm/coff.h13
-rw-r--r--contrib/gcc/config/arm/constraints.md186
-rw-r--r--contrib/gcc/config/arm/crti.asm16
-rw-r--r--contrib/gcc/config/arm/crtn.asm16
-rw-r--r--contrib/gcc/config/arm/ecos-elf.h4
-rw-r--r--contrib/gcc/config/arm/elf.h26
-rw-r--r--contrib/gcc/config/arm/fpa.md214
-rw-r--r--contrib/gcc/config/arm/freebsd.h5
-rwxr-xr-xcontrib/gcc/config/arm/gentune.sh12
-rw-r--r--contrib/gcc/config/arm/ieee754-df.S1133
-rw-r--r--contrib/gcc/config/arm/ieee754-sf.S932
-rw-r--r--contrib/gcc/config/arm/iwmmxt.md46
-rw-r--r--contrib/gcc/config/arm/kaos-arm.h4
-rw-r--r--contrib/gcc/config/arm/kaos-strongarm.h4
-rw-r--r--contrib/gcc/config/arm/lib1funcs.asm474
-rw-r--r--contrib/gcc/config/arm/libgcc-bpabi.ver83
-rw-r--r--contrib/gcc/config/arm/libunwind.S120
-rw-r--r--contrib/gcc/config/arm/linux-eabi.h85
-rw-r--r--contrib/gcc/config/arm/linux-elf.h78
-rw-r--r--contrib/gcc/config/arm/linux-gas.h22
-rw-r--r--contrib/gcc/config/arm/mmintrin.h34
-rw-r--r--contrib/gcc/config/arm/netbsd-elf.h47
-rw-r--r--contrib/gcc/config/arm/netbsd.h31
-rw-r--r--contrib/gcc/config/arm/pe.c54
-rw-r--r--contrib/gcc/config/arm/pe.h108
-rw-r--r--contrib/gcc/config/arm/pe.opt24
-rw-r--r--contrib/gcc/config/arm/pr-support.c381
-rw-r--r--contrib/gcc/config/arm/predicates.md458
-rw-r--r--contrib/gcc/config/arm/rtems-elf.h21
-rw-r--r--contrib/gcc/config/arm/semi.h19
-rw-r--r--contrib/gcc/config/arm/semiaof.h16
-rw-r--r--contrib/gcc/config/arm/strongarm-coff.h4
-rw-r--r--contrib/gcc/config/arm/strongarm-elf.h4
-rw-r--r--contrib/gcc/config/arm/strongarm-pe.h4
-rw-r--r--contrib/gcc/config/arm/symbian.h101
-rw-r--r--contrib/gcc/config/arm/t-arm22
-rw-r--r--contrib/gcc/config/arm/t-arm-coff2
-rw-r--r--contrib/gcc/config/arm/t-arm-elf12
-rw-r--r--contrib/gcc/config/arm/t-bpabi16
-rw-r--r--contrib/gcc/config/arm/t-linux5
-rw-r--r--contrib/gcc/config/arm/t-linux-eabi14
-rw-r--r--contrib/gcc/config/arm/t-netbsd5
-rw-r--r--contrib/gcc/config/arm/t-pe6
-rw-r--r--contrib/gcc/config/arm/t-semi6
-rw-r--r--contrib/gcc/config/arm/t-strongarm-elf2
-rw-r--r--contrib/gcc/config/arm/t-strongarm-pe2
-rw-r--r--contrib/gcc/config/arm/t-symbian32
-rw-r--r--contrib/gcc/config/arm/t-wince-pe8
-rw-r--r--contrib/gcc/config/arm/t-xscale-coff15
-rw-r--r--contrib/gcc/config/arm/t-xscale-elf27
-rw-r--r--contrib/gcc/config/arm/uclinux-elf.h52
-rw-r--r--contrib/gcc/config/arm/unaligned-funcs.c62
-rw-r--r--contrib/gcc/config/arm/unknown-elf.h28
-rw-r--r--contrib/gcc/config/arm/unwind-arm.c1016
-rw-r--r--contrib/gcc/config/arm/unwind-arm.h271
-rw-r--r--contrib/gcc/config/arm/vfp.md841
-rw-r--r--contrib/gcc/config/arm/vxworks.h18
-rw-r--r--contrib/gcc/config/arm/wince-pe.h12
-rw-r--r--contrib/gcc/config/arm/xscale-coff.h4
-rw-r--r--contrib/gcc/config/arm/xscale-elf.h4
80 files changed, 15883 insertions, 7516 deletions
diff --git a/contrib/gcc/config/arm/README-interworking b/contrib/gcc/config/arm/README-interworking
index 0a03cdc..d221e15 100644
--- a/contrib/gcc/config/arm/README-interworking
+++ b/contrib/gcc/config/arm/README-interworking
@@ -78,7 +78,7 @@ then the following rules must be obeyed:
* All externally visible functions which should be entered in
Thumb mode must have the .thumb_func pseudo op specified just
- before their entry point. eg:
+ before their entry point. e.g.:
.code 16
.global function
diff --git a/contrib/gcc/config/arm/aof.h b/contrib/gcc/config/arm/aof.h
index 5a6ab2c..8a1223c 100644
--- a/contrib/gcc/config/arm/aof.h
+++ b/contrib/gcc/config/arm/aof.h
@@ -1,6 +1,7 @@
/* Definitions of target machine for GNU compiler, for Advanced RISC Machines
ARM compilation, AOF Assembler.
- Copyright (C) 1995, 1996, 1997, 2000, 2003 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997, 2000, 2003, 2004
+ Free Software Foundation, Inc.
Contributed by Richard Earnshaw (rearnsha@armltd.co.uk)
This file is part of GCC.
@@ -17,8 +18,8 @@
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, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
@@ -34,8 +35,7 @@
#define ENDFILE_SPEC "crtend.o%s"
#ifndef ASM_SPEC
-#define ASM_SPEC "%{g -g} -arch 4 \
--apcs 3%{mapcs-32:/32bit}%{mapcs-26:/26bit}%{!mapcs-26:%{!macps-32:/26bit}}"
+#define ASM_SPEC "%{g -g} -arch 4 -apcs 3/32bit"
#endif
#ifndef LIB_SPEC
@@ -44,48 +44,6 @@
#define LIBGCC_SPEC "libgcc.a%s"
-/* Dividing the Output into Sections (Text, Data, ...) */
-/* 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. */
-#define TEXT_SECTION_ASM_OP aof_text_section ()
-
-#define DATA_SECTION_ASM_OP aof_data_section ()
-
-#define EXTRA_SECTIONS in_zero_init, in_common
-
-#define EXTRA_SECTION_FUNCTIONS \
- ZERO_INIT_SECTION \
- COMMON_SECTION
-
-#define ZERO_INIT_SECTION \
- void \
- zero_init_section () \
- { \
- static int zero_init_count = 1; \
- \
- if (in_section != in_zero_init) \
- { \
- fprintf (asm_out_file, "\tAREA |C$$zidata%d|,NOINIT\n", \
- zero_init_count++); \
- in_section = in_zero_init; \
- } \
- }
-
-/* Used by ASM_OUTPUT_COMMON (below) to tell varasm.c that we've
- changed areas. */
-#define COMMON_SECTION \
- void \
- common_section () \
- { \
- if (in_section != in_common) \
- in_section = in_common; \
- }
-
#define CTOR_LIST_BEGIN \
asm (CTORS_SECTION_ASM_OP); \
extern func_ptr __CTOR_END__[1]; \
@@ -130,6 +88,8 @@
whole table generation until the end of the function. */
#define JUMP_TABLES_IN_TEXT_SECTION 1
+#define TARGET_ASM_INIT_SECTIONS aof_asm_init_sections
+
/* Some systems use __main in a way incompatible with its use in gcc, in these
cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to
give the same symbol without quotes for an alternative entry point. You
@@ -159,7 +119,7 @@
/* Output of Uninitialized Variables. */
#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \
- (common_section (), \
+ (in_section = NULL, \
fprintf ((STREAM), "\tAREA "), \
assemble_name ((STREAM), (NAME)), \
fprintf ((STREAM), ", DATA, COMMON\n\t%% %d\t%s size=%d\n", \
@@ -246,7 +206,12 @@ do { \
"wr0", "wr1", "wr2", "wr3", \
"wr4", "wr5", "wr6", "wr7", \
"wr8", "wr9", "wr10", "wr11", \
- "wr12", "wr13", "wr14", "wr15" \
+ "wr12", "wr13", "wr14", "wr15", \
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", \
+ "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", \
+ "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", \
+ "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", \
+ "vfpcc" \
}
#define ADDITIONAL_REGISTER_NAMES \
@@ -266,7 +231,23 @@ do { \
{"r12", 12}, {"ip", 12}, \
{"r13", 13}, {"sp", 13}, \
{"r14", 14}, {"lr", 14}, \
- {"r15", 15}, {"pc", 15} \
+ {"r15", 15}, {"pc", 15}, \
+ {"d0", 63}, \
+ {"d1", 65}, \
+ {"d2", 67}, \
+ {"d3", 69}, \
+ {"d4", 71}, \
+ {"d5", 73}, \
+ {"d6", 75}, \
+ {"d7", 77}, \
+ {"d8", 79}, \
+ {"d9", 81}, \
+ {"d10", 83}, \
+ {"d11", 85}, \
+ {"d12", 87}, \
+ {"d13", 89}, \
+ {"d14", 91}, \
+ {"d15", 93} \
}
#define REGISTER_PREFIX "__"
diff --git a/contrib/gcc/config/arm/aout.h b/contrib/gcc/config/arm/aout.h
index 1f060fa..903afa7 100644
--- a/contrib/gcc/config/arm/aout.h
+++ b/contrib/gcc/config/arm/aout.h
@@ -1,5 +1,5 @@
/* Definitions of target machine for GNU compiler, for ARM with a.out
- Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+ Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2004
Free Software Foundation, Inc.
Contributed by Richard Earnshaw (rearnsha@armltd.co.uk).
@@ -17,8 +17,8 @@
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, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#ifndef ASM_APP_ON
#define ASM_APP_ON ""
@@ -49,7 +49,7 @@
/* The assembler's names for the registers. */
#ifndef REGISTER_NAMES
-#define REGISTER_NAMES \
+#define REGISTER_NAMES \
{ \
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
"r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc", \
@@ -63,7 +63,12 @@
"wr0", "wr1", "wr2", "wr3", \
"wr4", "wr5", "wr6", "wr7", \
"wr8", "wr9", "wr10", "wr11", \
- "wr12", "wr13", "wr14", "wr15" \
+ "wr12", "wr13", "wr14", "wr15", \
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", \
+ "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", \
+ "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", \
+ "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", \
+ "vfpcc" \
}
#endif
@@ -152,7 +157,23 @@
{"mvdx12", 39}, \
{"mvdx13", 40}, \
{"mvdx14", 41}, \
- {"mvdx15", 42} \
+ {"mvdx15", 42}, \
+ {"d0", 63}, \
+ {"d1", 65}, \
+ {"d2", 67}, \
+ {"d3", 69}, \
+ {"d4", 71}, \
+ {"d5", 73}, \
+ {"d6", 75}, \
+ {"d7", 77}, \
+ {"d8", 79}, \
+ {"d9", 81}, \
+ {"d10", 83}, \
+ {"d11", 85}, \
+ {"d12", 87}, \
+ {"d13", 89}, \
+ {"d14", 91}, \
+ {"d15", 93}, \
}
#endif
@@ -172,19 +193,6 @@
#define DBX_CONTIN_LENGTH 0
#endif
-/* Output a source filename for the debugger. RISCiX dbx insists that the
- ``desc'' field is set to compiler version number >= 315 (sic). */
-#define DBX_OUTPUT_MAIN_SOURCE_FILENAME(STREAM, NAME) \
- do \
- { \
- fprintf (STREAM, ".stabs "); \
- output_quoted_string (STREAM, NAME); \
- fprintf (STREAM, ",%d,0,315,%s\n", N_SO, &ltext_label_name[1]); \
- text_section (); \
- (*targetm.asm_out.internal_label) (STREAM, "Ltext", 0); \
- } \
- while (0)
-
/* Output a function label definition. */
#ifndef ASM_DECLARE_FUNCTION_NAME
#define ASM_DECLARE_FUNCTION_NAME(STREAM, NAME, DECL) \
@@ -265,7 +273,7 @@
#define ASM_OUTPUT_ALIGNED_LOCAL(STREAM, NAME, SIZE, ALIGN) \
do \
{ \
- bss_section (); \
+ switch_to_section (bss_section); \
ASM_OUTPUT_ALIGN (STREAM, floor_log2 (ALIGN / BITS_PER_UNIT)); \
ASM_OUTPUT_LABEL (STREAM, NAME); \
fprintf (STREAM, "\t.space\t%d\n", (int)(SIZE)); \
diff --git a/contrib/gcc/config/arm/arm-cores.def b/contrib/gcc/config/arm/arm-cores.def
new file mode 100644
index 0000000..3f9b7ba
--- /dev/null
+++ b/contrib/gcc/config/arm/arm-cores.def
@@ -0,0 +1,117 @@
+/* ARM CPU Cores
+ Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+ Written by CodeSourcery, LLC
+
+ 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.
+
+ 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. */
+
+/* Before using #include to read this file, define a macro:
+
+ ARM_CORE(CORE_NAME, CORE_IDENT, ARCH, FLAGS, COSTS)
+
+ The CORE_NAME is the name of the core, represented as a string constant.
+ The CORE_IDENT is the name of the core, represented as an identifier.
+ ARCH is the architecture revision implemented by the chip.
+ FLAGS are the bitwise-or of the traits that apply to that core.
+ This need not include flags implied by the architecture.
+ COSTS is the name of the rtx_costs routine to use.
+
+ If you update this table, you must update the "tune" attribute in
+ arm.md.
+
+ Some tools assume no whitespace up to the first "," in each entry. */
+
+/* V2/V2A Architecture Processors */
+ARM_CORE("arm2", arm2, 2, FL_CO_PROC | FL_MODE26, slowmul)
+ARM_CORE("arm250", arm250, 2, FL_CO_PROC | FL_MODE26, slowmul)
+ARM_CORE("arm3", arm3, 2, FL_CO_PROC | FL_MODE26, slowmul)
+
+/* V3 Architecture Processors */
+ARM_CORE("arm6", arm6, 3, FL_CO_PROC | FL_MODE26, slowmul)
+ARM_CORE("arm60", arm60, 3, FL_CO_PROC | FL_MODE26, slowmul)
+ARM_CORE("arm600", arm600, 3, FL_CO_PROC | FL_MODE26 | FL_WBUF, slowmul)
+ARM_CORE("arm610", arm610, 3, FL_MODE26 | FL_WBUF, slowmul)
+ARM_CORE("arm620", arm620, 3, FL_CO_PROC | FL_MODE26 | FL_WBUF, slowmul)
+ARM_CORE("arm7", arm7, 3, FL_CO_PROC | FL_MODE26, slowmul)
+ARM_CORE("arm7d", arm7d, 3, FL_CO_PROC | FL_MODE26, slowmul)
+ARM_CORE("arm7di", arm7di, 3, FL_CO_PROC | FL_MODE26, slowmul)
+ARM_CORE("arm70", arm70, 3, FL_CO_PROC | FL_MODE26, slowmul)
+ARM_CORE("arm700", arm700, 3, FL_CO_PROC | FL_MODE26 | FL_WBUF, slowmul)
+ARM_CORE("arm700i", arm700i, 3, FL_CO_PROC | FL_MODE26 | FL_WBUF, slowmul)
+ARM_CORE("arm710", arm710, 3, FL_MODE26 | FL_WBUF, slowmul)
+ARM_CORE("arm720", arm720, 3, FL_MODE26 | FL_WBUF, slowmul)
+ARM_CORE("arm710c", arm710c, 3, FL_MODE26 | FL_WBUF, slowmul)
+ARM_CORE("arm7100", arm7100, 3, FL_MODE26 | FL_WBUF, slowmul)
+ARM_CORE("arm7500", arm7500, 3, FL_MODE26 | FL_WBUF, slowmul)
+/* Doesn't have an external co-proc, but does have embedded fpa. */
+ARM_CORE("arm7500fe", arm7500fe, 3, FL_CO_PROC | FL_MODE26 | FL_WBUF, slowmul)
+
+/* V3M Architecture Processors */
+/* arm7m doesn't exist on its own, but only with D, ("and", and I), but
+ those don't alter the code, so arm7m is sometimes used. */
+ARM_CORE("arm7m", arm7m, 3M, FL_CO_PROC | FL_MODE26, fastmul)
+ARM_CORE("arm7dm", arm7dm, 3M, FL_CO_PROC | FL_MODE26, fastmul)
+ARM_CORE("arm7dmi", arm7dmi, 3M, FL_CO_PROC | FL_MODE26, fastmul)
+
+/* V4 Architecture Processors */
+ARM_CORE("arm8", arm8, 4, FL_MODE26 | FL_LDSCHED, fastmul)
+ARM_CORE("arm810", arm810, 4, FL_MODE26 | FL_LDSCHED, fastmul)
+ARM_CORE("strongarm", strongarm, 4, FL_MODE26 | FL_LDSCHED | FL_STRONG, fastmul)
+ARM_CORE("strongarm110", strongarm110, 4, FL_MODE26 | FL_LDSCHED | FL_STRONG, fastmul)
+ARM_CORE("strongarm1100", strongarm1100, 4, FL_MODE26 | FL_LDSCHED | FL_STRONG, fastmul)
+ARM_CORE("strongarm1110", strongarm1110, 4, FL_MODE26 | FL_LDSCHED | FL_STRONG, fastmul)
+
+/* V4T Architecture Processors */
+ARM_CORE("arm7tdmi", arm7tdmi, 4T, FL_CO_PROC , fastmul)
+ARM_CORE("arm7tdmi-s", arm7tdmis, 4T, FL_CO_PROC , fastmul)
+ARM_CORE("arm710t", arm710t, 4T, FL_WBUF, fastmul)
+ARM_CORE("arm720t", arm720t, 4T, FL_WBUF, fastmul)
+ARM_CORE("arm740t", arm740t, 4T, FL_WBUF, fastmul)
+ARM_CORE("arm9", arm9, 4T, FL_LDSCHED, fastmul)
+ARM_CORE("arm9tdmi", arm9tdmi, 4T, FL_LDSCHED, fastmul)
+ARM_CORE("arm920", arm920, 4T, FL_LDSCHED, fastmul)
+ARM_CORE("arm920t", arm920t, 4T, FL_LDSCHED, fastmul)
+ARM_CORE("arm922t", arm922t, 4T, FL_LDSCHED, fastmul)
+ARM_CORE("arm940t", arm940t, 4T, FL_LDSCHED, fastmul)
+ARM_CORE("ep9312", ep9312, 4T, FL_LDSCHED | FL_CIRRUS, fastmul)
+
+/* V5T Architecture Processors */
+ARM_CORE("arm10tdmi", arm10tdmi, 5T, FL_LDSCHED, fastmul)
+ARM_CORE("arm1020t", arm1020t, 5T, FL_LDSCHED, fastmul)
+
+/* V5TE Architecture Processors */
+ARM_CORE("arm9e", arm9e, 5TE, FL_LDSCHED, 9e)
+ARM_CORE("arm946e-s", arm946es, 5TE, FL_LDSCHED, 9e)
+ARM_CORE("arm966e-s", arm966es, 5TE, FL_LDSCHED, 9e)
+ARM_CORE("arm968e-s", arm968es, 5TE, FL_LDSCHED, 9e)
+ARM_CORE("arm10e", arm10e, 5TE, FL_LDSCHED, fastmul)
+ARM_CORE("arm1020e", arm1020e, 5TE, FL_LDSCHED, fastmul)
+ARM_CORE("arm1022e", arm1022e, 5TE, FL_LDSCHED, fastmul)
+ARM_CORE("xscale", xscale, 5TE, FL_LDSCHED | FL_STRONG | FL_XSCALE, xscale)
+ARM_CORE("iwmmxt", iwmmxt, 5TE, FL_LDSCHED | FL_STRONG | FL_XSCALE | FL_IWMMXT, xscale)
+
+/* V5TEJ Architecture Processors */
+ARM_CORE("arm926ej-s", arm926ejs, 5TEJ, FL_LDSCHED, 9e)
+ARM_CORE("arm1026ej-s", arm1026ejs, 5TEJ, FL_LDSCHED, 9e)
+
+/* V6 Architecture Processors */
+ARM_CORE("arm1136j-s", arm1136js, 6J, FL_LDSCHED, 9e)
+ARM_CORE("arm1136jf-s", arm1136jfs, 6J, FL_LDSCHED | FL_VFPV2, 9e)
+ARM_CORE("arm1176jz-s", arm1176jzs, 6ZK, FL_LDSCHED, 9e)
+ARM_CORE("arm1176jzf-s", arm1176jzfs, 6ZK, FL_LDSCHED | FL_VFPV2, 9e)
+ARM_CORE("mpcorenovfp", mpcorenovfp, 6K, FL_LDSCHED, 9e)
+ARM_CORE("mpcore", mpcore, 6K, FL_LDSCHED | FL_VFPV2, 9e)
diff --git a/contrib/gcc/config/arm/arm-generic.md b/contrib/gcc/config/arm/arm-generic.md
new file mode 100644
index 0000000..6116486
--- /dev/null
+++ b/contrib/gcc/config/arm/arm-generic.md
@@ -0,0 +1,152 @@
+;; Generic ARM Pipeline Description
+;; Copyright (C) 2003 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.
+;;
+;; 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. */
+
+(define_automaton "arm")
+
+;; Write buffer
+;
+; Strictly, we should model a 4-deep write buffer for ARM7xx based chips
+;
+; The write buffer on some of the arm6 processors is hard to model exactly.
+; There is room in the buffer for up to two addresses and up to eight words
+; of memory, but the two needn't be split evenly. When writing the two
+; addresses are fully pipelined. However, a read from memory that is not
+; currently in the cache will block until the writes have completed.
+; It is normally the case that FCLK and MCLK will be in the ratio 2:1, so
+; writes will take 2 FCLK cycles per word, if FCLK and MCLK are asynchronous
+; (they aren't allowed to be at present) then there is a startup cost of 1MCLK
+; cycle to add as well.
+(define_cpu_unit "write_buf" "arm")
+
+;; Write blockage unit
+;
+; The write_blockage unit models (partially), the fact that reads will stall
+; until the write buffer empties.
+; The f_mem_r and r_mem_f could also block, but they are to the stack,
+; so we don't model them here
+(define_cpu_unit "write_blockage" "arm")
+
+;; Core
+;
+(define_cpu_unit "core" "arm")
+
+(define_insn_reservation "r_mem_f_wbuf" 5
+ (and (eq_attr "generic_sched" "yes")
+ (and (eq_attr "model_wbuf" "yes")
+ (eq_attr "type" "r_mem_f")))
+ "core+write_buf*3")
+
+(define_insn_reservation "store_wbuf" 5
+ (and (eq_attr "generic_sched" "yes")
+ (and (eq_attr "model_wbuf" "yes")
+ (eq_attr "type" "store1")))
+ "core+write_buf*3+write_blockage*5")
+
+(define_insn_reservation "store2_wbuf" 7
+ (and (eq_attr "generic_sched" "yes")
+ (and (eq_attr "model_wbuf" "yes")
+ (eq_attr "type" "store2")))
+ "core+write_buf*4+write_blockage*7")
+
+(define_insn_reservation "store3_wbuf" 9
+ (and (eq_attr "generic_sched" "yes")
+ (and (eq_attr "model_wbuf" "yes")
+ (eq_attr "type" "store3")))
+ "core+write_buf*5+write_blockage*9")
+
+(define_insn_reservation "store4_wbuf" 11
+ (and (eq_attr "generic_sched" "yes")
+ (and (eq_attr "model_wbuf" "yes")
+ (eq_attr "type" "store4")))
+ "core+write_buf*6+write_blockage*11")
+
+(define_insn_reservation "store2" 3
+ (and (eq_attr "generic_sched" "yes")
+ (and (eq_attr "model_wbuf" "no")
+ (eq_attr "type" "store2")))
+ "core*3")
+
+(define_insn_reservation "store3" 4
+ (and (eq_attr "generic_sched" "yes")
+ (and (eq_attr "model_wbuf" "no")
+ (eq_attr "type" "store3")))
+ "core*4")
+
+(define_insn_reservation "store4" 5
+ (and (eq_attr "generic_sched" "yes")
+ (and (eq_attr "model_wbuf" "no")
+ (eq_attr "type" "store4")))
+ "core*5")
+
+(define_insn_reservation "store_ldsched" 1
+ (and (eq_attr "generic_sched" "yes")
+ (and (eq_attr "ldsched" "yes")
+ (eq_attr "type" "store1")))
+ "core")
+
+(define_insn_reservation "load_ldsched_xscale" 3
+ (and (eq_attr "generic_sched" "yes")
+ (and (eq_attr "ldsched" "yes")
+ (and (eq_attr "type" "load_byte,load1")
+ (eq_attr "is_xscale" "yes"))))
+ "core")
+
+(define_insn_reservation "load_ldsched" 2
+ (and (eq_attr "generic_sched" "yes")
+ (and (eq_attr "ldsched" "yes")
+ (and (eq_attr "type" "load_byte,load1")
+ (eq_attr "is_xscale" "no"))))
+ "core")
+
+(define_insn_reservation "load_or_store" 2
+ (and (eq_attr "generic_sched" "yes")
+ (and (eq_attr "ldsched" "!yes")
+ (eq_attr "type" "load_byte,load1,load2,load3,load4,store1")))
+ "core*2")
+
+(define_insn_reservation "mult" 16
+ (and (eq_attr "generic_sched" "yes")
+ (and (eq_attr "ldsched" "no") (eq_attr "type" "mult")))
+ "core*16")
+
+(define_insn_reservation "mult_ldsched_strongarm" 3
+ (and (eq_attr "generic_sched" "yes")
+ (and (eq_attr "ldsched" "yes")
+ (and (eq_attr "is_strongarm" "yes")
+ (eq_attr "type" "mult"))))
+ "core*2")
+
+(define_insn_reservation "mult_ldsched" 4
+ (and (eq_attr "generic_sched" "yes")
+ (and (eq_attr "ldsched" "yes")
+ (and (eq_attr "is_strongarm" "no")
+ (eq_attr "type" "mult"))))
+ "core*4")
+
+(define_insn_reservation "multi_cycle" 32
+ (and (eq_attr "generic_sched" "yes")
+ (and (eq_attr "core_cycles" "multi")
+ (eq_attr "type" "!mult,load_byte,load1,load2,load3,load4,store1,store2,store3,store4")))
+ "core*32")
+
+(define_insn_reservation "single_cycle" 1
+ (and (eq_attr "generic_sched" "yes")
+ (eq_attr "core_cycles" "single"))
+ "core")
diff --git a/contrib/gcc/config/arm/arm-modes.def b/contrib/gcc/config/arm/arm-modes.def
index b853551..10ba025 100644
--- a/contrib/gcc/config/arm/arm-modes.def
+++ b/contrib/gcc/config/arm/arm-modes.def
@@ -1,5 +1,5 @@
/* Definitions of target machine for GNU compiler, for ARM.
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004 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)
@@ -19,8 +19,8 @@
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, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* Extended precision floating point.
FIXME What format is this? */
@@ -50,3 +50,11 @@ CC_MODE (CC_DGEU);
CC_MODE (CC_DGTU);
CC_MODE (CC_C);
CC_MODE (CC_N);
+
+/* Vector modes. */
+VECTOR_MODES (INT, 4); /* V4QI V2HI */
+VECTOR_MODES (INT, 8); /* V8QI V4HI V2SI */
+VECTOR_MODES (INT, 16); /* V16QI V8HI V4SI V2DI */
+VECTOR_MODES (FLOAT, 8); /* V4HF V2SF */
+VECTOR_MODES (FLOAT, 16); /* V8HF V4SF V2DF */
+
diff --git a/contrib/gcc/config/arm/arm-protos.h b/contrib/gcc/config/arm/arm-protos.h
index 0b28e74..c8c119e 100644
--- a/contrib/gcc/config/arm/arm-protos.h
+++ b/contrib/gcc/config/arm/arm-protos.h
@@ -1,5 +1,5 @@
/* Prototypes for exported functions defined in arm.c and pe.c
- Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005
+ Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
Free Software Foundation, Inc.
Contributed by Richard Earnshaw (rearnsha@arm.com)
Minor hacks by Nick Clifton (nickc@cygnus.com)
@@ -18,8 +18,8 @@
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, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#ifndef GCC_ARM_PROTOS_H
#define GCC_ARM_PROTOS_H
@@ -27,76 +27,57 @@
extern void arm_override_options (void);
extern int use_return_insn (int, rtx);
extern int arm_regno_class (int);
-extern void arm_finalize_pic (int);
+extern void arm_load_pic_register (unsigned long);
extern int arm_volatile_func (void);
extern const char *arm_output_epilogue (rtx);
extern void arm_expand_prologue (void);
-extern HOST_WIDE_INT arm_get_frame_size (void);
extern const char *arm_strip_name_encoding (const char *);
extern void arm_asm_output_labelref (FILE *, const char *);
extern unsigned long arm_current_func_type (void);
-extern unsigned int arm_compute_initial_elimination_offset (unsigned int,
- unsigned int);
+extern HOST_WIDE_INT arm_compute_initial_elimination_offset (unsigned int,
+ unsigned int);
+extern HOST_WIDE_INT thumb_compute_initial_elimination_offset (unsigned int,
+ unsigned int);
+extern unsigned int arm_dbx_register_number (unsigned int);
+extern void arm_output_fn_unwind (FILE *, bool);
+
#ifdef TREE_CODE
extern int arm_return_in_memory (tree);
extern void arm_encode_call_attribute (tree, int);
#endif
#ifdef RTX_CODE
+extern bool arm_vector_mode_supported_p (enum machine_mode);
extern int arm_hard_regno_mode_ok (unsigned int, enum machine_mode);
extern int const_ok_for_arm (HOST_WIDE_INT);
-extern int arm_split_constant (RTX_CODE, enum machine_mode, HOST_WIDE_INT, rtx,
- rtx, int);
-extern RTX_CODE arm_canonicalize_comparison (RTX_CODE, rtx *);
+extern int arm_split_constant (RTX_CODE, enum machine_mode, rtx,
+ HOST_WIDE_INT, rtx, rtx, int);
+extern RTX_CODE arm_canonicalize_comparison (RTX_CODE, enum machine_mode,
+ rtx *);
extern int legitimate_pic_operand_p (rtx);
extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx);
-extern int arm_legitimate_address_p (enum machine_mode, rtx, int);
+extern rtx legitimize_tls_address (rtx, rtx);
+extern int arm_legitimate_address_p (enum machine_mode, rtx, RTX_CODE, int);
extern int thumb_legitimate_address_p (enum machine_mode, rtx, int);
extern int thumb_legitimate_offset_p (enum machine_mode, HOST_WIDE_INT);
extern rtx arm_legitimize_address (rtx, rtx, enum machine_mode);
-extern int const_double_rtx_ok_for_fpa (rtx);
+extern rtx thumb_legitimize_address (rtx, rtx, enum machine_mode);
+extern rtx thumb_legitimize_reload_address (rtx *, enum machine_mode, int, int,
+ int);
+extern int arm_const_double_rtx (rtx);
extern int neg_const_double_rtx_ok_for_fpa (rtx);
+extern enum reg_class coproc_secondary_reload_class (enum machine_mode, rtx,
+ bool);
+extern bool arm_tls_referenced_p (rtx);
-/* Predicates. */
-extern int s_register_operand (rtx, enum machine_mode);
-extern int arm_hard_register_operand (rtx, enum machine_mode);
-extern int f_register_operand (rtx, enum machine_mode);
-extern int reg_or_int_operand (rtx, enum machine_mode);
-extern int arm_reload_memory_operand (rtx, enum machine_mode);
-extern int arm_rhs_operand (rtx, enum machine_mode);
-extern int arm_rhsm_operand (rtx, enum machine_mode);
-extern int arm_add_operand (rtx, enum machine_mode);
-extern int arm_addimm_operand (rtx, enum machine_mode);
-extern int arm_not_operand (rtx, enum machine_mode);
-extern int offsettable_memory_operand (rtx, enum machine_mode);
-extern int alignable_memory_operand (rtx, enum machine_mode);
-extern int bad_signed_byte_operand (rtx, enum machine_mode);
-extern int fpa_rhs_operand (rtx, enum machine_mode);
-extern int fpa_add_operand (rtx, enum machine_mode);
-extern int power_of_two_operand (rtx, enum machine_mode);
-extern int nonimmediate_di_operand (rtx, enum machine_mode);
-extern int di_operand (rtx, enum machine_mode);
-extern int nonimmediate_soft_df_operand (rtx, enum machine_mode);
-extern int soft_df_operand (rtx, enum machine_mode);
-extern int index_operand (rtx, enum machine_mode);
-extern int const_shift_operand (rtx, enum machine_mode);
-extern int arm_comparison_operator (rtx, enum machine_mode);
-extern int shiftable_operator (rtx, enum machine_mode);
-extern int shift_operator (rtx, enum machine_mode);
-extern int equality_operator (rtx, enum machine_mode);
-extern int minmax_operator (rtx, enum machine_mode);
-extern int cc_register (rtx, enum machine_mode);
-extern int dominant_cc_register (rtx, enum machine_mode);
-extern int logical_binary_operator (rtx, enum machine_mode);
-extern int multi_register_push (rtx, enum machine_mode);
-extern int load_multiple_operation (rtx, enum machine_mode);
-extern int store_multiple_operation (rtx, enum machine_mode);
-extern int cirrus_fp_register (rtx, enum machine_mode);
-extern int cirrus_general_operand (rtx, enum machine_mode);
-extern int cirrus_register_operand (rtx, enum machine_mode);
-extern int cirrus_shift_const (rtx, enum machine_mode);
extern int cirrus_memory_offset (rtx);
+extern int arm_coproc_mem_operand (rtx, bool);
+extern int arm_no_early_store_addr_dep (rtx, rtx);
+extern int arm_no_early_alu_shift_dep (rtx, rtx);
+extern int arm_no_early_alu_shift_value_dep (rtx, rtx);
+extern int arm_no_early_mul_dep (rtx, rtx);
+extern int tls_mentioned_p (rtx);
extern int symbol_mentioned_p (rtx);
extern int label_mentioned_p (rtx);
extern RTX_CODE minmax_code (rtx);
@@ -109,8 +90,7 @@ extern rtx arm_gen_load_multiple (int, int, rtx, int, int,
rtx, HOST_WIDE_INT *);
extern rtx arm_gen_store_multiple (int, int, rtx, int, int,
rtx, HOST_WIDE_INT *);
-extern int arm_gen_movstrqi (rtx *);
-extern rtx arm_gen_rotated_half_load (rtx);
+extern int arm_gen_movmemqi (rtx *);
extern enum machine_mode arm_select_cc_mode (RTX_CODE, rtx, rtx);
extern enum machine_mode arm_select_dominance_cc_mode (rtx, rtx,
HOST_WIDE_INT);
@@ -118,6 +98,8 @@ extern rtx arm_gen_compare_reg (RTX_CODE, rtx, rtx);
extern rtx arm_gen_return_addr_mask (void);
extern void arm_reload_in_hi (rtx *);
extern void arm_reload_out_hi (rtx *);
+extern int arm_const_double_inline_cost (rtx);
+extern bool arm_const_double_by_parts (rtx);
extern const char *fp_immediate_constant (rtx);
extern const char *output_call (rtx *);
extern const char *output_call_mem (rtx *);
@@ -127,7 +109,6 @@ extern const char *output_mov_long_double_arm_from_arm (rtx *);
extern const char *output_mov_double_fpa_from_arm (rtx *);
extern const char *output_mov_double_arm_from_fpa (rtx *);
extern const char *output_move_double (rtx *);
-extern const char *output_mov_immediate (rtx *);
extern const char *output_add_immediate (rtx *);
extern const char *arithmetic_instr (rtx, int);
extern void output_ascii_pseudo_op (FILE *, const unsigned char *, int);
@@ -141,24 +122,27 @@ extern int arm_debugger_arg_offset (int, rtx);
extern int arm_is_longcall_p (rtx, int, int);
extern int arm_emit_vector_const (FILE *, rtx);
extern const char * arm_output_load_gr (rtx *);
+extern const char *vfp_output_fstmx (rtx *);
+extern void arm_set_return_address (rtx, rtx);
extern int arm_eliminable_register (rtx);
+extern bool arm_output_addr_const_extra (FILE *, rtx);
+
#if defined TREE_CODE
extern rtx arm_function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, int);
extern void arm_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree);
-extern rtx arm_va_arg (tree, tree);
-extern int arm_function_arg_pass_by_reference (CUMULATIVE_ARGS *,
- enum machine_mode, tree, int);
+extern bool arm_pad_arg_upward (enum machine_mode, tree);
+extern bool arm_pad_reg_upward (enum machine_mode, tree, int);
+extern bool arm_needs_doubleword_align (enum machine_mode, tree);
+extern rtx arm_function_value(tree, tree);
#endif
+extern int arm_apply_result_size (void);
-#if defined AOF_ASSEMBLER
+#if defined AOF_ASSEMBLER
extern rtx aof_pic_entry (rtx);
-extern char *aof_text_section (void);
-extern char *aof_data_section (void);
extern void aof_add_import (const char *);
extern void aof_delete_import (const char *);
extern void zero_init_section (void);
-extern void common_section (void);
#endif /* AOF_ASSEMBLER */
#endif /* RTX_CODE */
@@ -167,9 +151,7 @@ extern int arm_float_words_big_endian (void);
/* Thumb functions. */
extern void arm_init_expanders (void);
-extern int thumb_far_jump_used_p (int);
extern const char *thumb_unexpanded_epilogue (void);
-extern HOST_WIDE_INT thumb_get_frame_size (void);
extern void thumb_expand_prologue (void);
extern void thumb_expand_epilogue (void);
#ifdef TREE_CODE
@@ -180,14 +162,13 @@ extern int thumb_shiftable_const (unsigned HOST_WIDE_INT);
extern void thumb_final_prescan_insn (rtx);
extern const char *thumb_load_double_from_address (rtx *);
extern const char *thumb_output_move_mem_multiple (int, rtx *);
-extern void thumb_expand_movstrqi (rtx *);
-extern int thumb_cmp_operand (rtx, enum machine_mode);
-extern int thumb_cbrch_target_operand (rtx, enum machine_mode);
-extern rtx *thumb_legitimize_pic_address (rtx, enum machine_mode, rtx);
+extern const char *thumb_call_via_reg (rtx);
+extern void thumb_expand_movmemqi (rtx *);
extern int thumb_go_if_legitimate_address (enum machine_mode, rtx);
extern rtx arm_return_addr (int, rtx);
extern void thumb_reload_out_hi (rtx *);
extern void thumb_reload_in_hi (rtx *);
+extern void thumb_set_return_address (rtx, rtx);
#endif
/* Defined in pe.c. */
diff --git a/contrib/gcc/config/arm/arm-tune.md b/contrib/gcc/config/arm/arm-tune.md
new file mode 100644
index 0000000..950cd91
--- /dev/null
+++ b/contrib/gcc/config/arm/arm-tune.md
@@ -0,0 +1,5 @@
+;; -*- buffer-read-only: t -*-
+;; Generated automatically by gentune.sh from arm-cores.def
+(define_attr "tune"
+ "arm2,arm250,arm3,arm6,arm60,arm600,arm610,arm620,arm7,arm7d,arm7di,arm70,arm700,arm700i,arm710,arm720,arm710c,arm7100,arm7500,arm7500fe,arm7m,arm7dm,arm7dmi,arm8,arm810,strongarm,strongarm110,strongarm1100,strongarm1110,arm7tdmi,arm7tdmis,arm710t,arm720t,arm740t,arm9,arm9tdmi,arm920,arm920t,arm922t,arm940t,ep9312,arm10tdmi,arm1020t,arm9e,arm946es,arm966es,arm968es,arm10e,arm1020e,arm1022e,xscale,iwmmxt,arm926ejs,arm1026ejs,arm1136js,arm1136jfs,arm1176jzs,arm1176jzfs,mpcorenovfp,mpcore"
+ (const (symbol_ref "arm_tune")))
diff --git a/contrib/gcc/config/arm/arm.c b/contrib/gcc/config/arm/arm.c
index 2f0eaed..dc7aa77 100644
--- a/contrib/gcc/config/arm/arm.c
+++ b/contrib/gcc/config/arm/arm.c
@@ -1,6 +1,6 @@
/* Output routines for GCC for ARM.
Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ 2002, 2003, 2004, 2005, 2006 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).
@@ -19,9 +19,9 @@
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, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
-
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
#include "config.h"
#include "system.h"
#include "coretypes.h"
@@ -51,6 +51,7 @@
#include "target.h"
#include "target-def.h"
#include "debug.h"
+#include "langhooks.h"
/* Forward definitions of types. */
typedef struct minipool_node Mnode;
@@ -59,34 +60,32 @@ typedef struct minipool_fixup Mfix;
const struct attribute_spec arm_attribute_table[];
/* Forward function declarations. */
+static arm_stack_offsets *arm_get_frame_offsets (void);
static void arm_add_gc_roots (void);
-static int arm_gen_constant (enum rtx_code, enum machine_mode, HOST_WIDE_INT,
- rtx, rtx, int, int);
+static int arm_gen_constant (enum rtx_code, enum machine_mode, rtx,
+ HOST_WIDE_INT, rtx, rtx, int, int);
static unsigned bit_count (unsigned long);
static int arm_address_register_rtx_p (rtx, int);
-static int arm_legitimate_index_p (enum machine_mode, rtx, int);
+static int arm_legitimate_index_p (enum machine_mode, rtx, RTX_CODE, int);
static int thumb_base_register_rtx_p (rtx, enum machine_mode, int);
inline static int thumb_index_register_rtx_p (rtx, int);
+static int thumb_far_jump_used_p (void);
+static bool thumb_force_lr_save (void);
static int const_ok_for_op (HOST_WIDE_INT, enum rtx_code);
-static rtx emit_multi_reg_push (int);
static rtx emit_sfm (int, int);
+static int arm_size_return_regs (void);
#ifndef AOF_ASSEMBLER
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 void init_fpa_table (void);
static HOST_WIDE_INT int_log2 (HOST_WIDE_INT);
static rtx is_jump_table (rtx);
static const char *output_multi_immediate (rtx *, const char *, const char *,
int, HOST_WIDE_INT);
-static void print_multi_reg (FILE *, const char *, int, int);
static const char *shift_op (rtx, HOST_WIDE_INT *);
static struct machine_function *arm_init_machine_status (void);
-static int number_of_first_bit_set (int);
-static void replace_symbols_in_block (tree, rtx, rtx);
-static void thumb_exit (FILE *, int, rtx);
-static void thumb_pushpop (FILE *, int, int, int *, int);
+static void thumb_exit (FILE *, int);
static rtx is_jump_table (rtx);
static HOST_WIDE_INT get_jump_table_size (rtx);
static Mnode *move_minipool_fix_forward_ref (Mnode *, Mnode *, HOST_WIDE_INT);
@@ -110,13 +109,15 @@ static unsigned long arm_isr_value (tree);
static unsigned long arm_compute_func_type (void);
static tree arm_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
static tree arm_handle_isr_attribute (tree *, tree, tree, int, bool *);
+#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
+static tree arm_handle_notshared_attribute (tree *, tree, tree, int, bool *);
+#endif
static void arm_output_function_epilogue (FILE *, HOST_WIDE_INT);
static void arm_output_function_prologue (FILE *, HOST_WIDE_INT);
static void thumb_output_function_prologue (FILE *, HOST_WIDE_INT);
static int arm_comp_type_attributes (tree, tree);
static void arm_set_default_type_attributes (tree);
static int arm_adjust_cost (rtx, rtx, rtx, int);
-static int arm_use_dfa_pipeline_interface (void);
static int count_insns_for_constant (HOST_WIDE_INT, int);
static int arm_get_strip_length (int);
static bool arm_function_ok_for_sibcall (tree, tree);
@@ -124,7 +125,11 @@ static void arm_internal_label (FILE *, const char *, unsigned long);
static void arm_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT,
tree);
static int arm_rtx_costs_1 (rtx, enum rtx_code, enum rtx_code);
-static bool arm_rtx_costs (rtx, int, int, int *);
+static bool arm_size_rtx_costs (rtx, int, int, int *);
+static bool arm_slowmul_rtx_costs (rtx, int, int, int *);
+static bool arm_fastmul_rtx_costs (rtx, int, int, int *);
+static bool arm_xscale_rtx_costs (rtx, int, int, int *);
+static bool arm_9e_rtx_costs (rtx, int, int, int *);
static int arm_address_cost (rtx);
static bool arm_memory_load_p (rtx);
static bool arm_cirrus_insn_p (rtx);
@@ -136,24 +141,60 @@ static rtx safe_vector_operand (rtx, enum machine_mode);
static rtx arm_expand_binop_builtin (enum insn_code, tree, rtx);
static rtx arm_expand_unop_builtin (enum insn_code, tree, rtx, int);
static rtx arm_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
+static void emit_constant_insn (rtx cond, rtx pattern);
+static rtx emit_set_insn (rtx, rtx);
+static int arm_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
+ tree, bool);
#ifdef OBJECT_FORMAT_ELF
-static void arm_elf_asm_named_section (const char *, unsigned int);
+static void arm_elf_asm_constructor (rtx, int);
#endif
#ifndef ARM_PE
static void arm_encode_section_info (tree, rtx, int);
#endif
+
+static void arm_file_end (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);
+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);
+#ifdef TARGET_UNWIND_INFO
+static void arm_unwind_emit (FILE *, rtx);
+static bool arm_output_ttype (rtx);
+#endif
+
+static tree arm_cxx_guard_type (void);
+static bool arm_cxx_guard_mask_bit (void);
+static tree arm_get_cookie_size (tree);
+static bool arm_cookie_has_size (void);
+static bool arm_cxx_cdtor_returns_this (void);
+static bool arm_cxx_key_method_may_be_inline (void);
+static void arm_cxx_determine_class_data_visibility (tree);
+static bool arm_cxx_class_data_always_comdat (void);
+static bool arm_cxx_use_aeabi_atexit (void);
+static void arm_init_libfuncs (void);
+static bool arm_handle_option (size_t, const char *, int);
+static unsigned HOST_WIDE_INT arm_shift_truncation_mask (enum machine_mode);
+static bool arm_cannot_copy_insn_p (rtx);
+static bool arm_tls_symbol_p (rtx x);
/* Initialize the GCC target structure. */
-#ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES
+#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
#undef TARGET_MERGE_DECL_ATTRIBUTES
#define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes
#endif
@@ -161,6 +202,9 @@ static void aof_file_end (void);
#undef TARGET_ATTRIBUTE_TABLE
#define TARGET_ATTRIBUTE_TABLE arm_attribute_table
+#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"
@@ -187,6 +231,11 @@ static void aof_file_end (void);
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE arm_output_function_epilogue
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS (TARGET_DEFAULT | MASK_SCHED_PROLOG)
+#undef TARGET_HANDLE_OPTION
+#define TARGET_HANDLE_OPTION arm_handle_option
+
#undef TARGET_COMP_TYPE_ATTRIBUTES
#define TARGET_COMP_TYPE_ATTRIBUTES arm_comp_type_attributes
@@ -196,9 +245,6 @@ static void aof_file_end (void);
#undef TARGET_SCHED_ADJUST_COST
#define TARGET_SCHED_ADJUST_COST arm_adjust_cost
-#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
-#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE arm_use_dfa_pipeline_interface
-
#undef TARGET_ENCODE_SECTION_INFO
#ifdef ARM_PE
#define TARGET_ENCODE_SECTION_INFO arm_pe_encode_section_info
@@ -220,11 +266,17 @@ static void aof_file_end (void);
#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
+/* This will be overridden in arm_override_options. */
#undef TARGET_RTX_COSTS
-#define TARGET_RTX_COSTS arm_rtx_costs
+#define TARGET_RTX_COSTS arm_slowmul_rtx_costs
#undef TARGET_ADDRESS_COST
#define TARGET_ADDRESS_COST arm_address_cost
+#undef TARGET_SHIFT_TRUNCATION_MASK
+#define TARGET_SHIFT_TRUNCATION_MASK arm_shift_truncation_mask
+#undef TARGET_VECTOR_MODE_SUPPORTED_P
+#define TARGET_VECTOR_MODE_SUPPORTED_P arm_vector_mode_supported_p
+
#undef TARGET_MACHINE_DEPENDENT_REORG
#define TARGET_MACHINE_DEPENDENT_REORG arm_reorg
@@ -233,6 +285,89 @@ static void aof_file_end (void);
#undef TARGET_EXPAND_BUILTIN
#define TARGET_EXPAND_BUILTIN arm_expand_builtin
+#undef TARGET_INIT_LIBFUNCS
+#define TARGET_INIT_LIBFUNCS arm_init_libfuncs
+
+#undef TARGET_PROMOTE_FUNCTION_ARGS
+#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
+#undef TARGET_PROMOTE_FUNCTION_RETURN
+#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
+#undef TARGET_PROMOTE_PROTOTYPES
+#define TARGET_PROMOTE_PROTOTYPES arm_promote_prototypes
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE arm_pass_by_reference
+#undef TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES arm_arg_partial_bytes
+
+#undef TARGET_SETUP_INCOMING_VARARGS
+#define TARGET_SETUP_INCOMING_VARARGS arm_setup_incoming_varargs
+
+#undef TARGET_DEFAULT_SHORT_ENUMS
+#define TARGET_DEFAULT_SHORT_ENUMS arm_default_short_enums
+
+#undef TARGET_ALIGN_ANON_BITFIELD
+#define TARGET_ALIGN_ANON_BITFIELD arm_align_anon_bitfield
+
+#undef TARGET_NARROW_VOLATILE_BITFIELD
+#define TARGET_NARROW_VOLATILE_BITFIELD hook_bool_void_false
+
+#undef TARGET_CXX_GUARD_TYPE
+#define TARGET_CXX_GUARD_TYPE arm_cxx_guard_type
+
+#undef TARGET_CXX_GUARD_MASK_BIT
+#define TARGET_CXX_GUARD_MASK_BIT arm_cxx_guard_mask_bit
+
+#undef TARGET_CXX_GET_COOKIE_SIZE
+#define TARGET_CXX_GET_COOKIE_SIZE arm_get_cookie_size
+
+#undef TARGET_CXX_COOKIE_HAS_SIZE
+#define TARGET_CXX_COOKIE_HAS_SIZE arm_cookie_has_size
+
+#undef TARGET_CXX_CDTOR_RETURNS_THIS
+#define TARGET_CXX_CDTOR_RETURNS_THIS arm_cxx_cdtor_returns_this
+
+#undef TARGET_CXX_KEY_METHOD_MAY_BE_INLINE
+#define TARGET_CXX_KEY_METHOD_MAY_BE_INLINE arm_cxx_key_method_may_be_inline
+
+#undef TARGET_CXX_USE_AEABI_ATEXIT
+#define TARGET_CXX_USE_AEABI_ATEXIT arm_cxx_use_aeabi_atexit
+
+#undef TARGET_CXX_DETERMINE_CLASS_DATA_VISIBILITY
+#define TARGET_CXX_DETERMINE_CLASS_DATA_VISIBILITY \
+ arm_cxx_determine_class_data_visibility
+
+#undef TARGET_CXX_CLASS_DATA_ALWAYS_COMDAT
+#define TARGET_CXX_CLASS_DATA_ALWAYS_COMDAT arm_cxx_class_data_always_comdat
+
+#undef TARGET_RETURN_IN_MSB
+#define TARGET_RETURN_IN_MSB arm_return_in_msb
+
+#undef TARGET_MUST_PASS_IN_STACK
+#define TARGET_MUST_PASS_IN_STACK arm_must_pass_in_stack
+
+#ifdef TARGET_UNWIND_INFO
+#undef TARGET_UNWIND_EMIT
+#define TARGET_UNWIND_EMIT arm_unwind_emit
+
+/* EABI unwinding tables use a different format for the typeinfo tables. */
+#undef TARGET_ASM_TTYPE
+#define TARGET_ASM_TTYPE arm_output_ttype
+
+#undef TARGET_ARM_EABI_UNWINDER
+#define TARGET_ARM_EABI_UNWINDER true
+#endif /* TARGET_UNWIND_INFO */
+
+#undef TARGET_CANNOT_COPY_INSN_P
+#define TARGET_CANNOT_COPY_INSN_P arm_cannot_copy_insn_p
+
+#ifdef HAVE_AS_TLS
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS true
+#endif
+
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM arm_tls_referenced_p
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* Obstack for minipool constant handling. */
@@ -252,25 +387,37 @@ int making_const_table;
stored from the compare operation. */
rtx arm_compare_op0, arm_compare_op1;
-/* What type of floating point are we tuning for? */
-enum fputype arm_fpu_tune;
+/* The processor for which instructions should be scheduled. */
+enum processor_type arm_tune = arm_none;
+
+/* Which floating point model to use. */
+enum arm_fp_model arm_fp_model;
-/* What type of floating point instructions are available? */
+/* Which floating point hardware is available. */
enum fputype arm_fpu_arch;
-/* What program mode is the cpu running in? 26-bit mode or 32-bit mode. */
-enum prog_mode_type arm_prgmode;
+/* Which floating point hardware to schedule for. */
+enum fputype arm_fpu_tune;
+
+/* Whether to use floating point hardware. */
+enum float_abi_type arm_float_abi;
+
+/* Which ABI to use. */
+enum arm_abi_type arm_abi;
-/* Set by the -mfp=... option. */
-const char * target_fp_name = NULL;
+/* Which thread pointer model to use. */
+enum arm_tp_type target_thread_pointer = TP_AUTO;
/* Used to parse -mstructure_size_boundary command line option. */
-const char * structure_size_string = NULL;
int arm_structure_size_boundary = DEFAULT_STRUCTURE_SIZE_BOUNDARY;
+/* Used for Thumb call_via trampolines. */
+rtx thumb_call_via_label[14];
+static int thumb_call_reg_needed;
+
/* Bit values used to identify processor capabilities. */
#define FL_CO_PROC (1 << 0) /* Has external co-processor bus */
-#define FL_FAST_MULT (1 << 1) /* Fast multiply */
+#define FL_ARCH3M (1 << 1) /* Extended multiply */
#define FL_MODE26 (1 << 2) /* 26-bit mode support */
#define FL_MODE32 (1 << 3) /* 32-bit mode support */
#define FL_ARCH4 (1 << 4) /* Architecture rel 4 */
@@ -281,41 +428,71 @@ int arm_structure_size_boundary = DEFAULT_STRUCTURE_SIZE_BOUNDARY;
#define FL_ARCH5E (1 << 9) /* DSP extensions to v5 */
#define FL_XSCALE (1 << 10) /* XScale */
#define FL_CIRRUS (1 << 11) /* Cirrus/DSP. */
-#define FL_IWMMXT (1 << 29) /* XScale v2 or "Intel Wireless MMX technology". */
-#define FL_ARCH6J (1 << 12) /* Architecture rel 6. Adds
+#define FL_ARCH6 (1 << 12) /* Architecture rel 6. Adds
media instructions. */
#define FL_VFPV2 (1 << 13) /* Vector Floating Point V2. */
+#define FL_WBUF (1 << 14) /* Schedule for write buffer ops.
+ Note: ARM6 & 7 derivatives only. */
+#define FL_ARCH6K (1 << 15) /* Architecture rel 6 K extensions. */
+
+#define FL_IWMMXT (1 << 29) /* XScale v2 or "Intel Wireless MMX technology". */
+
+#define FL_FOR_ARCH2 0
+#define FL_FOR_ARCH3 FL_MODE32
+#define FL_FOR_ARCH3M (FL_FOR_ARCH3 | FL_ARCH3M)
+#define FL_FOR_ARCH4 (FL_FOR_ARCH3M | FL_ARCH4)
+#define FL_FOR_ARCH4T (FL_FOR_ARCH4 | FL_THUMB)
+#define FL_FOR_ARCH5 (FL_FOR_ARCH4 | FL_ARCH5)
+#define FL_FOR_ARCH5T (FL_FOR_ARCH5 | FL_THUMB)
+#define FL_FOR_ARCH5E (FL_FOR_ARCH5 | FL_ARCH5E)
+#define FL_FOR_ARCH5TE (FL_FOR_ARCH5E | FL_THUMB)
+#define FL_FOR_ARCH5TEJ FL_FOR_ARCH5TE
+#define FL_FOR_ARCH6 (FL_FOR_ARCH5TE | FL_ARCH6)
+#define FL_FOR_ARCH6J FL_FOR_ARCH6
+#define FL_FOR_ARCH6K (FL_FOR_ARCH6 | FL_ARCH6K)
+#define FL_FOR_ARCH6Z FL_FOR_ARCH6
+#define FL_FOR_ARCH6ZK FL_FOR_ARCH6K
/* The bits in this mask specify which
instructions we are allowed to generate. */
static unsigned long insn_flags = 0;
/* The bits in this mask specify which instruction scheduling options should
- be used. Note - there is an overlap with the FL_FAST_MULT. For some
- hardware we want to be able to generate the multiply instructions, but to
- tune as if they were not present in the architecture. */
+ be used. */
static unsigned long tune_flags = 0;
/* The following are used in the arm.md file as equivalents to bits
in the above two flag variables. */
-/* Nonzero if this is an "M" variant of the processor. */
-int arm_fast_multiply = 0;
+/* Nonzero if this chip supports the ARM Architecture 3M extensions. */
+int arm_arch3m = 0;
/* Nonzero if this chip supports the ARM Architecture 4 extensions. */
int arm_arch4 = 0;
+/* Nonzero if this chip supports the ARM Architecture 4t extensions. */
+int arm_arch4t = 0;
+
/* Nonzero if this chip supports the ARM Architecture 5 extensions. */
int arm_arch5 = 0;
/* Nonzero if this chip supports the ARM Architecture 5E extensions. */
int arm_arch5e = 0;
+/* Nonzero if this chip supports the ARM Architecture 6 extensions. */
+int arm_arch6 = 0;
+
+/* Nonzero if this chip supports the ARM 6K extensions. */
+int arm_arch6k = 0;
+
/* Nonzero if this chip can benefit from load scheduling. */
int arm_ld_sched = 0;
/* Nonzero if this chip is a StrongARM. */
-int arm_is_strong = 0;
+int arm_tune_strongarm = 0;
+
+/* Nonzero if this chip is a Cirrus variant. */
+int arm_arch_cirrus = 0;
/* Nonzero if this chip supports Intel Wireless MMX technology. */
int arm_arch_iwmmxt = 0;
@@ -326,23 +503,27 @@ int arm_arch_xscale = 0;
/* Nonzero if tuning for XScale */
int arm_tune_xscale = 0;
-/* Nonzero if this chip is an ARM6 or an ARM7. */
-int arm_is_6_or_7 = 0;
-
-/* Nonzero if this chip is a Cirrus/DSP. */
-int arm_is_cirrus = 0;
+/* Nonzero if we want to tune for stores that access the write-buffer.
+ This typically means an ARM6 or ARM7 with MMU or MPU. */
+int arm_tune_wbuf = 0;
/* Nonzero if generating Thumb instructions. */
int thumb_code = 0;
+/* Nonzero if we should define __THUMB_INTERWORK__ in the
+ preprocessor.
+ XXX This is a bit of a hack, it's intended to help work around
+ problems in GLD which doesn't understand that armv5t code is
+ interworking clean. */
+int arm_cpp_interwork = 0;
+
/* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference, we
must report the mode of the memory reference from PRINT_OPERAND to
PRINT_OPERAND_ADDRESS. */
enum machine_mode output_memory_reference_mode;
/* The register number to be used for the PIC offset register. */
-const char * arm_pic_register_string = NULL;
-int arm_pic_register = INVALID_REGNUM;
+unsigned arm_pic_register = INVALID_REGNUM;
/* Set to 1 when a return insn is output, this means that the epilogue
is not needed. */
@@ -375,7 +556,10 @@ static const char * const arm_condition_codes[] =
struct processors
{
const char *const name;
+ enum processor_type core;
+ const char *arch;
const unsigned long flags;
+ bool (* rtx_costs) (rtx, int, int, int *);
};
/* Not all of these give usefully different compilation alternatives,
@@ -383,103 +567,162 @@ struct processors
static const struct processors all_cores[] =
{
/* ARM Cores */
-
- {"arm2", FL_CO_PROC | FL_MODE26 },
- {"arm250", FL_CO_PROC | FL_MODE26 },
- {"arm3", FL_CO_PROC | FL_MODE26 },
- {"arm6", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
- {"arm60", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
- {"arm600", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
- {"arm610", FL_MODE26 | FL_MODE32 },
- {"arm620", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
- {"arm7", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
- /* arm7m doesn't exist on its own, but only with D, (and I), but
- those don't alter the code, so arm7m is sometimes used. */
- {"arm7m", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT },
- {"arm7d", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
- {"arm7dm", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT },
- {"arm7di", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
- {"arm7dmi", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT },
- {"arm70", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
- {"arm700", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
- {"arm700i", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
- {"arm710", FL_MODE26 | FL_MODE32 },
- {"arm720", FL_MODE26 | FL_MODE32 },
- {"arm710c", FL_MODE26 | FL_MODE32 },
- {"arm7100", FL_MODE26 | FL_MODE32 },
- {"arm7500", FL_MODE26 | FL_MODE32 },
- /* Doesn't have an external co-proc, but does have embedded fpa. */
- {"arm7500fe", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
- /* V4 Architecture Processors */
- {"arm7tdmi", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB },
- {"arm710t", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB },
- {"arm720t", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB },
- {"arm740t", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB },
- {"arm8", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED },
- {"arm810", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED },
- {"arm9", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
- {"arm920", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED },
- {"arm920t", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
- {"arm940t", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
- {"arm9tdmi", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
- {"arm9e", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED },
- {"ep9312", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_CIRRUS },
- {"strongarm", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_STRONG },
- {"strongarm110", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_STRONG },
- {"strongarm1100", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_STRONG },
- {"strongarm1110", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_STRONG },
- /* V5 Architecture Processors */
- {"arm10tdmi", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED | FL_ARCH5 },
- {"arm1020t", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED | FL_ARCH5 },
- {"arm926ejs", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 | FL_ARCH5E },
- {"arm1026ejs", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 | FL_ARCH5E },
- {"xscale", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED | FL_STRONG | FL_ARCH5 | FL_ARCH5E | FL_XSCALE },
- {"iwmmxt", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED | FL_STRONG | FL_ARCH5 | FL_ARCH5E | FL_XSCALE | FL_IWMMXT },
- /* V6 Architecture Processors */
- {"arm1136js", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 | FL_ARCH5E | FL_ARCH6J },
- {"arm1136jfs", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 | FL_ARCH5E | FL_ARCH6J | FL_VFPV2 },
- {NULL, 0}
+#define ARM_CORE(NAME, IDENT, ARCH, FLAGS, COSTS) \
+ {NAME, arm_none, #ARCH, FLAGS | FL_FOR_ARCH##ARCH, arm_##COSTS##_rtx_costs},
+#include "arm-cores.def"
+#undef ARM_CORE
+ {NULL, arm_none, NULL, 0, NULL}
};
static const struct processors all_architectures[] =
{
/* ARM Architectures */
-
- { "armv2", FL_CO_PROC | FL_MODE26 },
- { "armv2a", FL_CO_PROC | FL_MODE26 },
- { "armv3", FL_CO_PROC | FL_MODE26 | FL_MODE32 },
- { "armv3m", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT },
- { "armv4", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 },
+ /* We don't specify rtx_costs here as it will be figured out
+ from the core. */
+
+ {"armv2", arm2, "2", FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH2, NULL},
+ {"armv2a", arm2, "2", FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH2, NULL},
+ {"armv3", arm6, "3", FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH3, NULL},
+ {"armv3m", arm7m, "3M", FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH3M, NULL},
+ {"armv4", arm7tdmi, "4", FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH4, NULL},
/* Strictly, FL_MODE26 is a permitted option for v4t, but there are no
implementations that support it, so we will leave it out for now. */
- { "armv4t", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB },
- { "armv5", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 },
- { "armv5t", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 },
- { "armv5te", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 | FL_ARCH5E },
- { "armv6j", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 | FL_ARCH5E | FL_ARCH6J },
- { "ep9312", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_CIRRUS },
- {"iwmmxt", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED | FL_STRONG | FL_ARCH5 | FL_ARCH5E | FL_XSCALE | FL_IWMMXT },
- { NULL, 0 }
+ {"armv4t", arm7tdmi, "4T", FL_CO_PROC | FL_FOR_ARCH4T, NULL},
+ {"armv5", arm10tdmi, "5", FL_CO_PROC | FL_FOR_ARCH5, NULL},
+ {"armv5t", arm10tdmi, "5T", FL_CO_PROC | FL_FOR_ARCH5T, NULL},
+ {"armv5e", arm1026ejs, "5E", FL_CO_PROC | FL_FOR_ARCH5E, NULL},
+ {"armv5te", arm1026ejs, "5TE", FL_CO_PROC | FL_FOR_ARCH5TE, NULL},
+ {"armv6", arm1136js, "6", FL_CO_PROC | FL_FOR_ARCH6, NULL},
+ {"armv6j", arm1136js, "6J", FL_CO_PROC | FL_FOR_ARCH6J, NULL},
+ {"armv6k", mpcore, "6K", FL_CO_PROC | FL_FOR_ARCH6K, NULL},
+ {"armv6z", arm1176jzs, "6Z", FL_CO_PROC | FL_FOR_ARCH6Z, NULL},
+ {"armv6zk", arm1176jzs, "6ZK", FL_CO_PROC | FL_FOR_ARCH6ZK, NULL},
+ {"ep9312", ep9312, "4T", FL_LDSCHED | FL_CIRRUS | FL_FOR_ARCH4, NULL},
+ {"iwmmxt", iwmmxt, "5TE", FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT , NULL},
+ {NULL, arm_none, NULL, 0 , NULL}
+};
+
+struct arm_cpu_select
+{
+ const char * string;
+ const char * name;
+ const struct processors * processors;
};
/* This is a magic structure. The 'string' field is magically filled in
with a pointer to the value specified by the user on the command line
assuming that the user has specified such a value. */
-struct arm_cpu_select arm_select[] =
+static struct arm_cpu_select arm_select[] =
{
- /* string name processors */
+ /* string name processors */
{ NULL, "-mcpu=", all_cores },
{ NULL, "-march=", all_architectures },
{ NULL, "-mtune=", all_cores }
};
+/* Defines representing the indexes into the above table. */
+#define ARM_OPT_SET_CPU 0
+#define ARM_OPT_SET_ARCH 1
+#define ARM_OPT_SET_TUNE 2
+
+/* The name of the preprocessor macro to define for this architecture. */
+
+char arm_arch_name[] = "__ARM_ARCH_0UNK__";
+
+struct fpu_desc
+{
+ const char * name;
+ enum fputype fpu;
+};
+
+
+/* Available values for -mfpu=. */
+
+static const struct fpu_desc all_fpus[] =
+{
+ {"fpa", FPUTYPE_FPA},
+ {"fpe2", FPUTYPE_FPA_EMU2},
+ {"fpe3", FPUTYPE_FPA_EMU2},
+ {"maverick", FPUTYPE_MAVERICK},
+ {"vfp", FPUTYPE_VFP}
+};
+
+
+/* Floating point models used by the different hardware.
+ See fputype in arm.h. */
+
+static const enum fputype fp_model_for_fpu[] =
+{
+ /* No FP hardware. */
+ ARM_FP_MODEL_UNKNOWN, /* FPUTYPE_NONE */
+ ARM_FP_MODEL_FPA, /* FPUTYPE_FPA */
+ ARM_FP_MODEL_FPA, /* FPUTYPE_FPA_EMU2 */
+ ARM_FP_MODEL_FPA, /* FPUTYPE_FPA_EMU3 */
+ ARM_FP_MODEL_MAVERICK, /* FPUTYPE_MAVERICK */
+ ARM_FP_MODEL_VFP /* FPUTYPE_VFP */
+};
+
+
+struct float_abi
+{
+ const char * name;
+ enum float_abi_type abi_type;
+};
+
+
+/* Available values for -mfloat-abi=. */
+
+static const struct float_abi all_float_abis[] =
+{
+ {"soft", ARM_FLOAT_ABI_SOFT},
+ {"softfp", ARM_FLOAT_ABI_SOFTFP},
+ {"hard", ARM_FLOAT_ABI_HARD}
+};
+
+
+struct abi_name
+{
+ const char *name;
+ enum arm_abi_type abi_type;
+};
+
+
+/* Available values for -mabi=. */
+
+static const struct abi_name arm_all_abis[] =
+{
+ {"apcs-gnu", ARM_ABI_APCS},
+ {"atpcs", ARM_ABI_ATPCS},
+ {"aapcs", ARM_ABI_AAPCS},
+ {"iwmmxt", ARM_ABI_IWMMXT},
+ {"aapcs-linux", ARM_ABI_AAPCS_LINUX}
+};
+
+/* Supported TLS relocations. */
+
+enum tls_reloc {
+ TLS_GD32,
+ TLS_LDM32,
+ TLS_LDO32,
+ TLS_IE32,
+ TLS_LE32
+};
+
+/* Emit an insn that's a simple single-set. Both the operands must be known
+ to be valid. */
+inline static rtx
+emit_set_insn (rtx x, rtx y)
+{
+ return emit_insn (gen_rtx_SET (VOIDmode, x, y));
+}
+
/* Return the number of bits set in VALUE. */
static unsigned
bit_count (unsigned long value)
{
unsigned long count = 0;
-
+
while (value)
{
count++;
@@ -489,18 +732,159 @@ bit_count (unsigned long value)
return count;
}
+/* Set up library functions unique to ARM. */
+
+static void
+arm_init_libfuncs (void)
+{
+ /* There are no special library functions unless we are using the
+ ARM BPABI. */
+ if (!TARGET_BPABI)
+ return;
+
+ /* The functions below are described in Section 4 of the "Run-Time
+ ABI for the ARM architecture", Version 1.0. */
+
+ /* Double-precision floating-point arithmetic. Table 2. */
+ set_optab_libfunc (add_optab, DFmode, "__aeabi_dadd");
+ set_optab_libfunc (sdiv_optab, DFmode, "__aeabi_ddiv");
+ set_optab_libfunc (smul_optab, DFmode, "__aeabi_dmul");
+ set_optab_libfunc (neg_optab, DFmode, "__aeabi_dneg");
+ set_optab_libfunc (sub_optab, DFmode, "__aeabi_dsub");
+
+ /* Double-precision comparisons. Table 3. */
+ set_optab_libfunc (eq_optab, DFmode, "__aeabi_dcmpeq");
+ set_optab_libfunc (ne_optab, DFmode, NULL);
+ set_optab_libfunc (lt_optab, DFmode, "__aeabi_dcmplt");
+ set_optab_libfunc (le_optab, DFmode, "__aeabi_dcmple");
+ set_optab_libfunc (ge_optab, DFmode, "__aeabi_dcmpge");
+ set_optab_libfunc (gt_optab, DFmode, "__aeabi_dcmpgt");
+ set_optab_libfunc (unord_optab, DFmode, "__aeabi_dcmpun");
+
+ /* Single-precision floating-point arithmetic. Table 4. */
+ set_optab_libfunc (add_optab, SFmode, "__aeabi_fadd");
+ set_optab_libfunc (sdiv_optab, SFmode, "__aeabi_fdiv");
+ set_optab_libfunc (smul_optab, SFmode, "__aeabi_fmul");
+ set_optab_libfunc (neg_optab, SFmode, "__aeabi_fneg");
+ set_optab_libfunc (sub_optab, SFmode, "__aeabi_fsub");
+
+ /* Single-precision comparisons. Table 5. */
+ set_optab_libfunc (eq_optab, SFmode, "__aeabi_fcmpeq");
+ set_optab_libfunc (ne_optab, SFmode, NULL);
+ set_optab_libfunc (lt_optab, SFmode, "__aeabi_fcmplt");
+ set_optab_libfunc (le_optab, SFmode, "__aeabi_fcmple");
+ set_optab_libfunc (ge_optab, SFmode, "__aeabi_fcmpge");
+ set_optab_libfunc (gt_optab, SFmode, "__aeabi_fcmpgt");
+ set_optab_libfunc (unord_optab, SFmode, "__aeabi_fcmpun");
+
+ /* Floating-point to integer conversions. Table 6. */
+ set_conv_libfunc (sfix_optab, SImode, DFmode, "__aeabi_d2iz");
+ set_conv_libfunc (ufix_optab, SImode, DFmode, "__aeabi_d2uiz");
+ set_conv_libfunc (sfix_optab, DImode, DFmode, "__aeabi_d2lz");
+ set_conv_libfunc (ufix_optab, DImode, DFmode, "__aeabi_d2ulz");
+ set_conv_libfunc (sfix_optab, SImode, SFmode, "__aeabi_f2iz");
+ set_conv_libfunc (ufix_optab, SImode, SFmode, "__aeabi_f2uiz");
+ set_conv_libfunc (sfix_optab, DImode, SFmode, "__aeabi_f2lz");
+ set_conv_libfunc (ufix_optab, DImode, SFmode, "__aeabi_f2ulz");
+
+ /* Conversions between floating types. Table 7. */
+ set_conv_libfunc (trunc_optab, SFmode, DFmode, "__aeabi_d2f");
+ set_conv_libfunc (sext_optab, DFmode, SFmode, "__aeabi_f2d");
+
+ /* Integer to floating-point conversions. Table 8. */
+ set_conv_libfunc (sfloat_optab, DFmode, SImode, "__aeabi_i2d");
+ set_conv_libfunc (ufloat_optab, DFmode, SImode, "__aeabi_ui2d");
+ set_conv_libfunc (sfloat_optab, DFmode, DImode, "__aeabi_l2d");
+ set_conv_libfunc (ufloat_optab, DFmode, DImode, "__aeabi_ul2d");
+ set_conv_libfunc (sfloat_optab, SFmode, SImode, "__aeabi_i2f");
+ set_conv_libfunc (ufloat_optab, SFmode, SImode, "__aeabi_ui2f");
+ set_conv_libfunc (sfloat_optab, SFmode, DImode, "__aeabi_l2f");
+ set_conv_libfunc (ufloat_optab, SFmode, DImode, "__aeabi_ul2f");
+
+ /* Long long. Table 9. */
+ set_optab_libfunc (smul_optab, DImode, "__aeabi_lmul");
+ set_optab_libfunc (sdivmod_optab, DImode, "__aeabi_ldivmod");
+ set_optab_libfunc (udivmod_optab, DImode, "__aeabi_uldivmod");
+ set_optab_libfunc (ashl_optab, DImode, "__aeabi_llsl");
+ set_optab_libfunc (lshr_optab, DImode, "__aeabi_llsr");
+ set_optab_libfunc (ashr_optab, DImode, "__aeabi_lasr");
+ set_optab_libfunc (cmp_optab, DImode, "__aeabi_lcmp");
+ set_optab_libfunc (ucmp_optab, DImode, "__aeabi_ulcmp");
+
+ /* Integer (32/32->32) division. \S 4.3.1. */
+ set_optab_libfunc (sdivmod_optab, SImode, "__aeabi_idivmod");
+ set_optab_libfunc (udivmod_optab, SImode, "__aeabi_uidivmod");
+
+ /* The divmod functions are designed so that they can be used for
+ plain division, even though they return both the quotient and the
+ remainder. The quotient is returned in the usual location (i.e.,
+ r0 for SImode, {r0, r1} for DImode), just as would be expected
+ for an ordinary division routine. Because the AAPCS calling
+ conventions specify that all of { r0, r1, r2, r3 } are
+ callee-saved registers, there is no need to tell the compiler
+ explicitly that those registers are clobbered by these
+ routines. */
+ set_optab_libfunc (sdiv_optab, DImode, "__aeabi_ldivmod");
+ set_optab_libfunc (udiv_optab, DImode, "__aeabi_uldivmod");
+
+ /* For SImode division the ABI provides div-without-mod routines,
+ which are faster. */
+ set_optab_libfunc (sdiv_optab, SImode, "__aeabi_idiv");
+ set_optab_libfunc (udiv_optab, SImode, "__aeabi_uidiv");
+
+ /* We don't have mod libcalls. Fortunately gcc knows how to use the
+ divmod libcalls instead. */
+ set_optab_libfunc (smod_optab, DImode, NULL);
+ set_optab_libfunc (umod_optab, DImode, NULL);
+ set_optab_libfunc (smod_optab, SImode, NULL);
+ set_optab_libfunc (umod_optab, SImode, NULL);
+}
+
+/* Implement TARGET_HANDLE_OPTION. */
+
+static bool
+arm_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
+{
+ switch (code)
+ {
+ case OPT_march_:
+ arm_select[1].string = arg;
+ return true;
+
+ case OPT_mcpu_:
+ arm_select[0].string = arg;
+ return true;
+
+ case OPT_mhard_float:
+ target_float_abi_name = "hard";
+ return true;
+
+ case OPT_msoft_float:
+ target_float_abi_name = "soft";
+ return true;
+
+ case OPT_mtune_:
+ arm_select[2].string = arg;
+ return true;
+
+ default:
+ return true;
+ }
+}
+
/* Fix up any incompatible options that the user has specified.
This has now turned into a maze. */
void
arm_override_options (void)
{
unsigned i;
-
+ enum processor_type target_arch_cpu = arm_none;
+
/* Set up the flags based on the cpu/architecture selected by the user. */
for (i = ARRAY_SIZE (arm_select); i--;)
{
struct arm_cpu_select * ptr = arm_select + i;
-
+
if (ptr->string != NULL && ptr->string[0] != '\0')
{
const struct processors * sel;
@@ -508,21 +892,38 @@ arm_override_options (void)
for (sel = ptr->processors; sel->name != NULL; sel++)
if (streq (ptr->string, sel->name))
{
- if (i == 2)
- tune_flags = sel->flags;
- else
+ /* Set the architecture define. */
+ if (i != ARM_OPT_SET_TUNE)
+ sprintf (arm_arch_name, "__ARM_ARCH_%s__", sel->arch);
+
+ /* Determine the processor core for which we should
+ tune code-generation. */
+ if (/* -mcpu= is a sensible default. */
+ i == ARM_OPT_SET_CPU
+ /* -mtune= overrides -mcpu= and -march=. */
+ || i == ARM_OPT_SET_TUNE)
+ arm_tune = (enum processor_type) (sel - ptr->processors);
+
+ /* Remember the CPU associated with this architecture.
+ If no other option is used to set the CPU type,
+ we'll use this to guess the most suitable tuning
+ options. */
+ if (i == ARM_OPT_SET_ARCH)
+ target_arch_cpu = sel->core;
+
+ if (i != ARM_OPT_SET_TUNE)
{
/* If we have been given an architecture and a processor
make sure that they are compatible. We only generate
a warning though, and we prefer the CPU over the
architecture. */
if (insn_flags != 0 && (insn_flags ^ sel->flags))
- warning ("switch -mcpu=%s conflicts with -march= switch",
+ warning (0, "switch -mcpu=%s conflicts with -march= switch",
ptr->string);
-
+
insn_flags = sel->flags;
}
-
+
break;
}
@@ -530,71 +931,41 @@ arm_override_options (void)
error ("bad value (%s) for %s switch", ptr->string, ptr->name);
}
}
-
+
+ /* Guess the tuning options from the architecture if necessary. */
+ if (arm_tune == arm_none)
+ arm_tune = target_arch_cpu;
+
/* If the user did not specify a processor, choose one for them. */
if (insn_flags == 0)
{
const struct processors * sel;
unsigned int sought;
- static const struct cpu_default
- {
- const int cpu;
- const char *const name;
- }
- cpu_defaults[] =
- {
- { TARGET_CPU_arm2, "arm2" },
- { TARGET_CPU_arm6, "arm6" },
- { TARGET_CPU_arm610, "arm610" },
- { TARGET_CPU_arm710, "arm710" },
- { TARGET_CPU_arm7m, "arm7m" },
- { TARGET_CPU_arm7500fe, "arm7500fe" },
- { TARGET_CPU_arm7tdmi, "arm7tdmi" },
- { TARGET_CPU_arm8, "arm8" },
- { TARGET_CPU_arm810, "arm810" },
- { TARGET_CPU_arm9, "arm9" },
- { TARGET_CPU_strongarm, "strongarm" },
- { TARGET_CPU_xscale, "xscale" },
- { TARGET_CPU_ep9312, "ep9312" },
- { TARGET_CPU_iwmmxt, "iwmmxt" },
- { TARGET_CPU_arm926ej_s, "arm926ej-s" },
- { TARGET_CPU_arm1026ej_s, "arm1026ej-s" },
- { TARGET_CPU_arm1136j_s, "arm1136j_s" },
- { TARGET_CPU_arm1136jf_s, "arm1136jf_s" },
- { TARGET_CPU_generic, "arm" },
- { 0, 0 }
- };
- const struct cpu_default * def;
-
- /* Find the default. */
- for (def = cpu_defaults; def->name; def++)
- if (def->cpu == TARGET_CPU_DEFAULT)
- break;
+ enum processor_type cpu;
- /* Make sure we found the default CPU. */
- if (def->name == NULL)
- abort ();
-
- /* Find the default CPU's flags. */
- for (sel = all_cores; sel->name != NULL; sel++)
- if (streq (def->name, sel->name))
- break;
-
- if (sel->name == NULL)
- abort ();
+ cpu = TARGET_CPU_DEFAULT;
+ if (cpu == arm_none)
+ {
+#ifdef SUBTARGET_CPU_DEFAULT
+ /* Use the subtarget default CPU if none was specified by
+ configure. */
+ cpu = SUBTARGET_CPU_DEFAULT;
+#endif
+ /* Default to ARM6. */
+ if (cpu == arm_none)
+ cpu = arm6;
+ }
+ sel = &all_cores[cpu];
insn_flags = sel->flags;
-
+
/* Now check to see if the user has specified some command line
switch that require certain abilities from the cpu. */
sought = 0;
-
+
if (TARGET_INTERWORK || TARGET_THUMB)
{
sought |= (FL_THUMB | FL_MODE32);
-
- /* Force apcs-32 to be used for interworking. */
- target_flags |= ARM_FLAG_APCS_32;
/* There are no ARM processors that support both APCS-26 and
interworking. Therefore we force FL_MODE26 to be removed
@@ -602,9 +973,7 @@ arm_override_options (void)
below will always be able to find a compatible processor. */
insn_flags &= ~FL_MODE26;
}
- else if (!TARGET_APCS_32)
- sought |= FL_MODE26;
-
+
if (sought != 0 && ((sought & insn_flags) != sought))
{
/* Try to locate a CPU type that supports all of the abilities
@@ -618,7 +987,7 @@ arm_override_options (void)
{
unsigned current_bit_count = 0;
const struct processors * best_fit = NULL;
-
+
/* Ideally we would like to issue an error message here
saying that it was not possible to find a CPU compatible
with the default CPU, but which also supports the command
@@ -626,12 +995,10 @@ arm_override_options (void)
ought to use the -mcpu=<name> command line option to
override the default CPU type.
- Unfortunately this does not work with multilibing. We
- need to be able to support multilibs for -mapcs-26 and for
- -mthumb-interwork and there is no CPU that can support both
- options. Instead if we cannot find a cpu that has both the
- characteristics of the default cpu and the given command line
- options we scan the array again looking for a best match. */
+ If we cannot find a cpu that has both the
+ characteristics of the default cpu and the given
+ command line options we scan the array again looking
+ for a best match. */
for (sel = all_cores; sel->name != NULL; sel++)
if ((sel->flags & sought) == sought)
{
@@ -646,184 +1013,275 @@ arm_override_options (void)
}
}
- if (best_fit == NULL)
- abort ();
- else
- sel = best_fit;
+ gcc_assert (best_fit);
+ sel = best_fit;
}
insn_flags = sel->flags;
}
+ sprintf (arm_arch_name, "__ARM_ARCH_%s__", sel->arch);
+ if (arm_tune == arm_none)
+ arm_tune = (enum processor_type) (sel - all_cores);
}
-
- /* If tuning has not been specified, tune for whichever processor or
- architecture has been selected. */
- if (tune_flags == 0)
- tune_flags = insn_flags;
+
+ /* The processor for which we should tune should now have been
+ chosen. */
+ gcc_assert (arm_tune != arm_none);
+
+ tune_flags = all_cores[(int)arm_tune].flags;
+ if (optimize_size)
+ targetm.rtx_costs = arm_size_rtx_costs;
+ else
+ targetm.rtx_costs = all_cores[(int)arm_tune].rtx_costs;
/* Make sure that the processor choice does not conflict with any of the
other command line choices. */
- if (TARGET_APCS_32 && !(insn_flags & FL_MODE32))
- {
- /* If APCS-32 was not the default then it must have been set by the
- user, so issue a warning message. If the user has specified
- "-mapcs-32 -mcpu=arm2" then we loose here. */
- if ((TARGET_DEFAULT & ARM_FLAG_APCS_32) == 0)
- warning ("target CPU does not support APCS-32" );
- target_flags &= ~ARM_FLAG_APCS_32;
- }
- else if (!TARGET_APCS_32 && !(insn_flags & FL_MODE26))
- {
- warning ("target CPU does not support APCS-26" );
- target_flags |= ARM_FLAG_APCS_32;
- }
-
if (TARGET_INTERWORK && !(insn_flags & FL_THUMB))
{
- warning ("target CPU does not support interworking" );
- target_flags &= ~ARM_FLAG_INTERWORK;
+ warning (0, "target CPU does not support interworking" );
+ target_flags &= ~MASK_INTERWORK;
}
-
+
if (TARGET_THUMB && !(insn_flags & FL_THUMB))
{
- warning ("target CPU does not support THUMB instructions");
- target_flags &= ~ARM_FLAG_THUMB;
+ warning (0, "target CPU does not support THUMB instructions");
+ target_flags &= ~MASK_THUMB;
}
- if (!TARGET_APCS_32)
- inform ("future releases of GCC will not support -mapcs-26");
-
if (TARGET_APCS_FRAME && TARGET_THUMB)
{
- /* warning ("ignoring -mapcs-frame because -mthumb was used"); */
- target_flags &= ~ARM_FLAG_APCS_FRAME;
+ /* warning (0, "ignoring -mapcs-frame because -mthumb was used"); */
+ target_flags &= ~MASK_APCS_FRAME;
}
+ /* Callee super interworking implies thumb interworking. Adding
+ this to the flags here simplifies the logic elsewhere. */
+ if (TARGET_THUMB && TARGET_CALLEE_INTERWORKING)
+ target_flags |= MASK_INTERWORK;
+
/* TARGET_BACKTRACE calls leaf_function_p, which causes a crash if done
from here where no function is being compiled currently. */
- if ((target_flags & (THUMB_FLAG_LEAF_BACKTRACE | THUMB_FLAG_BACKTRACE))
- && TARGET_ARM)
- warning ("enabling backtrace support is only meaningful when compiling for the Thumb");
+ if ((TARGET_TPCS_FRAME || TARGET_TPCS_LEAF_FRAME) && TARGET_ARM)
+ warning (0, "enabling backtrace support is only meaningful when compiling for the Thumb");
if (TARGET_ARM && TARGET_CALLEE_INTERWORKING)
- warning ("enabling callee interworking support is only meaningful when compiling for the Thumb");
+ warning (0, "enabling callee interworking support is only meaningful when compiling for the Thumb");
if (TARGET_ARM && TARGET_CALLER_INTERWORKING)
- warning ("enabling caller interworking support is only meaningful when compiling for the Thumb");
+ warning (0, "enabling caller interworking support is only meaningful when compiling for the Thumb");
- /* If interworking is enabled then APCS-32 must be selected as well. */
- if (TARGET_INTERWORK)
- {
- if (!TARGET_APCS_32)
- warning ("interworking forces APCS-32 to be used" );
- target_flags |= ARM_FLAG_APCS_32;
- }
-
if (TARGET_APCS_STACK && !TARGET_APCS_FRAME)
{
- warning ("-mapcs-stack-check incompatible with -mno-apcs-frame");
- target_flags |= ARM_FLAG_APCS_FRAME;
+ warning (0, "-mapcs-stack-check incompatible with -mno-apcs-frame");
+ target_flags |= MASK_APCS_FRAME;
}
-
+
if (TARGET_POKE_FUNCTION_NAME)
- target_flags |= ARM_FLAG_APCS_FRAME;
-
+ target_flags |= MASK_APCS_FRAME;
+
if (TARGET_APCS_REENT && flag_pic)
error ("-fpic and -mapcs-reent are incompatible");
-
+
if (TARGET_APCS_REENT)
- warning ("APCS reentrant code not supported. Ignored");
-
+ warning (0, "APCS reentrant code not supported. Ignored");
+
/* If this target is normally configured to use APCS frames, warn if they
are turned off and debugging is turned on. */
if (TARGET_ARM
&& write_symbols != NO_DEBUG
&& !TARGET_APCS_FRAME
- && (TARGET_DEFAULT & ARM_FLAG_APCS_FRAME))
- warning ("-g with -mno-apcs-frame may not give sensible debugging");
-
+ && (TARGET_DEFAULT & MASK_APCS_FRAME))
+ warning (0, "-g with -mno-apcs-frame may not give sensible debugging");
+
/* If stack checking is disabled, we can use r10 as the PIC register,
which keeps r9 available. */
- if (flag_pic)
+ if (flag_pic && TARGET_SINGLE_PIC_BASE)
arm_pic_register = TARGET_APCS_STACK ? 9 : 10;
-
+
if (TARGET_APCS_FLOAT)
- warning ("passing floating point arguments in fp regs not yet supported");
-
- /* Initialize boolean versions of the flags, for use in the arm.md file. */
- arm_fast_multiply = (insn_flags & FL_FAST_MULT) != 0;
- arm_arch4 = (insn_flags & FL_ARCH4) != 0;
- arm_arch5 = (insn_flags & FL_ARCH5) != 0;
- arm_arch5e = (insn_flags & FL_ARCH5E) != 0;
- arm_arch_xscale = (insn_flags & FL_XSCALE) != 0;
+ warning (0, "passing floating point arguments in fp regs not yet supported");
- arm_ld_sched = (tune_flags & FL_LDSCHED) != 0;
- arm_is_strong = (tune_flags & FL_STRONG) != 0;
- thumb_code = (TARGET_ARM == 0);
- arm_is_6_or_7 = (((tune_flags & (FL_MODE26 | FL_MODE32))
- && !(tune_flags & FL_ARCH4))) != 0;
- arm_tune_xscale = (tune_flags & FL_XSCALE) != 0;
- arm_is_cirrus = (tune_flags & FL_CIRRUS) != 0;
- arm_arch_iwmmxt = (insn_flags & FL_IWMMXT) != 0;
+ /* Initialize boolean versions of the flags, for use in the arm.md file. */
+ arm_arch3m = (insn_flags & FL_ARCH3M) != 0;
+ arm_arch4 = (insn_flags & FL_ARCH4) != 0;
+ arm_arch4t = arm_arch4 & ((insn_flags & FL_THUMB) != 0);
+ arm_arch5 = (insn_flags & FL_ARCH5) != 0;
+ arm_arch5e = (insn_flags & FL_ARCH5E) != 0;
+ arm_arch6 = (insn_flags & FL_ARCH6) != 0;
+ arm_arch6k = (insn_flags & FL_ARCH6K) != 0;
+ arm_arch_xscale = (insn_flags & FL_XSCALE) != 0;
+ arm_arch_cirrus = (insn_flags & FL_CIRRUS) != 0;
+
+ arm_ld_sched = (tune_flags & FL_LDSCHED) != 0;
+ arm_tune_strongarm = (tune_flags & FL_STRONG) != 0;
+ thumb_code = (TARGET_ARM == 0);
+ arm_tune_wbuf = (tune_flags & FL_WBUF) != 0;
+ arm_tune_xscale = (tune_flags & FL_XSCALE) != 0;
+ arm_arch_iwmmxt = (insn_flags & FL_IWMMXT) != 0;
+
+ /* V5 code we generate is completely interworking capable, so we turn off
+ TARGET_INTERWORK here to avoid many tests later on. */
+
+ /* XXX However, we must pass the right pre-processor defines to CPP
+ or GLD can get confused. This is a hack. */
+ if (TARGET_INTERWORK)
+ arm_cpp_interwork = 1;
- if (TARGET_IWMMXT && (! TARGET_ATPCS))
- target_flags |= ARM_FLAG_ATPCS;
+ if (arm_arch5)
+ target_flags &= ~MASK_INTERWORK;
- if (arm_is_cirrus)
+ if (target_abi_name)
{
- arm_fpu_tune = FPUTYPE_MAVERICK;
+ for (i = 0; i < ARRAY_SIZE (arm_all_abis); i++)
+ {
+ if (streq (arm_all_abis[i].name, target_abi_name))
+ {
+ arm_abi = arm_all_abis[i].abi_type;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE (arm_all_abis))
+ error ("invalid ABI option: -mabi=%s", target_abi_name);
+ }
+ else
+ arm_abi = ARM_DEFAULT_ABI;
+
+ if (TARGET_IWMMXT && !ARM_DOUBLEWORD_ALIGN)
+ error ("iwmmxt requires an AAPCS compatible ABI for proper operation");
- /* Ignore -mhard-float if -mcpu=ep9312. */
- if (TARGET_HARD_FLOAT)
- target_flags ^= ARM_FLAG_SOFT_FLOAT;
+ if (TARGET_IWMMXT_ABI && !TARGET_IWMMXT)
+ error ("iwmmxt abi requires an iwmmxt capable cpu");
+
+ arm_fp_model = ARM_FP_MODEL_UNKNOWN;
+ if (target_fpu_name == NULL && target_fpe_name != NULL)
+ {
+ if (streq (target_fpe_name, "2"))
+ target_fpu_name = "fpe2";
+ else if (streq (target_fpe_name, "3"))
+ target_fpu_name = "fpe3";
+ else
+ error ("invalid floating point emulation option: -mfpe=%s",
+ target_fpe_name);
+ }
+ if (target_fpu_name != NULL)
+ {
+ /* The user specified a FPU. */
+ for (i = 0; i < ARRAY_SIZE (all_fpus); i++)
+ {
+ if (streq (all_fpus[i].name, target_fpu_name))
+ {
+ arm_fpu_arch = all_fpus[i].fpu;
+ arm_fpu_tune = arm_fpu_arch;
+ arm_fp_model = fp_model_for_fpu[arm_fpu_arch];
+ break;
+ }
+ }
+ if (arm_fp_model == ARM_FP_MODEL_UNKNOWN)
+ error ("invalid floating point option: -mfpu=%s", target_fpu_name);
}
else
- /* Default value for floating point code... if no co-processor
- bus, then schedule for emulated floating point. Otherwise,
- assume the user has an FPA.
- Note: this does not prevent use of floating point instructions,
- -msoft-float does that. */
- arm_fpu_tune = (tune_flags & FL_CO_PROC) ? FPUTYPE_FPA : FPUTYPE_FPA_EMU3;
-
- if (target_fp_name)
{
- if (streq (target_fp_name, "2"))
+#ifdef FPUTYPE_DEFAULT
+ /* Use the default if it is specified for this platform. */
+ arm_fpu_arch = FPUTYPE_DEFAULT;
+ arm_fpu_tune = FPUTYPE_DEFAULT;
+#else
+ /* Pick one based on CPU type. */
+ /* ??? Some targets assume FPA is the default.
+ if ((insn_flags & FL_VFP) != 0)
+ arm_fpu_arch = FPUTYPE_VFP;
+ else
+ */
+ if (arm_arch_cirrus)
+ arm_fpu_arch = FPUTYPE_MAVERICK;
+ else
arm_fpu_arch = FPUTYPE_FPA_EMU2;
- else if (streq (target_fp_name, "3"))
- arm_fpu_arch = FPUTYPE_FPA_EMU3;
+#endif
+ if (tune_flags & FL_CO_PROC && arm_fpu_arch == FPUTYPE_FPA_EMU2)
+ arm_fpu_tune = FPUTYPE_FPA;
else
- error ("invalid floating point emulation option: -mfpe-%s",
- target_fp_name);
+ arm_fpu_tune = arm_fpu_arch;
+ arm_fp_model = fp_model_for_fpu[arm_fpu_arch];
+ gcc_assert (arm_fp_model != ARM_FP_MODEL_UNKNOWN);
}
- else
- arm_fpu_arch = FPUTYPE_DEFAULT;
-
- if (TARGET_FPE)
+
+ if (target_float_abi_name != NULL)
{
- if (arm_fpu_tune == FPUTYPE_FPA_EMU3)
- arm_fpu_tune = FPUTYPE_FPA_EMU2;
- else if (arm_fpu_tune == FPUTYPE_MAVERICK)
- warning ("-mfpe switch not supported by ep9312 target cpu - ignored.");
- else if (arm_fpu_tune != FPUTYPE_FPA)
- arm_fpu_tune = FPUTYPE_FPA_EMU2;
+ /* The user specified a FP ABI. */
+ for (i = 0; i < ARRAY_SIZE (all_float_abis); i++)
+ {
+ if (streq (all_float_abis[i].name, target_float_abi_name))
+ {
+ arm_float_abi = all_float_abis[i].abi_type;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE (all_float_abis))
+ error ("invalid floating point abi: -mfloat-abi=%s",
+ target_float_abi_name);
}
-
+ else
+ arm_float_abi = TARGET_DEFAULT_FLOAT_ABI;
+
+ if (arm_float_abi == ARM_FLOAT_ABI_HARD && TARGET_VFP)
+ sorry ("-mfloat-abi=hard and VFP");
+
+ /* FPA and iWMMXt are incompatible because the insn encodings overlap.
+ VFP and iWMMXt can theoretically coexist, but it's unlikely such silicon
+ will ever exist. GCC makes no attempt to support this combination. */
+ if (TARGET_IWMMXT && !TARGET_SOFT_FLOAT)
+ sorry ("iWMMXt and hardware floating point");
+
+ /* If soft-float is specified then don't use FPU. */
+ if (TARGET_SOFT_FLOAT)
+ arm_fpu_arch = FPUTYPE_NONE;
+
/* For arm2/3 there is no need to do any scheduling if there is only
a floating point emulator, or we are doing software floating-point. */
- if ((TARGET_SOFT_FLOAT || arm_fpu_tune != FPUTYPE_FPA)
+ if ((TARGET_SOFT_FLOAT
+ || arm_fpu_tune == FPUTYPE_FPA_EMU2
+ || arm_fpu_tune == FPUTYPE_FPA_EMU3)
&& (tune_flags & FL_MODE32) == 0)
flag_schedule_insns = flag_schedule_insns_after_reload = 0;
-
- arm_prgmode = TARGET_APCS_32 ? PROG_MODE_PROG32 : PROG_MODE_PROG26;
-
+
+ if (target_thread_switch)
+ {
+ if (strcmp (target_thread_switch, "soft") == 0)
+ target_thread_pointer = TP_SOFT;
+ else if (strcmp (target_thread_switch, "auto") == 0)
+ target_thread_pointer = TP_AUTO;
+ else if (strcmp (target_thread_switch, "cp15") == 0)
+ target_thread_pointer = TP_CP15;
+ else
+ error ("invalid thread pointer option: -mtp=%s", target_thread_switch);
+ }
+
+ /* Use the cp15 method if it is available. */
+ if (target_thread_pointer == TP_AUTO)
+ {
+ if (arm_arch6k && !TARGET_THUMB)
+ target_thread_pointer = TP_CP15;
+ else
+ target_thread_pointer = TP_SOFT;
+ }
+
+ if (TARGET_HARD_TP && TARGET_THUMB)
+ error ("can not use -mtp=cp15 with -mthumb");
+
+ /* Override the default structure alignment for AAPCS ABI. */
+ if (TARGET_AAPCS_BASED)
+ arm_structure_size_boundary = 8;
+
if (structure_size_string != NULL)
{
int size = strtol (structure_size_string, NULL, 0);
-
- if (size == 8 || size == 32)
+
+ if (size == 8 || size == 32
+ || (ARM_DOUBLEWORD_ALIGN && size == 64))
arm_structure_size_boundary = size;
else
- warning ("structure size boundary can only be set to 8 or 32");
+ warning (0, "structure size boundary can only be set to %s",
+ ARM_DOUBLEWORD_ALIGN ? "8, 32 or 64": "8 or 32");
}
if (arm_pic_register_string != NULL)
@@ -831,7 +1289,7 @@ arm_override_options (void)
int pic_register = decode_reg_name (arm_pic_register_string);
if (!flag_pic)
- warning ("-mpic-register= is useless without -fpic");
+ warning (0, "-mpic-register= is useless without -fpic");
/* Prevent the user from choosing an obviously stupid PIC register. */
else if (pic_register < 0 || call_used_regs[pic_register]
@@ -851,10 +1309,6 @@ arm_override_options (void)
if (optimize_size)
{
- /* There's some dispute as to whether this should be 1 or 2. However,
- experiments seem to show that in pathological cases a setting of
- 1 degrades less severely than a setting of 2. This could change if
- other parts of the compiler change their behavior. */
arm_constant_limit = 1;
/* If optimizing for size, bump the number of instructions that we
@@ -866,7 +1320,7 @@ arm_override_options (void)
/* For processors with load scheduling, it never costs more than
2 cycles to load a constant, and the load scheduler may well
reduce that to 1. */
- if (tune_flags & FL_LDSCHED)
+ if (arm_ld_sched)
arm_constant_limit = 1;
/* On XScale the longer latency of a load makes it more difficult
@@ -877,7 +1331,7 @@ arm_override_options (void)
/* StrongARM has early execution of branches, so a sequence
that is worth skipping is shorter. */
- if (arm_is_strong)
+ if (arm_tune_strongarm)
max_insns_skipped = 3;
}
@@ -956,42 +1410,38 @@ arm_compute_func_type (void)
unsigned long type = ARM_FT_UNKNOWN;
tree a;
tree attr;
-
- if (TREE_CODE (current_function_decl) != FUNCTION_DECL)
- abort ();
+
+ gcc_assert (TREE_CODE (current_function_decl) == FUNCTION_DECL);
/* Decide if the current function is volatile. Such functions
never return, and many memory cycles can be saved by not storing
register values that will never be needed again. This optimization
was added to speed up context switching in a kernel application. */
if (optimize > 0
- && current_function_nothrow
+ && (TREE_NOTHROW (current_function_decl)
+ || !(flag_unwind_tables
+ || (flag_exceptions && !USING_SJLJ_EXCEPTIONS)))
&& TREE_THIS_VOLATILE (current_function_decl))
type |= ARM_FT_VOLATILE;
-
- if (current_function_needs_context)
+
+ if (cfun->static_chain_decl != NULL)
type |= ARM_FT_NESTED;
attr = DECL_ATTRIBUTES (current_function_decl);
-
+
a = lookup_attribute ("naked", attr);
if (a != NULL_TREE)
type |= ARM_FT_NAKED;
- if (cfun->machine->eh_epilogue_sp_ofs != NULL_RTX)
- type |= ARM_FT_EXCEPTION_HANDLER;
+ a = lookup_attribute ("isr", attr);
+ if (a == NULL_TREE)
+ a = lookup_attribute ("interrupt", attr);
+
+ if (a == NULL_TREE)
+ type |= TARGET_INTERWORK ? ARM_FT_INTERWORKED : ARM_FT_NORMAL;
else
- {
- a = lookup_attribute ("isr", attr);
- if (a == NULL_TREE)
- a = lookup_attribute ("interrupt", attr);
-
- if (a == NULL_TREE)
- type |= TARGET_INTERWORK ? ARM_FT_INTERWORKED : ARM_FT_NORMAL;
- else
- type |= arm_isr_value (TREE_VALUE (a));
- }
-
+ type |= arm_isr_value (TREE_VALUE (a));
+
return type;
}
@@ -1006,7 +1456,7 @@ arm_current_func_type (void)
return cfun->machine->func_type;
}
-/* Return 1 if it is possible to return using a single instruction.
+/* Return 1 if it is possible to return using a single instruction.
If SIBLING is non-null, this is a test for a return before a sibling
call. SIBLING is the call insn, so we can examine its register usage. */
@@ -1017,6 +1467,7 @@ use_return_insn (int iscond, rtx sibling)
unsigned int func_type;
unsigned long saved_int_regs;
unsigned HOST_WIDE_INT stack_adjust;
+ arm_stack_offsets *offsets;
/* Never use a return instruction before reload has run. */
if (!reload_completed)
@@ -1033,13 +1484,14 @@ use_return_insn (int iscond, rtx sibling)
if (IS_INTERRUPT (func_type) && frame_pointer_needed)
return 0;
- stack_adjust = arm_get_frame_size () + current_function_outgoing_args_size;
+ offsets = arm_get_frame_offsets ();
+ stack_adjust = offsets->outgoing_args - offsets->saved_regs;
/* As do variadic functions. */
if (current_function_pretend_args_size
|| cfun->machine->uses_anonymous_args
/* Or if the function calls __builtin_eh_return () */
- || ARM_FUNC_TYPE (func_type) == ARM_FT_EXCEPTION_HANDLER
+ || current_function_calls_eh_return
/* Or if the function calls alloca */
|| current_function_calls_alloca
/* Or if there is a stack adjustment. However, if the stack pointer
@@ -1057,7 +1509,7 @@ use_return_insn (int iscond, rtx sibling)
pointer won't be correctly restored if the instruction takes a
page fault. We work around this problem by popping r3 along with
the other registers, since that is never slower than executing
- another instruction.
+ another instruction.
We test for !arm_arch5 here, because code for any architecture
less than this could potentially be run on one of the buggy
@@ -1069,13 +1521,14 @@ use_return_insn (int iscond, rtx sibling)
if (!call_used_regs[3])
return 0;
- /* ... that it isn't being used for a return value (always true
- until we implement return-in-regs), or for a tail-call
- argument ... */
+ /* ... that it isn't being used for a return value ... */
+ if (arm_size_return_regs () >= (4 * UNITS_PER_WORD))
+ return 0;
+
+ /* ... or for a tail-call argument ... */
if (sibling)
{
- if (GET_CODE (sibling) != CALL_INSN)
- abort ();
+ gcc_assert (GET_CODE (sibling) == CALL_INSN);
if (find_regno_fusage (sibling, USE, 3))
return 0;
@@ -1094,14 +1547,16 @@ use_return_insn (int iscond, rtx sibling)
/* On StrongARM, conditional returns are expensive if they aren't
taken and multiple registers have been stacked. */
- if (iscond && arm_is_strong)
+ if (iscond && arm_tune_strongarm)
{
- /* Conditional return when just the LR is stored is a simple
+ /* Conditional return when just the LR is stored is a simple
conditional-load instruction, that's not expensive. */
if (saved_int_regs != 0 && saved_int_regs != (1 << LR_REGNUM))
return 0;
- if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
+ if (flag_pic
+ && arm_pic_register != INVALID_REGNUM
+ && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
return 0;
}
@@ -1112,8 +1567,14 @@ use_return_insn (int iscond, rtx sibling)
/* Can't be done if any of the FPA regs are pushed,
since this also requires an insn. */
- if (TARGET_HARD_FLOAT)
- for (regno = FIRST_ARM_FP_REGNUM; regno <= LAST_ARM_FP_REGNUM; regno++)
+ if (TARGET_HARD_FLOAT && TARGET_FPA)
+ for (regno = FIRST_FPA_REGNUM; regno <= LAST_FPA_REGNUM; regno++)
+ if (regs_ever_live[regno] && !call_used_regs[regno])
+ return 0;
+
+ /* Likewise VFP regs. */
+ if (TARGET_HARD_FLOAT && TARGET_VFP)
+ for (regno = FIRST_VFP_REGNUM; regno <= LAST_VFP_REGNUM; regno++)
if (regs_ever_live[regno] && !call_used_regs[regno])
return 0;
@@ -1130,29 +1591,34 @@ use_return_insn (int iscond, rtx sibling)
int
const_ok_for_arm (HOST_WIDE_INT i)
{
- unsigned HOST_WIDE_INT mask = ~(unsigned HOST_WIDE_INT)0xFF;
+ int lowbit;
- /* For machines with >32 bit HOST_WIDE_INT, the bits above bit 31 must
+ /* For machines with >32 bit HOST_WIDE_INT, the bits above bit 31 must
be all zero, or all one. */
if ((i & ~(unsigned HOST_WIDE_INT) 0xffffffff) != 0
&& ((i & ~(unsigned HOST_WIDE_INT) 0xffffffff)
!= ((~(unsigned HOST_WIDE_INT) 0)
& ~(unsigned HOST_WIDE_INT) 0xffffffff)))
return FALSE;
-
- /* Fast return for 0 and powers of 2 */
- if ((i & (i - 1)) == 0)
+
+ i &= (unsigned HOST_WIDE_INT) 0xffffffff;
+
+ /* Fast return for 0 and small values. We must do this for zero, since
+ the code below can't handle that one case. */
+ if ((i & ~(unsigned HOST_WIDE_INT) 0xff) == 0)
return TRUE;
- do
- {
- if ((i & mask & (unsigned HOST_WIDE_INT) 0xffffffff) == 0)
- return TRUE;
- mask =
- (mask << 2) | ((mask & (unsigned HOST_WIDE_INT) 0xffffffff)
- >> (32 - 2)) | ~(unsigned HOST_WIDE_INT) 0xffffffff;
- }
- while (mask != ~(unsigned HOST_WIDE_INT) 0xFF);
+ /* Get the number of trailing zeros, rounded down to the nearest even
+ number. */
+ lowbit = (ffs ((int) i) - 1) & ~1;
+
+ if ((i & ~(((unsigned HOST_WIDE_INT) 0xff) << lowbit)) == 0)
+ return TRUE;
+ else if (lowbit <= 4
+ && ((i & ~0xc000003f) == 0
+ || (i & ~0xf000000f) == 0
+ || (i & ~0xfc000003) == 0))
+ return TRUE;
return FALSE;
}
@@ -1178,7 +1644,7 @@ const_ok_for_op (HOST_WIDE_INT i, enum rtx_code code)
return const_ok_for_arm (ARM_SIGN_EXTEND (~i));
default:
- abort ();
+ gcc_unreachable ();
}
}
@@ -1193,9 +1659,16 @@ const_ok_for_op (HOST_WIDE_INT i, enum rtx_code code)
Return value is the number of insns emitted. */
int
-arm_split_constant (enum rtx_code code, enum machine_mode mode,
+arm_split_constant (enum rtx_code code, enum machine_mode mode, rtx insn,
HOST_WIDE_INT val, rtx target, rtx source, int subtargets)
{
+ rtx cond;
+
+ if (insn && GET_CODE (PATTERN (insn)) == COND_EXEC)
+ cond = COND_EXEC_TEST (PATTERN (insn));
+ else
+ cond = NULL_RTX;
+
if (subtargets || code == SET
|| (GET_CODE (target) == REG && GET_CODE (source) == REG
&& REGNO (target) != REGNO (source)))
@@ -1210,35 +1683,37 @@ arm_split_constant (enum rtx_code code, enum machine_mode mode,
Ref: gcc -O1 -mcpu=strongarm gcc.c-torture/compile/980506-2.c
*/
if (!after_arm_reorg
- && (arm_gen_constant (code, mode, val, target, source, 1, 0)
+ && !cond
+ && (arm_gen_constant (code, mode, NULL_RTX, val, target, source,
+ 1, 0)
> arm_constant_limit + (code != SET)))
{
if (code == SET)
{
/* Currently SET is the only monadic value for CODE, all
the rest are diadic. */
- emit_insn (gen_rtx_SET (VOIDmode, target, GEN_INT (val)));
+ emit_set_insn (target, GEN_INT (val));
return 1;
}
else
{
rtx temp = subtargets ? gen_reg_rtx (mode) : target;
- emit_insn (gen_rtx_SET (VOIDmode, temp, GEN_INT (val)));
+ emit_set_insn (temp, GEN_INT (val));
/* For MINUS, the value is subtracted from, since we never
have subtraction of a constant. */
if (code == MINUS)
- emit_insn (gen_rtx_SET (VOIDmode, target,
- gen_rtx_MINUS (mode, temp, source)));
+ emit_set_insn (target, gen_rtx_MINUS (mode, temp, source));
else
- emit_insn (gen_rtx_SET (VOIDmode, target,
- gen_rtx (code, mode, source, temp)));
+ emit_set_insn (target,
+ gen_rtx_fmt_ee (code, mode, source, temp));
return 2;
}
}
}
- return arm_gen_constant (code, mode, val, target, source, subtargets, 1);
+ return arm_gen_constant (code, mode, cond, val, target, source, subtargets,
+ 1);
}
static int
@@ -1249,7 +1724,7 @@ count_insns_for_constant (HOST_WIDE_INT remainder, int i)
do
{
int end;
-
+
if (i <= 0)
i += 32;
if (remainder & (3 << (i - 2)))
@@ -1268,11 +1743,23 @@ count_insns_for_constant (HOST_WIDE_INT remainder, int i)
return num_insns;
}
+/* Emit an instruction with the indicated PATTERN. If COND is
+ non-NULL, conditionalize the execution of the instruction on COND
+ being true. */
+
+static void
+emit_constant_insn (rtx cond, rtx pattern)
+{
+ if (cond)
+ pattern = gen_rtx_COND_EXEC (VOIDmode, copy_rtx (cond), pattern);
+ emit_insn (pattern);
+}
+
/* As above, but extra parameter GENERATE which, if clear, suppresses
RTL generation. */
static int
-arm_gen_constant (enum rtx_code code, enum machine_mode mode,
+arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond,
HOST_WIDE_INT val, rtx target, rtx source, int subtargets,
int generate)
{
@@ -1310,8 +1797,9 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode,
if (remainder == 0xffffffff)
{
if (generate)
- emit_insn (gen_rtx_SET (VOIDmode, target,
- GEN_INT (ARM_SIGN_EXTEND (val))));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, target,
+ GEN_INT (ARM_SIGN_EXTEND (val))));
return 1;
}
if (remainder == 0)
@@ -1319,7 +1807,8 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode,
if (reload_completed && rtx_equal_p (target, source))
return 0;
if (generate)
- emit_insn (gen_rtx_SET (VOIDmode, target, source));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, target, source));
return 1;
}
break;
@@ -1328,7 +1817,8 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode,
if (remainder == 0)
{
if (generate)
- emit_insn (gen_rtx_SET (VOIDmode, target, const0_rtx));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, target, const0_rtx));
return 1;
}
if (remainder == 0xffffffff)
@@ -1336,7 +1826,8 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode,
if (reload_completed && rtx_equal_p (target, source))
return 0;
if (generate)
- emit_insn (gen_rtx_SET (VOIDmode, target, source));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, target, source));
return 1;
}
can_invert = 1;
@@ -1348,19 +1839,19 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode,
if (reload_completed && rtx_equal_p (target, source))
return 0;
if (generate)
- emit_insn (gen_rtx_SET (VOIDmode, target, source));
- return 1;
- }
- if (remainder == 0xffffffff)
- {
- if (generate)
- emit_insn (gen_rtx_SET (VOIDmode, target,
- gen_rtx_NOT (mode, source)));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, target, source));
return 1;
}
- /* We don't know how to handle this yet below. */
- abort ();
+ /* We don't know how to handle other cases yet. */
+ gcc_assert (remainder == 0xffffffff);
+
+ if (generate)
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, target,
+ gen_rtx_NOT (mode, source)));
+ return 1;
case MINUS:
/* We treat MINUS as (val - source), since (source - val) is always
@@ -1368,16 +1859,18 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode,
if (remainder == 0)
{
if (generate)
- emit_insn (gen_rtx_SET (VOIDmode, target,
- gen_rtx_NEG (mode, source)));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, target,
+ gen_rtx_NEG (mode, source)));
return 1;
}
if (const_ok_for_arm (val))
{
if (generate)
- emit_insn (gen_rtx_SET (VOIDmode, target,
- gen_rtx_MINUS (mode, GEN_INT (val),
- source)));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, target,
+ gen_rtx_MINUS (mode, GEN_INT (val),
+ source)));
return 1;
}
can_negate = 1;
@@ -1385,7 +1878,7 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode,
break;
default:
- abort ();
+ gcc_unreachable ();
}
/* If we can do it in one insn get out quickly. */
@@ -1394,10 +1887,12 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode,
|| (can_invert && const_ok_for_arm (~val)))
{
if (generate)
- emit_insn (gen_rtx_SET (VOIDmode, target,
- (source ? gen_rtx (code, mode, source,
- GEN_INT (val))
- : GEN_INT (val))));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, target,
+ (source
+ ? gen_rtx_fmt_ee (code, mode, source,
+ GEN_INT (val))
+ : GEN_INT (val))));
return 1;
}
@@ -1444,16 +1939,18 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode,
if (set_sign_bit_copies > 1)
{
if (const_ok_for_arm
- (temp1 = ARM_SIGN_EXTEND (remainder
+ (temp1 = ARM_SIGN_EXTEND (remainder
<< (set_sign_bit_copies - 1))))
{
if (generate)
{
rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
- emit_insn (gen_rtx_SET (VOIDmode, new_src,
- GEN_INT (temp1)));
- emit_insn (gen_ashrsi3 (target, new_src,
- GEN_INT (set_sign_bit_copies - 1)));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, new_src,
+ GEN_INT (temp1)));
+ emit_constant_insn (cond,
+ gen_ashrsi3 (target, new_src,
+ GEN_INT (set_sign_bit_copies - 1)));
}
return 2;
}
@@ -1465,11 +1962,48 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode,
if (generate)
{
rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
- emit_insn (gen_rtx_SET (VOIDmode, new_src,
- GEN_INT (temp1)));
- emit_insn (gen_ashrsi3 (target, new_src,
- GEN_INT (set_sign_bit_copies - 1)));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, new_src,
+ GEN_INT (temp1)));
+ emit_constant_insn (cond,
+ gen_ashrsi3 (target, new_src,
+ GEN_INT (set_sign_bit_copies - 1)));
+ }
+ return 2;
+ }
+ }
+
+ /* See if we can calculate the value as the difference between two
+ valid immediates. */
+ if (clear_sign_bit_copies + clear_zero_bit_copies <= 16)
+ {
+ int topshift = clear_sign_bit_copies & ~1;
+
+ temp1 = ARM_SIGN_EXTEND ((remainder + (0x00800000 >> topshift))
+ & (0xff000000 >> topshift));
+
+ /* If temp1 is zero, then that means the 9 most significant
+ bits of remainder were 1 and we've caused it to overflow.
+ When topshift is 0 we don't need to do anything since we
+ can borrow from 'bit 32'. */
+ if (temp1 == 0 && topshift != 0)
+ temp1 = 0x80000000 >> (topshift - 1);
+
+ temp2 = ARM_SIGN_EXTEND (temp1 - remainder);
+
+ if (const_ok_for_arm (temp2))
+ {
+ if (generate)
+ {
+ rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, new_src,
+ GEN_INT (temp1)));
+ emit_constant_insn (cond,
+ gen_addsi3 (target, new_src,
+ GEN_INT (-temp2)));
}
+
return 2;
}
}
@@ -1493,16 +2027,18 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode,
rtx new_src = (subtargets
? (generate ? gen_reg_rtx (mode) : NULL_RTX)
: target);
- insns = arm_gen_constant (code, mode, temp2, new_src,
+ insns = arm_gen_constant (code, mode, cond, temp2, new_src,
source, subtargets, generate);
source = new_src;
if (generate)
- emit_insn (gen_rtx_SET
- (VOIDmode, target,
- gen_rtx_IOR (mode,
- gen_rtx_ASHIFT (mode, source,
- GEN_INT (i)),
- source)));
+ emit_constant_insn
+ (cond,
+ gen_rtx_SET
+ (VOIDmode, target,
+ gen_rtx_IOR (mode,
+ gen_rtx_ASHIFT (mode, source,
+ GEN_INT (i)),
+ source)));
return insns + 1;
}
}
@@ -1516,12 +2052,13 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode,
rtx new_src = (subtargets
? (generate ? gen_reg_rtx (mode) : NULL_RTX)
: target);
- insns = arm_gen_constant (code, mode, temp1, new_src,
+ insns = arm_gen_constant (code, mode, cond, temp1, new_src,
source, subtargets, generate);
source = new_src;
if (generate)
- emit_insn
- (gen_rtx_SET (VOIDmode, target,
+ emit_constant_insn
+ (cond,
+ gen_rtx_SET (VOIDmode, target,
gen_rtx_IOR
(mode,
gen_rtx_LSHIFTRT (mode, source,
@@ -1548,9 +2085,13 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode,
{
rtx sub = subtargets ? gen_reg_rtx (mode) : target;
- emit_insn (gen_rtx_SET (VOIDmode, sub, GEN_INT (val)));
- emit_insn (gen_rtx_SET (VOIDmode, target,
- gen_rtx (code, mode, source, sub)));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, sub,
+ GEN_INT (val)));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, target,
+ gen_rtx_fmt_ee (code, mode,
+ source, sub)));
}
return 2;
}
@@ -1567,15 +2108,19 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode,
rtx sub = subtargets ? gen_reg_rtx (mode) : target;
rtx shift = GEN_INT (set_sign_bit_copies);
- emit_insn (gen_rtx_SET (VOIDmode, sub,
- gen_rtx_NOT (mode,
- gen_rtx_ASHIFT (mode,
- source,
- shift))));
- emit_insn (gen_rtx_SET (VOIDmode, target,
- gen_rtx_NOT (mode,
- gen_rtx_LSHIFTRT (mode, sub,
- shift))));
+ emit_constant_insn
+ (cond,
+ gen_rtx_SET (VOIDmode, sub,
+ gen_rtx_NOT (mode,
+ gen_rtx_ASHIFT (mode,
+ source,
+ shift))));
+ emit_constant_insn
+ (cond,
+ gen_rtx_SET (VOIDmode, target,
+ gen_rtx_NOT (mode,
+ gen_rtx_LSHIFTRT (mode, sub,
+ shift))));
}
return 2;
}
@@ -1588,15 +2133,19 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode,
rtx sub = subtargets ? gen_reg_rtx (mode) : target;
rtx shift = GEN_INT (set_zero_bit_copies);
- emit_insn (gen_rtx_SET (VOIDmode, sub,
- gen_rtx_NOT (mode,
- gen_rtx_LSHIFTRT (mode,
- source,
- shift))));
- emit_insn (gen_rtx_SET (VOIDmode, target,
- gen_rtx_NOT (mode,
- gen_rtx_ASHIFT (mode, sub,
- shift))));
+ emit_constant_insn
+ (cond,
+ gen_rtx_SET (VOIDmode, sub,
+ gen_rtx_NOT (mode,
+ gen_rtx_LSHIFTRT (mode,
+ source,
+ shift))));
+ emit_constant_insn
+ (cond,
+ gen_rtx_SET (VOIDmode, target,
+ gen_rtx_NOT (mode,
+ gen_rtx_ASHIFT (mode, sub,
+ shift))));
}
return 2;
}
@@ -1606,16 +2155,19 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode,
if (generate)
{
rtx sub = subtargets ? gen_reg_rtx (mode) : target;
- emit_insn (gen_rtx_SET (VOIDmode, sub,
- gen_rtx_NOT (mode, source)));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, sub,
+ gen_rtx_NOT (mode, source)));
source = sub;
if (subtargets)
sub = gen_reg_rtx (mode);
- emit_insn (gen_rtx_SET (VOIDmode, sub,
- gen_rtx_AND (mode, source,
- GEN_INT (temp1))));
- emit_insn (gen_rtx_SET (VOIDmode, target,
- gen_rtx_NOT (mode, sub)));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, sub,
+ gen_rtx_AND (mode, source,
+ GEN_INT (temp1))));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, target,
+ gen_rtx_NOT (mode, sub)));
}
return 3;
}
@@ -1634,14 +2186,16 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode,
if (generate)
{
rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
- insns = arm_gen_constant (AND, mode, remainder | shift_mask,
+ insns = arm_gen_constant (AND, mode, cond,
+ remainder | shift_mask,
new_src, source, subtargets, 1);
source = new_src;
}
else
{
rtx targ = subtargets ? NULL_RTX : target;
- insns = arm_gen_constant (AND, mode, remainder | shift_mask,
+ insns = arm_gen_constant (AND, mode, cond,
+ remainder | shift_mask,
targ, source, subtargets, 0);
}
}
@@ -1661,14 +2215,15 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode,
if (clear_zero_bit_copies >= 16 && clear_zero_bit_copies < 24)
{
HOST_WIDE_INT shift_mask = (1 << clear_zero_bit_copies) - 1;
-
+
if ((remainder | shift_mask) != 0xffffffff)
{
if (generate)
{
rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
- insns = arm_gen_constant (AND, mode, remainder | shift_mask,
+ insns = arm_gen_constant (AND, mode, cond,
+ remainder | shift_mask,
new_src, source, subtargets, 1);
source = new_src;
}
@@ -1676,7 +2231,8 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode,
{
rtx targ = subtargets ? NULL_RTX : target;
- insns = arm_gen_constant (AND, mode, remainder | shift_mask,
+ insns = arm_gen_constant (AND, mode, cond,
+ remainder | shift_mask,
targ, source, subtargets, 0);
}
}
@@ -1763,12 +2319,12 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode,
rather than having to synthesize both large constants from scratch.
Therefore, we calculate how many insns would be required to emit
- the constant starting from `best_start', and also starting from
- zero (ie with bit 31 first to be output). If `best_start' doesn't
+ the constant starting from `best_start', and also starting from
+ zero (i.e. with bit 31 first to be output). If `best_start' doesn't
yield a shorter sequence, we may as well use zero. */
if (best_start != 0
&& ((((unsigned HOST_WIDE_INT) 1) << best_start) < remainder)
- && (count_insns_for_constant (remainder, 0) <=
+ && (count_insns_for_constant (remainder, 0) <=
count_insns_for_constant (remainder, best_start)))
best_start = 0;
@@ -1821,7 +2377,9 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode,
else
temp1_rtx = gen_rtx_fmt_ee (code, mode, source, temp1_rtx);
- emit_insn (gen_rtx_SET (VOIDmode, new_src, temp1_rtx));
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, new_src,
+ temp1_rtx));
source = new_src;
}
@@ -1849,9 +2407,12 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode,
immediate value easier to load. */
enum rtx_code
-arm_canonicalize_comparison (enum rtx_code code, rtx * op1)
+arm_canonicalize_comparison (enum rtx_code code, enum machine_mode mode,
+ rtx * op1)
{
unsigned HOST_WIDE_INT i = INTVAL (*op1);
+ unsigned HOST_WIDE_INT maxval;
+ maxval = (((unsigned HOST_WIDE_INT) 1) << (GET_MODE_BITSIZE(mode) - 1)) - 1;
switch (code)
{
@@ -1861,7 +2422,7 @@ arm_canonicalize_comparison (enum rtx_code code, rtx * op1)
case GT:
case LE:
- if (i != ((((unsigned HOST_WIDE_INT) 1) << (HOST_BITS_PER_WIDE_INT - 1)) - 1)
+ if (i != maxval
&& (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
{
*op1 = GEN_INT (i + 1);
@@ -1871,7 +2432,7 @@ arm_canonicalize_comparison (enum rtx_code code, rtx * op1)
case GE:
case LT:
- if (i != (((unsigned HOST_WIDE_INT) 1) << (HOST_BITS_PER_WIDE_INT - 1))
+ if (i != ~maxval
&& (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
{
*op1 = GEN_INT (i - 1);
@@ -1900,12 +2461,65 @@ arm_canonicalize_comparison (enum rtx_code code, rtx * op1)
break;
default:
- abort ();
+ gcc_unreachable ();
}
return code;
}
+
+/* Define how to find the value returned by a function. */
+
+rtx
+arm_function_value(tree type, tree func ATTRIBUTE_UNUSED)
+{
+ enum machine_mode mode;
+ int unsignedp ATTRIBUTE_UNUSED;
+ rtx r ATTRIBUTE_UNUSED;
+
+ mode = TYPE_MODE (type);
+ /* Promote integer types. */
+ if (INTEGRAL_TYPE_P (type))
+ PROMOTE_FUNCTION_MODE (mode, unsignedp, type);
+
+ /* Promotes small structs returned in a register to full-word size
+ for big-endian AAPCS. */
+ if (arm_return_in_msb (type))
+ {
+ HOST_WIDE_INT size = int_size_in_bytes (type);
+ if (size % UNITS_PER_WORD != 0)
+ {
+ size += UNITS_PER_WORD - size % UNITS_PER_WORD;
+ mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
+ }
+ }
+
+ return LIBCALL_VALUE(mode);
+}
+
+/* Determine the amount of memory needed to store the possible return
+ registers of an untyped call. */
+int
+arm_apply_result_size (void)
+{
+ int size = 16;
+
+ if (TARGET_ARM)
+ {
+ if (TARGET_HARD_FLOAT_ABI)
+ {
+ if (TARGET_FPA)
+ size += 12;
+ if (TARGET_MAVERICK)
+ size += 8;
+ }
+ if (TARGET_IWMMXT_ABI)
+ size += 8;
+ }
+
+ return size;
+}
+
/* Decide whether a type should be returned in memory (true)
or in a register (false). This is called by the macro
RETURN_IN_MEMORY. */
@@ -1914,19 +2528,27 @@ arm_return_in_memory (tree type)
{
HOST_WIDE_INT size;
- if (!AGGREGATE_TYPE_P (type))
- /* All simple types are returned in registers. */
+ if (!AGGREGATE_TYPE_P (type) &&
+ (TREE_CODE (type) != VECTOR_TYPE) &&
+ !(TARGET_AAPCS_BASED && TREE_CODE (type) == COMPLEX_TYPE))
+ /* All simple types are returned in registers.
+ For AAPCS, complex types are treated the same as aggregates. */
return 0;
size = int_size_in_bytes (type);
- if (TARGET_ATPCS)
+ if (arm_abi != ARM_ABI_APCS)
{
- /* ATPCS returns aggregate types in memory only if they are
+ /* ATPCS and later return aggregate types in memory only if they are
larger than a word (or are variable size). */
return (size < 0 || size > UNITS_PER_WORD);
}
-
+
+ /* To maximize backwards compatibility with previous versions of gcc,
+ return vectors up to 4 words in registers. */
+ if (TREE_CODE (type) == VECTOR_TYPE)
+ return (size < 0 || size > (4 * UNITS_PER_WORD));
+
/* For the arm-wince targets we choose to be compatible with Microsoft's
ARM and Thumb compilers, which always return aggregates in memory. */
#ifndef ARM_WINCE
@@ -1936,7 +2558,7 @@ arm_return_in_memory (tree type)
we will want to return it via memory and not in a register. */
if (size < 0 || size > UNITS_PER_WORD)
return 1;
-
+
if (TREE_CODE (type) == RECORD_TYPE)
{
tree field;
@@ -1946,14 +2568,14 @@ arm_return_in_memory (tree type)
has an offset of zero. For practical purposes this means
that the structure can have at most one non bit-field element
and that this element must be the first one in the structure. */
-
+
/* Find the first field, ignoring non FIELD_DECL things which will
have been created by C++. */
for (field = TYPE_FIELDS (type);
field && TREE_CODE (field) != FIELD_DECL;
field = TREE_CHAIN (field))
continue;
-
+
if (field == NULL)
return 0; /* An empty structure. Allowed by an extension to ANSI C. */
@@ -1976,14 +2598,14 @@ arm_return_in_memory (tree type)
{
if (TREE_CODE (field) != FIELD_DECL)
continue;
-
+
if (!DECL_BIT_FIELD_TYPE (field))
return 1;
}
return 0;
}
-
+
if (TREE_CODE (type) == UNION_TYPE)
{
tree field;
@@ -1999,15 +2621,15 @@ arm_return_in_memory (tree type)
if (FLOAT_TYPE_P (TREE_TYPE (field)))
return 1;
-
+
if (RETURN_IN_MEMORY (TREE_TYPE (field)))
return 1;
}
-
+
return 0;
}
-#endif /* not ARM_WINCE */
-
+#endif /* not ARM_WINCE */
+
/* Return all other types in memory. */
return 1;
}
@@ -2017,15 +2639,14 @@ arm_return_in_memory (tree type)
int
arm_float_words_big_endian (void)
{
- if (TARGET_CIRRUS)
+ if (TARGET_MAVERICK)
return 0;
/* For FPA, float words are always big-endian. For VFP, floats words
follow the memory system mode. */
- if (TARGET_HARD_FLOAT)
+ if (TARGET_FPA)
{
- /* FIXME: TARGET_HARD_FLOAT currently implies FPA. */
return 1;
}
@@ -2039,19 +2660,20 @@ arm_float_words_big_endian (void)
for a call to a function whose data type is FNTYPE.
For a library call, FNTYPE is NULL. */
void
-arm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype,
+arm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype,
rtx libname ATTRIBUTE_UNUSED,
tree fndecl ATTRIBUTE_UNUSED)
{
/* On the ARM, the offset starts at 0. */
- pcum->nregs = ((fntype && aggregate_value_p (TREE_TYPE (fntype), fntype)) ? 1 : 0);
+ pcum->nregs = 0;
pcum->iwmmxt_nregs = 0;
-
+ pcum->can_split = true;
+
pcum->call_cookie = CALL_NORMAL;
if (TARGET_LONG_CALLS)
pcum->call_cookie = CALL_LONG;
-
+
/* Check for long call/short call attributes. The attributes
override any command line option. */
if (fntype)
@@ -2081,6 +2703,16 @@ arm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype,
}
}
+
+/* Return true if mode/type need doubleword alignment. */
+bool
+arm_needs_doubleword_align (enum machine_mode mode, tree type)
+{
+ return (GET_MODE_ALIGNMENT (mode) > PARM_BOUNDARY
+ || (type && TYPE_ALIGN (type) > PARM_BOUNDARY));
+}
+
+
/* Determine where to put an argument to a function.
Value is zero to push the argument on the stack,
or a hard register in which to store the argument.
@@ -2096,92 +2728,81 @@ arm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype,
rtx
arm_function_arg (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
- tree type ATTRIBUTE_UNUSED, int named)
+ tree type, int named)
{
- if (TARGET_REALLY_IWMMXT)
+ int nregs;
+
+ /* Varargs vectors are treated the same as long long.
+ named_count avoids having to change the way arm handles 'named' */
+ if (TARGET_IWMMXT_ABI
+ && arm_vector_mode_supported_p (mode)
+ && pcum->named_count > pcum->nargs + 1)
{
- if (VECTOR_MODE_SUPPORTED_P (mode))
+ if (pcum->iwmmxt_nregs <= 9)
+ return gen_rtx_REG (mode, pcum->iwmmxt_nregs + FIRST_IWMMXT_REGNUM);
+ else
{
- /* varargs vectors are treated the same as long long.
- named_count avoids having to change the way arm handles 'named' */
- if (pcum->named_count <= pcum->nargs + 1)
- {
- if (pcum->nregs == 1)
- pcum->nregs += 1;
- if (pcum->nregs <= 2)
- return gen_rtx_REG (mode, pcum->nregs);
- else
- return NULL_RTX;
- }
- else if (pcum->iwmmxt_nregs <= 9)
- return gen_rtx_REG (mode, pcum->iwmmxt_nregs + FIRST_IWMMXT_REGNUM);
- else
- return NULL_RTX;
+ pcum->can_split = false;
+ return NULL_RTX;
}
- else if ((mode == DImode || mode == DFmode) && pcum->nregs & 1)
- pcum->nregs += 1;
}
+ /* Put doubleword aligned quantities in even register pairs. */
+ if (pcum->nregs & 1
+ && ARM_DOUBLEWORD_ALIGN
+ && arm_needs_doubleword_align (mode, type))
+ pcum->nregs++;
+
if (mode == VOIDmode)
/* Compute operand 2 of the call insn. */
return GEN_INT (pcum->call_cookie);
-
- if (!named || pcum->nregs >= NUM_ARG_REGS)
+
+ /* Only allow splitting an arg between regs and memory if all preceding
+ args were allocated to regs. For args passed by reference we only count
+ the reference pointer. */
+ if (pcum->can_split)
+ nregs = 1;
+ else
+ nregs = ARM_NUM_REGS2 (mode, type);
+
+ if (!named || pcum->nregs + nregs > NUM_ARG_REGS)
return NULL_RTX;
-
+
return gen_rtx_REG (mode, pcum->nregs);
}
-/* Variable sized types are passed by reference. This is a GCC
- extension to the ARM ABI. */
-
-int
-arm_function_arg_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
- enum machine_mode mode ATTRIBUTE_UNUSED,
- tree type, int named ATTRIBUTE_UNUSED)
+static int
+arm_arg_partial_bytes (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
+ tree type, bool named ATTRIBUTE_UNUSED)
{
- return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
-}
-
-/* Implement va_arg. */
+ int nregs = pcum->nregs;
-rtx
-arm_va_arg (tree valist, tree type)
-{
- /* Variable sized types are passed by reference. */
- if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
- {
- rtx addr = std_expand_builtin_va_arg (valist, build_pointer_type (type));
- return gen_rtx_MEM (ptr_mode, force_reg (Pmode, addr));
- }
+ if (arm_vector_mode_supported_p (mode))
+ return 0;
- if (FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), NULL) == IWMMXT_ALIGNMENT)
- {
- tree minus_eight;
- tree t;
+ if (NUM_ARG_REGS > nregs
+ && (NUM_ARG_REGS < nregs + ARM_NUM_REGS2 (mode, type))
+ && pcum->can_split)
+ return (NUM_ARG_REGS - nregs) * UNITS_PER_WORD;
- /* Maintain 64-bit alignment of the valist pointer by
- constructing: valist = ((valist + (8 - 1)) & -8). */
- minus_eight = build_int_2 (- (IWMMXT_ALIGNMENT / BITS_PER_UNIT), -1);
- t = build_int_2 ((IWMMXT_ALIGNMENT / BITS_PER_UNIT) - 1, 0);
- t = build (PLUS_EXPR, TREE_TYPE (valist), valist, t);
- t = build (BIT_AND_EXPR, TREE_TYPE (t), t, minus_eight);
- t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
- TREE_SIDE_EFFECTS (t) = 1;
- expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ return 0;
+}
- /* This is to stop the combine pass optimizing
- away the alignment adjustment. */
- mark_reg_pointer (arg_pointer_rtx, PARM_BOUNDARY);
- }
+/* Variable sized types are passed by reference. This is a GCC
+ extension to the ARM ABI. */
- return std_expand_builtin_va_arg (valist, type);
+static bool
+arm_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ tree type, bool named ATTRIBUTE_UNUSED)
+{
+ return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
}
/* Encode the current state of the #pragma [no_]long_calls. */
typedef enum
{
- OFF, /* No #pramgma [no_]long_calls is in effect. */
+ OFF, /* No #pragma [no_]long_calls is in effect. */
LONG, /* #pragma long_calls is in effect. */
SHORT /* #pragma no_long_calls is in effect. */
} arm_pragma_enum;
@@ -2217,7 +2838,7 @@ const struct attribute_spec arm_attribute_table[] =
/* Whereas these functions are always known to reside within the 26 bit
addressing range. */
{ "short_call", 0, 0, false, true, true, NULL },
- /* Interrupt Service Routines have special prologue and epilogue requirements. */
+ /* Interrupt Service Routines have special prologue and epilogue requirements. */
{ "isr", 0, 1, false, false, false, arm_handle_isr_attribute },
{ "interrupt", 0, 1, false, false, false, arm_handle_isr_attribute },
{ "naked", 0, 0, true, false, false, arm_handle_fndecl_attribute },
@@ -2234,6 +2855,10 @@ const struct attribute_spec arm_attribute_table[] =
{ "dllimport", 0, 0, true, false, false, NULL },
{ "dllexport", 0, 0, true, false, false, NULL },
{ "interfacearm", 0, 0, true, false, false, arm_handle_fndecl_attribute },
+#elif TARGET_DLLIMPORT_DECL_ATTRIBUTES
+ { "dllimport", 0, 0, false, false, false, handle_dll_attribute },
+ { "dllexport", 0, 0, false, false, false, handle_dll_attribute },
+ { "notshared", 0, 0, false, true, false, arm_handle_notshared_attribute },
#endif
{ NULL, 0, 0, false, false, false, NULL }
};
@@ -2246,7 +2871,7 @@ arm_handle_fndecl_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
{
if (TREE_CODE (*node) != FUNCTION_DECL)
{
- warning ("`%s' attribute only applies to functions",
+ warning (OPT_Wattributes, "%qs attribute only applies to functions",
IDENTIFIER_POINTER (name));
*no_add_attrs = true;
}
@@ -2264,7 +2889,7 @@ arm_handle_isr_attribute (tree *node, tree name, tree args, int flags,
{
if (TREE_CODE (*node) != FUNCTION_DECL)
{
- warning ("`%s' attribute only applies to functions",
+ warning (OPT_Wattributes, "%qs attribute only applies to functions",
IDENTIFIER_POINTER (name));
*no_add_attrs = true;
}
@@ -2278,7 +2903,8 @@ arm_handle_isr_attribute (tree *node, tree name, tree args, int flags,
{
if (arm_isr_value (args) == ARM_FT_UNKNOWN)
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qs attribute ignored",
+ IDENTIFIER_POINTER (name));
*no_add_attrs = true;
}
}
@@ -2287,7 +2913,7 @@ arm_handle_isr_attribute (tree *node, tree name, tree args, int flags,
|| TREE_CODE (TREE_TYPE (*node)) == METHOD_TYPE)
&& arm_isr_value (args) != ARM_FT_UNKNOWN)
{
- *node = build_type_copy (*node);
+ *node = build_variant_type_copy (*node);
TREE_TYPE (*node) = build_type_attribute_variant
(TREE_TYPE (*node),
tree_cons (name, args, TYPE_ATTRIBUTES (TREE_TYPE (*node))));
@@ -2305,7 +2931,8 @@ arm_handle_isr_attribute (tree *node, tree name, tree args, int flags,
}
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qs attribute ignored",
+ IDENTIFIER_POINTER (name));
}
}
}
@@ -2313,6 +2940,31 @@ arm_handle_isr_attribute (tree *node, tree name, tree args, int flags,
return NULL_TREE;
}
+#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
+/* Handle the "notshared" attribute. This attribute is another way of
+ requesting hidden visibility. ARM's compiler supports
+ "__declspec(notshared)"; we support the same thing via an
+ attribute. */
+
+static tree
+arm_handle_notshared_attribute (tree *node,
+ tree name ATTRIBUTE_UNUSED,
+ tree args ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED,
+ bool *no_add_attrs)
+{
+ tree decl = TYPE_NAME (*node);
+
+ if (decl)
+ {
+ DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
+ DECL_VISIBILITY_SPECIFIED (decl) = 1;
+ *no_add_attrs = false;
+ }
+ return NULL_TREE;
+}
+#endif
+
/* Return 0 if the attributes for two types are incompatible, 1 if they
are compatible, and 2 if they are nearly compatible (which causes a
warning to be generated). */
@@ -2320,7 +2972,7 @@ static int
arm_comp_type_attributes (tree type1, tree type2)
{
int l1, l2, s1, s2;
-
+
/* Check for mismatch of non-default calling convention. */
if (TREE_CODE (type1) != FUNCTION_TYPE)
return 1;
@@ -2342,7 +2994,7 @@ arm_comp_type_attributes (tree type1, tree type2)
if ((l1 & s2) || (l2 & s1))
return 0;
}
-
+
/* Check for mismatched ISR attribute. */
l1 = lookup_attribute ("isr", TYPE_ATTRIBUTES (type1)) != NULL;
if (! l1)
@@ -2416,7 +3068,7 @@ current_file_function_operand (rtx sym_ref)
return 1;
/* The current function is always defined within the current compilation
- unit. if it s a weak definition however, then this may not be the real
+ unit. If it s a weak definition however, then this may not be the real
definition of the function, and so we have to say no. */
if (sym_ref == XEXP (DECL_RTL (current_function_decl), 0)
&& !DECL_WEAK (current_function_decl))
@@ -2432,16 +3084,19 @@ current_file_function_operand (rtx sym_ref)
a. has an __attribute__((long call))
or b. is within the scope of a #pragma long_calls
or c. the -mlong-calls command line switch has been specified
+ . and either:
+ 1. -ffunction-sections is in effect
+ or 2. the current function has __attribute__ ((section))
+ or 3. the target function has __attribute__ ((section))
However we do not generate a long call if the function:
-
+
d. has an __attribute__ ((short_call))
or e. is inside the scope of a #pragma no_long_calls
- or f. has an __attribute__ ((section))
- or g. is defined within the current compilation unit.
-
+ or f. is defined within the current compilation unit.
+
This function will be called by C fragments contained in the machine
- description file. CALL_REF and CALL_COOKIE correspond to the matched
+ description file. SYM_REF and CALL_COOKIE correspond to the matched
rtl operands. CALL_SYMBOL is used to distinguish between
two different callers of the function. It is set to 1 in the
"call_symbol" and "call_symbol_value" patterns and to 0 in the "call"
@@ -2464,12 +3119,18 @@ arm_is_longcall_p (rtx sym_ref, int call_cookie, int call_symbol)
if (call_cookie & CALL_SHORT)
return 0;
- if (TARGET_LONG_CALLS && flag_function_sections)
- return 1;
-
+ if (TARGET_LONG_CALLS)
+ {
+ if (flag_function_sections
+ || DECL_SECTION_NAME (current_function_decl))
+ /* c.3 is handled by the definition of the
+ ARM_DECLARE_FUNCTION_SIZE macro. */
+ return 1;
+ }
+
if (current_file_function_operand (sym_ref))
return 0;
-
+
return (call_cookie & CALL_LONG)
|| ENCODED_LONG_CALL_ATTR_P (XSTR (sym_ref, 0))
|| TARGET_LONG_CALLS;
@@ -2502,7 +3163,7 @@ arm_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
return false;
/* If we are interworking and the function is not declared static
- then we can't tail-call it unless we know that it exists in this
+ then we can't tail-call it unless we know that it exists in this
compilation unit (since it might be a Thumb routine). */
if (TARGET_INTERWORK && TREE_PUBLIC (decl) && !TREE_ASM_WRITTEN (decl))
return false;
@@ -2519,16 +3180,14 @@ arm_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
/* Addressing mode support functions. */
/* Return nonzero if X is a legitimate immediate operand when compiling
- for PIC. */
+ for PIC. We know that X satisfies CONSTANT_P and flag_pic is true. */
int
legitimate_pic_operand_p (rtx x)
{
- if (CONSTANT_P (x)
- && flag_pic
- && (GET_CODE (x) == SYMBOL_REF
- || (GET_CODE (x) == CONST
- && GET_CODE (XEXP (x, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF)))
+ if (GET_CODE (x) == SYMBOL_REF
+ || (GET_CODE (x) == CONST
+ && GET_CODE (XEXP (x, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF))
return 0;
return 1;
@@ -2546,12 +3205,53 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
rtx insn;
int subregs = 0;
+ /* If this function doesn't have a pic register, create one now.
+ A lot of the logic here is made obscure by the fact that this
+ routine gets called as part of the rtx cost estimation
+ process. We don't want those calls to affect any assumptions
+ about the real function; and further, we can't call
+ entry_of_function() until we start the real expansion
+ process. */
+ if (!current_function_uses_pic_offset_table)
+ {
+ gcc_assert (!no_new_pseudos);
+ if (arm_pic_register != INVALID_REGNUM)
+ {
+ cfun->machine->pic_reg = gen_rtx_REG (Pmode, arm_pic_register);
+
+ /* Play games to avoid marking the function as needing pic
+ if we are being called as part of the cost-estimation
+ process. */
+ if (!ir_type())
+ current_function_uses_pic_offset_table = 1;
+ }
+ else
+ {
+ rtx seq;
+
+ cfun->machine->pic_reg = gen_reg_rtx (Pmode);
+
+ /* Play games to avoid marking the function as needing pic
+ if we are being called as part of the cost-estimation
+ process. */
+ if (!ir_type())
+ {
+ current_function_uses_pic_offset_table = 1;
+ start_sequence ();
+
+ arm_load_pic_register (0UL);
+
+ seq = get_insns ();
+ end_sequence ();
+ emit_insn_after (seq, entry_of_function ());
+ }
+ }
+ }
+
if (reg == 0)
{
- if (no_new_pseudos)
- abort ();
- else
- reg = gen_reg_rtx (Pmode);
+ gcc_assert (!no_new_pseudos);
+ reg = gen_reg_rtx (Pmode);
subregs = 1;
}
@@ -2572,21 +3272,19 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
emit_insn (gen_pic_load_addr_thumb (address, orig));
if ((GET_CODE (orig) == LABEL_REF
- || (GET_CODE (orig) == SYMBOL_REF &&
+ || (GET_CODE (orig) == SYMBOL_REF &&
SYMBOL_REF_LOCAL_P (orig)))
&& NEED_GOT_RELOC)
- pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, address);
+ pic_ref = gen_rtx_PLUS (Pmode, cfun->machine->pic_reg, address);
else
{
- pic_ref = gen_rtx_MEM (Pmode,
- gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
- address));
- RTX_UNCHANGING_P (pic_ref) = 1;
+ pic_ref = gen_const_mem (Pmode,
+ gen_rtx_PLUS (Pmode, cfun->machine->pic_reg,
+ address));
}
insn = emit_move_insn (reg, pic_ref);
#endif
- current_function_uses_pic_offset_table = 1;
/* Put a REG_EQUAL note on this insn, so that it can be optimized
by loop. */
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig,
@@ -2598,36 +3296,33 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
rtx base, offset;
if (GET_CODE (XEXP (orig, 0)) == PLUS
- && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
+ && XEXP (XEXP (orig, 0), 0) == cfun->machine->pic_reg)
+ return orig;
+
+ if (GET_CODE (XEXP (orig, 0)) == UNSPEC
+ && XINT (XEXP (orig, 0), 1) == UNSPEC_TLS)
return orig;
if (reg == 0)
{
- if (no_new_pseudos)
- abort ();
- else
- reg = gen_reg_rtx (Pmode);
+ gcc_assert (!no_new_pseudos);
+ reg = gen_reg_rtx (Pmode);
}
- if (GET_CODE (XEXP (orig, 0)) == PLUS)
- {
- base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
- offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
- base == reg ? 0 : reg);
- }
- else
- abort ();
+ gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
+
+ base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
+ offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
+ base == reg ? 0 : reg);
if (GET_CODE (offset) == CONST_INT)
{
/* The base register doesn't really matter, we only want to
test the index for the appropriate mode. */
- if (!arm_legitimate_index_p (mode, offset, 0))
+ if (!arm_legitimate_index_p (mode, offset, SET, 0))
{
- if (!no_new_pseudos)
- offset = force_reg (Pmode, offset);
- else
- abort ();
+ gcc_assert (!no_new_pseudos);
+ offset = force_reg (Pmode, offset);
}
if (GET_CODE (offset) == CONST_INT)
@@ -2648,31 +3343,89 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
return orig;
}
-/* Generate code to load the PIC register. PROLOGUE is true if
- called from arm_expand_prologue (in which case we want the
- generated insns at the start of the function); false if called
- by an exception receiver that needs the PIC register reloaded
- (in which case the insns are just dumped at the current location). */
+
+/* Find a spare low register to use during the prolog of a function. */
+
+static int
+thumb_find_work_register (unsigned long pushed_regs_mask)
+{
+ int reg;
+
+ /* Check the argument registers first as these are call-used. The
+ register allocation order means that sometimes r3 might be used
+ but earlier argument registers might not, so check them all. */
+ for (reg = LAST_ARG_REGNUM; reg >= 0; reg --)
+ if (!regs_ever_live[reg])
+ return reg;
+
+ /* Before going on to check the call-saved registers we can try a couple
+ more ways of deducing that r3 is available. The first is when we are
+ pushing anonymous arguments onto the stack and we have less than 4
+ registers worth of fixed arguments(*). In this case r3 will be part of
+ the variable argument list and so we can be sure that it will be
+ pushed right at the start of the function. Hence it will be available
+ for the rest of the prologue.
+ (*): ie current_function_pretend_args_size is greater than 0. */
+ if (cfun->machine->uses_anonymous_args
+ && current_function_pretend_args_size > 0)
+ return LAST_ARG_REGNUM;
+
+ /* The other case is when we have fixed arguments but less than 4 registers
+ worth. In this case r3 might be used in the body of the function, but
+ it is not being used to convey an argument into the function. In theory
+ we could just check current_function_args_size to see how many bytes are
+ being passed in argument registers, but it seems that it is unreliable.
+ Sometimes it will have the value 0 when in fact arguments are being
+ passed. (See testcase execute/20021111-1.c for an example). So we also
+ check the args_info.nregs field as well. The problem with this field is
+ that it makes no allowances for arguments that are passed to the
+ function but which are not used. Hence we could miss an opportunity
+ when a function has an unused argument in r3. But it is better to be
+ safe than to be sorry. */
+ if (! cfun->machine->uses_anonymous_args
+ && current_function_args_size >= 0
+ && current_function_args_size <= (LAST_ARG_REGNUM * UNITS_PER_WORD)
+ && cfun->args_info.nregs < 4)
+ return LAST_ARG_REGNUM;
+
+ /* Otherwise look for a call-saved register that is going to be pushed. */
+ for (reg = LAST_LO_REGNUM; reg > LAST_ARG_REGNUM; reg --)
+ if (pushed_regs_mask & (1 << reg))
+ return reg;
+
+ /* Something went wrong - thumb_compute_save_reg_mask()
+ should have arranged for a suitable register to be pushed. */
+ gcc_unreachable ();
+}
+
+static GTY(()) int pic_labelno;
+
+/* Generate code to load the PIC register. In thumb mode SCRATCH is a
+ low register. */
+
void
-arm_finalize_pic (int prologue ATTRIBUTE_UNUSED)
+arm_load_pic_register (unsigned long saved_regs ATTRIBUTE_UNUSED)
{
#ifndef AOF_ASSEMBLER
- rtx l1, pic_tmp, pic_tmp2, seq, pic_rtx;
+ rtx l1, labelno, pic_tmp, pic_tmp2, pic_rtx;
rtx global_offset_table;
if (current_function_uses_pic_offset_table == 0 || TARGET_SINGLE_PIC_BASE)
return;
- if (!flag_pic)
- abort ();
+ gcc_assert (flag_pic);
- start_sequence ();
- l1 = gen_label_rtx ();
+ /* We use an UNSPEC rather than a LABEL_REF because this label never appears
+ in the code stream. */
+
+ labelno = GEN_INT (pic_labelno++);
+ l1 = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_PIC_LABEL);
+ l1 = gen_rtx_CONST (VOIDmode, l1);
global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
/* On the ARM the PC register contains 'dot + 8' at the time of the
addition, on the Thumb it is 'dot + 4'. */
- pic_tmp = plus_constant (gen_rtx_LABEL_REF (Pmode, l1), TARGET_ARM ? 8 : 4);
+ pic_tmp = plus_constant (l1, TARGET_ARM ? 8 : 4);
if (GOT_PCREL)
pic_tmp2 = gen_rtx_CONST (VOIDmode,
gen_rtx_PLUS (Pmode, global_offset_table, pc_rtx));
@@ -2680,31 +3433,38 @@ arm_finalize_pic (int prologue ATTRIBUTE_UNUSED)
pic_tmp2 = gen_rtx_CONST (VOIDmode, global_offset_table);
pic_rtx = gen_rtx_CONST (Pmode, gen_rtx_MINUS (Pmode, pic_tmp2, pic_tmp));
-
+
if (TARGET_ARM)
{
- emit_insn (gen_pic_load_addr_arm (pic_offset_table_rtx, pic_rtx));
- emit_insn (gen_pic_add_dot_plus_eight (pic_offset_table_rtx, l1));
+ emit_insn (gen_pic_load_addr_arm (cfun->machine->pic_reg, pic_rtx));
+ emit_insn (gen_pic_add_dot_plus_eight (cfun->machine->pic_reg,
+ cfun->machine->pic_reg, labelno));
}
else
{
- emit_insn (gen_pic_load_addr_thumb (pic_offset_table_rtx, pic_rtx));
- emit_insn (gen_pic_add_dot_plus_four (pic_offset_table_rtx, l1));
+ if (arm_pic_register != INVALID_REGNUM
+ && REGNO (cfun->machine->pic_reg) > LAST_LO_REGNUM)
+ {
+ /* We will have pushed the pic register, so we should always be
+ able to find a work register. */
+ pic_tmp = gen_rtx_REG (SImode,
+ thumb_find_work_register (saved_regs));
+ emit_insn (gen_pic_load_addr_thumb (pic_tmp, pic_rtx));
+ emit_insn (gen_movsi (pic_offset_table_rtx, pic_tmp));
+ }
+ else
+ emit_insn (gen_pic_load_addr_thumb (cfun->machine->pic_reg, pic_rtx));
+ emit_insn (gen_pic_add_dot_plus_four (cfun->machine->pic_reg,
+ cfun->machine->pic_reg, labelno));
}
- seq = get_insns ();
- end_sequence ();
- if (prologue)
- emit_insn_after (seq, get_insns ());
- else
- emit_insn (seq);
-
/* 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_offset_table_rtx));
+ emit_insn (gen_rtx_USE (VOIDmode, cfun->machine->pic_reg));
#endif /* AOF_ASSEMBLER */
}
+
/* Return nonzero if X is valid as an ARM state addressing register. */
static int
arm_address_register_rtx_p (rtx x, int strict_p)
@@ -2725,28 +3485,62 @@ arm_address_register_rtx_p (rtx x, int strict_p)
|| regno == ARG_POINTER_REGNUM);
}
+/* Return TRUE if this rtx is the difference of a symbol and a label,
+ and will reduce to a PC-relative relocation in the object file.
+ Expressions like this can be left alone when generating PIC, rather
+ than forced through the GOT. */
+static int
+pcrel_constant_p (rtx x)
+{
+ if (GET_CODE (x) == MINUS)
+ return symbol_mentioned_p (XEXP (x, 0)) && label_mentioned_p (XEXP (x, 1));
+
+ return FALSE;
+}
+
/* Return nonzero if X is a valid ARM state address operand. */
int
-arm_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
+arm_legitimate_address_p (enum machine_mode mode, rtx x, RTX_CODE outer,
+ int strict_p)
{
+ bool use_ldrd;
+ enum rtx_code code = GET_CODE (x);
+
if (arm_address_register_rtx_p (x, strict_p))
return 1;
- else if (GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_DEC)
+ use_ldrd = (TARGET_LDRD
+ && (mode == DImode
+ || (mode == DFmode && (TARGET_SOFT_FLOAT || TARGET_VFP))));
+
+ if (code == POST_INC || code == PRE_DEC
+ || ((code == PRE_INC || code == POST_DEC)
+ && (use_ldrd || GET_MODE_SIZE (mode) <= 4)))
return arm_address_register_rtx_p (XEXP (x, 0), strict_p);
- else if ((GET_CODE (x) == POST_MODIFY || GET_CODE (x) == PRE_MODIFY)
- && GET_MODE_SIZE (mode) <= 4
+ else if ((code == POST_MODIFY || code == PRE_MODIFY)
&& arm_address_register_rtx_p (XEXP (x, 0), strict_p)
&& GET_CODE (XEXP (x, 1)) == PLUS
&& rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
- return arm_legitimate_index_p (mode, XEXP (XEXP (x, 1), 1), strict_p);
+ {
+ rtx addend = XEXP (XEXP (x, 1), 1);
+
+ /* Don't allow ldrd post increment by register because it's hard
+ to fixup invalid register choices. */
+ if (use_ldrd
+ && GET_CODE (x) == POST_MODIFY
+ && GET_CODE (addend) == REG)
+ return 0;
+
+ return ((use_ldrd || GET_MODE_SIZE (mode) <= 4)
+ && arm_legitimate_index_p (mode, addend, outer, strict_p));
+ }
/* After reload constants split into minipools will have addresses
from a LABEL_REF. */
else if (reload_completed
- && (GET_CODE (x) == LABEL_REF
- || (GET_CODE (x) == CONST
+ && (code == LABEL_REF
+ || (code == CONST
&& GET_CODE (XEXP (x, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)))
@@ -2755,28 +3549,15 @@ arm_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
else if (mode == TImode)
return 0;
- else if (mode == DImode || (TARGET_SOFT_FLOAT && mode == DFmode))
- {
- if (GET_CODE (x) == PLUS
- && arm_address_register_rtx_p (XEXP (x, 0), strict_p)
- && GET_CODE (XEXP (x, 1)) == CONST_INT)
- {
- HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
-
- if (val == 4 || val == -4 || val == -8)
- return 1;
- }
- }
-
- else if (GET_CODE (x) == PLUS)
+ else if (code == PLUS)
{
rtx xop0 = XEXP (x, 0);
rtx xop1 = XEXP (x, 1);
return ((arm_address_register_rtx_p (xop0, strict_p)
- && arm_legitimate_index_p (mode, xop1, strict_p))
+ && arm_legitimate_index_p (mode, xop1, outer, strict_p))
|| (arm_address_register_rtx_p (xop1, strict_p)
- && arm_legitimate_index_p (mode, xop0, strict_p)));
+ && arm_legitimate_index_p (mode, xop0, outer, strict_p)));
}
#if 0
@@ -2787,20 +3568,16 @@ arm_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
rtx xop1 = XEXP (x, 1);
return (arm_address_register_rtx_p (xop0, strict_p)
- && arm_legitimate_index_p (mode, xop1, strict_p));
+ && arm_legitimate_index_p (mode, xop1, outer, strict_p));
}
#endif
else if (GET_MODE_CLASS (mode) != MODE_FLOAT
- && GET_CODE (x) == SYMBOL_REF
+ && code == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (x)
&& ! (flag_pic
- && symbol_mentioned_p (get_pool_constant (x))))
- return 1;
-
- else if ((GET_CODE (x) == PRE_INC || GET_CODE (x) == POST_DEC)
- && (GET_MODE_SIZE (mode) <= 4)
- && arm_address_register_rtx_p (XEXP (x, 0), strict_p))
+ && symbol_mentioned_p (get_pool_constant (x))
+ && ! pcrel_constant_p (get_pool_constant (x))))
return 1;
return 0;
@@ -2809,63 +3586,87 @@ arm_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
/* Return nonzero if INDEX is valid for an address index operand in
ARM state. */
static int
-arm_legitimate_index_p (enum machine_mode mode, rtx index, int strict_p)
+arm_legitimate_index_p (enum machine_mode mode, rtx index, RTX_CODE outer,
+ int strict_p)
{
HOST_WIDE_INT range;
enum rtx_code code = GET_CODE (index);
- if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
+ /* Standard coprocessor addressing modes. */
+ if (TARGET_HARD_FLOAT
+ && (TARGET_FPA || TARGET_MAVERICK)
+ && (GET_MODE_CLASS (mode) == MODE_FLOAT
+ || (TARGET_MAVERICK && mode == DImode)))
return (code == CONST_INT && INTVAL (index) < 1024
&& INTVAL (index) > -1024
&& (INTVAL (index) & 3) == 0);
- if (TARGET_CIRRUS
- && (GET_MODE_CLASS (mode) == MODE_FLOAT || mode == DImode))
- return (code == CONST_INT
- && INTVAL (index) < 255
- && INTVAL (index) > -255);
+ if (TARGET_REALLY_IWMMXT && VALID_IWMMXT_REG_MODE (mode))
+ {
+ /* For DImode assume values will usually live in core regs
+ and only allow LDRD addressing modes. */
+ if (!TARGET_LDRD || mode != DImode)
+ return (code == CONST_INT
+ && INTVAL (index) < 1024
+ && INTVAL (index) > -1024
+ && (INTVAL (index) & 3) == 0);
+ }
if (arm_address_register_rtx_p (index, strict_p)
- && GET_MODE_SIZE (mode) <= 4)
+ && (GET_MODE_SIZE (mode) <= 4))
return 1;
- if (TARGET_REALLY_IWMMXT && VALID_IWMMXT_REG_MODE (mode))
- return (code == CONST_INT
- && INTVAL (index) < 256
- && INTVAL (index) > -256);
-
- /* XXX What about ldrsb? */
- if (GET_MODE_SIZE (mode) <= 4 && code == MULT
- && (!arm_arch4 || (mode) != HImode))
+ if (mode == DImode || mode == DFmode)
{
- rtx xiop0 = XEXP (index, 0);
- rtx xiop1 = XEXP (index, 1);
+ if (code == CONST_INT)
+ {
+ HOST_WIDE_INT val = INTVAL (index);
+
+ if (TARGET_LDRD)
+ return val > -256 && val < 256;
+ else
+ return val > -4096 && val < 4092;
+ }
- return ((arm_address_register_rtx_p (xiop0, strict_p)
- && power_of_two_operand (xiop1, SImode))
- || (arm_address_register_rtx_p (xiop1, strict_p)
- && power_of_two_operand (xiop0, SImode)));
+ return TARGET_LDRD && arm_address_register_rtx_p (index, strict_p);
}
if (GET_MODE_SIZE (mode) <= 4
- && (code == LSHIFTRT || code == ASHIFTRT
- || code == ASHIFT || code == ROTATERT)
- && (!arm_arch4 || (mode) != HImode))
+ && ! (arm_arch4
+ && (mode == HImode
+ || (mode == QImode && outer == SIGN_EXTEND))))
{
- rtx op = XEXP (index, 1);
+ if (code == MULT)
+ {
+ rtx xiop0 = XEXP (index, 0);
+ rtx xiop1 = XEXP (index, 1);
- return (arm_address_register_rtx_p (XEXP (index, 0), strict_p)
- && GET_CODE (op) == CONST_INT
- && INTVAL (op) > 0
- && INTVAL (op) <= 31);
+ return ((arm_address_register_rtx_p (xiop0, strict_p)
+ && power_of_two_operand (xiop1, SImode))
+ || (arm_address_register_rtx_p (xiop1, strict_p)
+ && power_of_two_operand (xiop0, SImode)));
+ }
+ else if (code == LSHIFTRT || code == ASHIFTRT
+ || code == ASHIFT || code == ROTATERT)
+ {
+ rtx op = XEXP (index, 1);
+
+ return (arm_address_register_rtx_p (XEXP (index, 0), strict_p)
+ && GET_CODE (op) == CONST_INT
+ && INTVAL (op) > 0
+ && INTVAL (op) <= 31);
+ }
}
- /* XXX For ARM v4 we may be doing a sign-extend operation during the
- load, but that has a restricted addressing range and we are unable
- to tell here whether that is the case. To be safe we restrict all
- loads to that range. */
+ /* For ARM v4 we may be doing a sign-extend operation during the
+ load. */
if (arm_arch4)
- range = (mode == HImode || mode == QImode) ? 256 : 4096;
+ {
+ if (mode == HImode || (outer == SIGN_EXTEND && mode == QImode))
+ range = 256;
+ else
+ range = 4096;
+ }
else
range = (mode == HImode) ? 4095 : 4096;
@@ -2907,7 +3708,7 @@ thumb_index_register_rtx_p (rtx x, int strict_p)
}
/* Return nonzero if x is a legitimate Thumb-state address.
-
+
The AP may be eliminated to either the SP or the FP, so we use the
least common denominator, e.g. SImode, and offsets from 0 to 64.
@@ -2944,7 +3745,7 @@ thumb_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
/* This is PC relative data before arm_reorg runs. */
else if (GET_MODE_SIZE (mode) >= 4 && CONSTANT_P (x)
&& GET_CODE (x) == SYMBOL_REF
- && CONSTANT_POOL_ADDRESS_P (x) && ! flag_pic)
+ && CONSTANT_POOL_ADDRESS_P (x) && !flag_pic)
return 1;
/* This is PC relative data after arm_reorg runs. */
@@ -3006,8 +3807,9 @@ thumb_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
&& GET_MODE_SIZE (mode) == 4
&& GET_CODE (x) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (x)
- && !(flag_pic
- && symbol_mentioned_p (get_pool_constant (x))))
+ && ! (flag_pic
+ && symbol_mentioned_p (get_pool_constant (x))
+ && ! pcrel_constant_p (get_pool_constant (x))))
return 1;
return 0;
@@ -3033,11 +3835,166 @@ thumb_legitimate_offset_p (enum machine_mode mode, HOST_WIDE_INT val)
}
}
+/* Build the SYMBOL_REF for __tls_get_addr. */
+
+static GTY(()) rtx tls_get_addr_libfunc;
+
+static rtx
+get_tls_get_addr (void)
+{
+ if (!tls_get_addr_libfunc)
+ tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr");
+ return tls_get_addr_libfunc;
+}
+
+static rtx
+arm_load_tp (rtx target)
+{
+ if (!target)
+ target = gen_reg_rtx (SImode);
+
+ if (TARGET_HARD_TP)
+ {
+ /* Can return in any reg. */
+ emit_insn (gen_load_tp_hard (target));
+ }
+ else
+ {
+ /* Always returned in r0. Immediately copy the result into a pseudo,
+ otherwise other uses of r0 (e.g. setting up function arguments) may
+ clobber the value. */
+
+ rtx tmp;
+
+ emit_insn (gen_load_tp_soft ());
+
+ tmp = gen_rtx_REG (SImode, 0);
+ emit_move_insn (target, tmp);
+ }
+ return target;
+}
+
+static rtx
+load_tls_operand (rtx x, rtx reg)
+{
+ rtx tmp;
+
+ if (reg == NULL_RTX)
+ reg = gen_reg_rtx (SImode);
+
+ tmp = gen_rtx_CONST (SImode, x);
+
+ emit_move_insn (reg, tmp);
+
+ return reg;
+}
+
+static rtx
+arm_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc)
+{
+ rtx insns, label, labelno, sum;
+
+ start_sequence ();
+
+ labelno = GEN_INT (pic_labelno++);
+ label = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_PIC_LABEL);
+ label = gen_rtx_CONST (VOIDmode, label);
+
+ sum = gen_rtx_UNSPEC (Pmode,
+ gen_rtvec (4, x, GEN_INT (reloc), label,
+ GEN_INT (TARGET_ARM ? 8 : 4)),
+ UNSPEC_TLS);
+ reg = load_tls_operand (sum, reg);
+
+ if (TARGET_ARM)
+ emit_insn (gen_pic_add_dot_plus_eight (reg, reg, labelno));
+ else
+ emit_insn (gen_pic_add_dot_plus_four (reg, reg, labelno));
+
+ *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX, LCT_PURE, /* LCT_CONST? */
+ Pmode, 1, reg, Pmode);
+
+ insns = get_insns ();
+ end_sequence ();
+
+ return insns;
+}
+
+rtx
+legitimize_tls_address (rtx x, rtx reg)
+{
+ rtx dest, tp, label, labelno, sum, insns, ret, eqv, addend;
+ unsigned int model = SYMBOL_REF_TLS_MODEL (x);
+
+ switch (model)
+ {
+ case TLS_MODEL_GLOBAL_DYNAMIC:
+ insns = arm_call_tls_get_addr (x, reg, &ret, TLS_GD32);
+ dest = gen_reg_rtx (Pmode);
+ emit_libcall_block (insns, dest, ret, x);
+ return dest;
+
+ case TLS_MODEL_LOCAL_DYNAMIC:
+ insns = arm_call_tls_get_addr (x, reg, &ret, TLS_LDM32);
+
+ /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
+ share the LDM result with other LD model accesses. */
+ eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx),
+ UNSPEC_TLS);
+ dest = gen_reg_rtx (Pmode);
+ emit_libcall_block (insns, dest, ret, eqv);
+
+ /* Load the addend. */
+ addend = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (TLS_LDO32)),
+ UNSPEC_TLS);
+ addend = force_reg (SImode, gen_rtx_CONST (SImode, addend));
+ return gen_rtx_PLUS (Pmode, dest, addend);
+
+ case TLS_MODEL_INITIAL_EXEC:
+ labelno = GEN_INT (pic_labelno++);
+ label = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_PIC_LABEL);
+ label = gen_rtx_CONST (VOIDmode, label);
+ sum = gen_rtx_UNSPEC (Pmode,
+ gen_rtvec (4, x, GEN_INT (TLS_IE32), label,
+ GEN_INT (TARGET_ARM ? 8 : 4)),
+ UNSPEC_TLS);
+ reg = load_tls_operand (sum, reg);
+
+ if (TARGET_ARM)
+ emit_insn (gen_tls_load_dot_plus_eight (reg, reg, labelno));
+ else
+ {
+ emit_insn (gen_pic_add_dot_plus_four (reg, reg, labelno));
+ emit_move_insn (reg, gen_const_mem (SImode, reg));
+ }
+
+ tp = arm_load_tp (NULL_RTX);
+
+ return gen_rtx_PLUS (Pmode, tp, reg);
+
+ case TLS_MODEL_LOCAL_EXEC:
+ tp = arm_load_tp (NULL_RTX);
+
+ reg = gen_rtx_UNSPEC (Pmode,
+ gen_rtvec (2, x, GEN_INT (TLS_LE32)),
+ UNSPEC_TLS);
+ reg = force_reg (SImode, gen_rtx_CONST (SImode, reg));
+
+ return gen_rtx_PLUS (Pmode, tp, reg);
+
+ default:
+ abort ();
+ }
+}
+
/* Try machine-dependent ways of modifying an illegitimate address
to be legitimate. If we find one, return the new, valid address. */
rtx
arm_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode)
{
+ if (arm_tls_symbol_p (x))
+ return legitimize_tls_address (x, NULL_RTX);
+
if (GET_CODE (x) == PLUS)
{
rtx xop0 = XEXP (x, 0);
@@ -3056,7 +4013,10 @@ arm_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode)
rtx base_reg, val;
n = INTVAL (xop1);
- if (mode == DImode || (TARGET_SOFT_FLOAT && mode == DFmode))
+ /* VFP addressing modes actually allow greater offsets, but for
+ now we just stick with the lowest common denominator. */
+ if (mode == DImode
+ || ((TARGET_SOFT_FLOAT || TARGET_VFP) && mode == DFmode))
{
low_n = n & 0x0f;
n &= ~0x0f;
@@ -3074,11 +4034,9 @@ arm_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode)
}
base_reg = gen_reg_rtx (SImode);
- val = force_operand (gen_rtx_PLUS (SImode, xop0,
- GEN_INT (n)), NULL_RTX);
+ val = force_operand (plus_constant (xop0, n), NULL_RTX);
emit_move_insn (base_reg, val);
- x = (low_n == 0 ? base_reg
- : gen_rtx_PLUS (SImode, base_reg, GEN_INT (low_n)));
+ x = plus_constant (base_reg, low_n);
}
else if (xop0 != XEXP (x, 0) || xop1 != XEXP (x, 1))
x = gen_rtx_PLUS (SImode, xop0, xop1);
@@ -3101,6 +4059,34 @@ arm_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode)
x = gen_rtx_MINUS (SImode, xop0, xop1);
}
+ /* Make sure to take full advantage of the pre-indexed addressing mode
+ with absolute addresses which often allows for the base register to
+ be factorized for multiple adjacent memory references, and it might
+ even allows for the mini pool to be avoided entirely. */
+ else if (GET_CODE (x) == CONST_INT && optimize > 0)
+ {
+ unsigned int bits;
+ HOST_WIDE_INT mask, base, index;
+ rtx base_reg;
+
+ /* ldr and ldrb can use a 12 bit index, ldrsb and the rest can only
+ use a 8 bit index. So let's use a 12 bit index for SImode only and
+ hope that arm_gen_constant will enable ldrb to use more bits. */
+ bits = (mode == SImode) ? 12 : 8;
+ mask = (1 << bits) - 1;
+ base = INTVAL (x) & ~mask;
+ index = INTVAL (x) & mask;
+ if (bit_count (base & 0xffffffff) > (32 - bits)/2)
+ {
+ /* It'll most probably be more efficient to generate the base
+ with more bits set and use a negative index instead. */
+ base |= mask;
+ index -= mask;
+ }
+ base_reg = force_reg (SImode, GEN_INT (base));
+ x = plus_constant (base_reg, index);
+ }
+
if (flag_pic)
{
/* We need to find and carefully transform any SYMBOL and LABEL
@@ -3114,8 +4100,164 @@ arm_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode)
return x;
}
-
+/* Try machine-dependent ways of modifying an illegitimate Thumb address
+ to be legitimate. If we find one, return the new, valid address. */
+rtx
+thumb_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode)
+{
+ if (arm_tls_symbol_p (x))
+ return legitimize_tls_address (x, NULL_RTX);
+
+ if (GET_CODE (x) == PLUS
+ && GET_CODE (XEXP (x, 1)) == CONST_INT
+ && (INTVAL (XEXP (x, 1)) >= 32 * GET_MODE_SIZE (mode)
+ || INTVAL (XEXP (x, 1)) < 0))
+ {
+ rtx xop0 = XEXP (x, 0);
+ rtx xop1 = XEXP (x, 1);
+ HOST_WIDE_INT offset = INTVAL (xop1);
+
+ /* Try and fold the offset into a biasing of the base register and
+ then offsetting that. Don't do this when optimizing for space
+ since it can cause too many CSEs. */
+ if (optimize_size && offset >= 0
+ && offset < 256 + 31 * GET_MODE_SIZE (mode))
+ {
+ HOST_WIDE_INT delta;
+
+ if (offset >= 256)
+ delta = offset - (256 - GET_MODE_SIZE (mode));
+ else if (offset < 32 * GET_MODE_SIZE (mode) + 8)
+ delta = 31 * GET_MODE_SIZE (mode);
+ else
+ delta = offset & (~31 * GET_MODE_SIZE (mode));
+
+ xop0 = force_operand (plus_constant (xop0, offset - delta),
+ NULL_RTX);
+ x = plus_constant (xop0, delta);
+ }
+ else if (offset < 0 && offset > -256)
+ /* Small negative offsets are best done with a subtract before the
+ dereference, forcing these into a register normally takes two
+ instructions. */
+ x = force_operand (x, NULL_RTX);
+ else
+ {
+ /* For the remaining cases, force the constant into a register. */
+ xop1 = force_reg (SImode, xop1);
+ x = gen_rtx_PLUS (SImode, xop0, xop1);
+ }
+ }
+ else if (GET_CODE (x) == PLUS
+ && s_register_operand (XEXP (x, 1), SImode)
+ && !s_register_operand (XEXP (x, 0), SImode))
+ {
+ rtx xop0 = force_operand (XEXP (x, 0), NULL_RTX);
+
+ x = gen_rtx_PLUS (SImode, xop0, XEXP (x, 1));
+ }
+
+ if (flag_pic)
+ {
+ /* We need to find and carefully transform any SYMBOL and LABEL
+ references; so go back to the original address expression. */
+ rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX);
+
+ if (new_x != orig_x)
+ x = new_x;
+ }
+
+ return x;
+}
+
+rtx
+thumb_legitimize_reload_address (rtx *x_p,
+ enum machine_mode mode,
+ int opnum, int type,
+ int ind_levels ATTRIBUTE_UNUSED)
+{
+ rtx x = *x_p;
+
+ if (GET_CODE (x) == PLUS
+ && GET_MODE_SIZE (mode) < 4
+ && REG_P (XEXP (x, 0))
+ && XEXP (x, 0) == stack_pointer_rtx
+ && GET_CODE (XEXP (x, 1)) == CONST_INT
+ && !thumb_legitimate_offset_p (mode, INTVAL (XEXP (x, 1))))
+ {
+ rtx orig_x = x;
+
+ x = copy_rtx (x);
+ push_reload (orig_x, NULL_RTX, x_p, NULL, MODE_BASE_REG_CLASS (mode),
+ Pmode, VOIDmode, 0, 0, opnum, type);
+ return x;
+ }
+
+ /* If both registers are hi-regs, then it's better to reload the
+ entire expression rather than each register individually. That
+ only requires one reload register rather than two. */
+ if (GET_CODE (x) == PLUS
+ && REG_P (XEXP (x, 0))
+ && REG_P (XEXP (x, 1))
+ && !REG_MODE_OK_FOR_REG_BASE_P (XEXP (x, 0), mode)
+ && !REG_MODE_OK_FOR_REG_BASE_P (XEXP (x, 1), mode))
+ {
+ rtx orig_x = x;
+
+ x = copy_rtx (x);
+ push_reload (orig_x, NULL_RTX, x_p, NULL, MODE_BASE_REG_CLASS (mode),
+ Pmode, VOIDmode, 0, 0, opnum, type);
+ return x;
+ }
+
+ return NULL;
+}
+
+/* Test for various thread-local symbols. */
+
+/* Return TRUE if X is a thread-local symbol. */
+
+static bool
+arm_tls_symbol_p (rtx x)
+{
+ if (! TARGET_HAVE_TLS)
+ return false;
+
+ if (GET_CODE (x) != SYMBOL_REF)
+ return false;
+
+ return SYMBOL_REF_TLS_MODEL (x) != 0;
+}
+
+/* Helper for arm_tls_referenced_p. */
+
+static int
+arm_tls_operand_p_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
+{
+ if (GET_CODE (*x) == SYMBOL_REF)
+ return SYMBOL_REF_TLS_MODEL (*x) != 0;
+
+ /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
+ TLS offsets, not real symbol references. */
+ if (GET_CODE (*x) == UNSPEC
+ && XINT (*x, 1) == UNSPEC_TLS)
+ return -1;
+
+ return 0;
+}
+
+/* Return TRUE if X contains any TLS symbol references. */
+
+bool
+arm_tls_referenced_p (rtx x)
+{
+ if (! TARGET_HAVE_TLS)
+ return false;
+
+ return for_each_rtx (&x, arm_tls_operand_p_1, NULL);
+}
+
#define REG_OR_SUBREG_REG(X) \
(GET_CODE (X) == REG \
|| (GET_CODE (X) == SUBREG && GET_CODE (SUBREG_REG (X)) == REG))
@@ -3126,129 +4268,132 @@ arm_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode)
#ifndef COSTS_N_INSNS
#define COSTS_N_INSNS(N) ((N) * 4 - 2)
#endif
-/* Worker routine for arm_rtx_costs. */
static inline int
-arm_rtx_costs_1 (rtx x, enum rtx_code code, enum rtx_code outer)
+thumb_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer)
{
enum machine_mode mode = GET_MODE (x);
- enum rtx_code subcode;
- int extra_cost;
- if (TARGET_THUMB)
+ switch (code)
{
- switch (code)
+ case ASHIFT:
+ case ASHIFTRT:
+ case LSHIFTRT:
+ case ROTATERT:
+ case PLUS:
+ case MINUS:
+ case COMPARE:
+ case NEG:
+ case NOT:
+ return COSTS_N_INSNS (1);
+
+ case MULT:
+ if (GET_CODE (XEXP (x, 1)) == CONST_INT)
{
- case ASHIFT:
- case ASHIFTRT:
- case LSHIFTRT:
- case ROTATERT:
- case PLUS:
- case MINUS:
- case COMPARE:
- case NEG:
- case NOT:
- return COSTS_N_INSNS (1);
-
- case MULT:
- if (GET_CODE (XEXP (x, 1)) == CONST_INT)
- {
- int cycles = 0;
- unsigned HOST_WIDE_INT i = INTVAL (XEXP (x, 1));
-
- while (i)
- {
- i >>= 2;
- cycles++;
- }
- return COSTS_N_INSNS (2) + cycles;
+ int cycles = 0;
+ unsigned HOST_WIDE_INT i = INTVAL (XEXP (x, 1));
+
+ while (i)
+ {
+ i >>= 2;
+ cycles++;
}
- return COSTS_N_INSNS (1) + 16;
-
- case SET:
- return (COSTS_N_INSNS (1)
- + 4 * ((GET_CODE (SET_SRC (x)) == MEM)
- + GET_CODE (SET_DEST (x)) == MEM));
-
- case CONST_INT:
- if (outer == SET)
- {
- if ((unsigned HOST_WIDE_INT) INTVAL (x) < 256)
- return 0;
- if (thumb_shiftable_const (INTVAL (x)))
- return COSTS_N_INSNS (2);
- return COSTS_N_INSNS (3);
- }
- else if ((outer == PLUS || outer == COMPARE)
- && INTVAL (x) < 256 && INTVAL (x) > -256)
+ return COSTS_N_INSNS (2) + cycles;
+ }
+ return COSTS_N_INSNS (1) + 16;
+
+ case SET:
+ return (COSTS_N_INSNS (1)
+ + 4 * ((GET_CODE (SET_SRC (x)) == MEM)
+ + GET_CODE (SET_DEST (x)) == MEM));
+
+ case CONST_INT:
+ if (outer == SET)
+ {
+ if ((unsigned HOST_WIDE_INT) INTVAL (x) < 256)
return 0;
- else if (outer == AND
- && INTVAL (x) < 256 && INTVAL (x) >= -256)
- return COSTS_N_INSNS (1);
- else if (outer == ASHIFT || outer == ASHIFTRT
- || outer == LSHIFTRT)
- return 0;
- return COSTS_N_INSNS (2);
-
- case CONST:
- case CONST_DOUBLE:
- case LABEL_REF:
- case SYMBOL_REF:
+ if (thumb_shiftable_const (INTVAL (x)))
+ return COSTS_N_INSNS (2);
return COSTS_N_INSNS (3);
-
- case UDIV:
- case UMOD:
- case DIV:
- case MOD:
- return 100;
-
- case TRUNCATE:
- return 99;
+ }
+ else if ((outer == PLUS || outer == COMPARE)
+ && INTVAL (x) < 256 && INTVAL (x) > -256)
+ return 0;
+ else if (outer == AND
+ && INTVAL (x) < 256 && INTVAL (x) >= -256)
+ return COSTS_N_INSNS (1);
+ else if (outer == ASHIFT || outer == ASHIFTRT
+ || outer == LSHIFTRT)
+ return 0;
+ return COSTS_N_INSNS (2);
- case AND:
- case XOR:
- case IOR:
- /* XXX guess. */
- return 8;
+ case CONST:
+ case CONST_DOUBLE:
+ case LABEL_REF:
+ case SYMBOL_REF:
+ return COSTS_N_INSNS (3);
- case ADDRESSOF:
- case MEM:
- /* XXX another guess. */
- /* Memory costs quite a lot for the first word, but subsequent words
- load at the equivalent of a single insn each. */
- return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD)
- + ((GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
- ? 4 : 0));
-
- case IF_THEN_ELSE:
- /* XXX a guess. */
- if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
- return 14;
- return 2;
+ case UDIV:
+ case UMOD:
+ case DIV:
+ case MOD:
+ return 100;
+
+ case TRUNCATE:
+ return 99;
+
+ case AND:
+ case XOR:
+ case IOR:
+ /* XXX guess. */
+ return 8;
+
+ case MEM:
+ /* XXX another guess. */
+ /* Memory costs quite a lot for the first word, but subsequent words
+ load at the equivalent of a single insn each. */
+ return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD)
+ + ((GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
+ ? 4 : 0));
+
+ case IF_THEN_ELSE:
+ /* XXX a guess. */
+ if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
+ return 14;
+ return 2;
+
+ case ZERO_EXTEND:
+ /* XXX still guessing. */
+ switch (GET_MODE (XEXP (x, 0)))
+ {
+ case QImode:
+ return (1 + (mode == DImode ? 4 : 0)
+ + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
+
+ case HImode:
+ return (4 + (mode == DImode ? 4 : 0)
+ + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
+
+ case SImode:
+ return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
- case ZERO_EXTEND:
- /* XXX still guessing. */
- switch (GET_MODE (XEXP (x, 0)))
- {
- case QImode:
- return (1 + (mode == DImode ? 4 : 0)
- + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
-
- case HImode:
- return (4 + (mode == DImode ? 4 : 0)
- + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
-
- case SImode:
- return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
-
- default:
- return 99;
- }
-
default:
return 99;
}
+
+ default:
+ return 99;
}
-
+}
+
+
+/* Worker routine for arm_rtx_costs. */
+static inline int
+arm_rtx_costs_1 (rtx x, enum rtx_code code, enum rtx_code outer)
+{
+ enum machine_mode mode = GET_MODE (x);
+ enum rtx_code subcode;
+ int extra_cost;
+
switch (code)
{
case MEM:
@@ -3275,7 +4420,7 @@ arm_rtx_costs_1 (rtx x, enum rtx_code code, enum rtx_code outer)
case ASHIFT: case LSHIFTRT: case ASHIFTRT:
if (mode == DImode)
return (8 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : 8)
- + ((GET_CODE (XEXP (x, 0)) == REG
+ + ((GET_CODE (XEXP (x, 0)) == REG
|| (GET_CODE (XEXP (x, 0)) == SUBREG
&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG))
? 0 : 8));
@@ -3300,11 +4445,11 @@ arm_rtx_costs_1 (rtx x, enum rtx_code code, enum rtx_code outer)
if (GET_MODE_CLASS (mode) == MODE_FLOAT)
return (2 + ((REG_OR_SUBREG_REG (XEXP (x, 1))
|| (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
- && const_double_rtx_ok_for_fpa (XEXP (x, 1))))
+ && arm_const_double_rtx (XEXP (x, 1))))
? 0 : 8)
+ ((REG_OR_SUBREG_REG (XEXP (x, 0))
|| (GET_CODE (XEXP (x, 0)) == CONST_DOUBLE
- && const_double_rtx_ok_for_fpa (XEXP (x, 0))))
+ && arm_const_double_rtx (XEXP (x, 0))))
? 0 : 8));
if (((GET_CODE (XEXP (x, 0)) == CONST_INT
@@ -3324,16 +4469,24 @@ arm_rtx_costs_1 (rtx x, enum rtx_code code, enum rtx_code outer)
return 1;
/* Fall through */
- case PLUS:
+ case PLUS:
+ if (GET_CODE (XEXP (x, 0)) == MULT)
+ {
+ extra_cost = rtx_cost (XEXP (x, 0), code);
+ if (!REG_OR_SUBREG_REG (XEXP (x, 1)))
+ extra_cost += 4 * ARM_NUM_REGS (mode);
+ return extra_cost;
+ }
+
if (GET_MODE_CLASS (mode) == MODE_FLOAT)
return (2 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8)
+ ((REG_OR_SUBREG_REG (XEXP (x, 1))
|| (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
- && const_double_rtx_ok_for_fpa (XEXP (x, 1))))
+ && arm_const_double_rtx (XEXP (x, 1))))
? 0 : 8));
/* Fall through */
- case AND: case XOR: case IOR:
+ case AND: case XOR: case IOR:
extra_cost = 0;
/* Normally the frame registers will be spilt into reg+const during
@@ -3379,65 +4532,11 @@ arm_rtx_costs_1 (rtx x, enum rtx_code code, enum rtx_code outer)
return 8;
case MULT:
- /* There is no point basing this on the tuning, since it is always the
- fast variant if it exists at all. */
- if (arm_fast_multiply && mode == DImode
- && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1)))
- && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
- || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
- return 8;
-
- if (GET_MODE_CLASS (mode) == MODE_FLOAT
- || mode == DImode)
- return 30;
-
- if (GET_CODE (XEXP (x, 1)) == CONST_INT)
- {
- unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1))
- & (unsigned HOST_WIDE_INT) 0xffffffff);
- int cost, const_ok = const_ok_for_arm (i);
- int j, booth_unit_size;
-
- if (arm_tune_xscale)
- {
- unsigned HOST_WIDE_INT masked_const;
-
- /* The cost will be related to two insns.
- First a load of the constant (MOV or LDR), then a multiply. */
- cost = 2;
- if (! const_ok)
- cost += 1; /* LDR is probably more expensive because
- of longer result latency. */
- masked_const = i & 0xffff8000;
- if (masked_const != 0 && masked_const != 0xffff8000)
- {
- masked_const = i & 0xf8000000;
- if (masked_const == 0 || masked_const == 0xf8000000)
- cost += 1;
- else
- cost += 2;
- }
- return cost;
- }
-
- /* Tune as appropriate. */
- cost = const_ok ? 4 : 8;
- booth_unit_size = ((tune_flags & FL_FAST_MULT) ? 8 : 2);
- for (j = 0; i && j < 32; j += booth_unit_size)
- {
- i >>= booth_unit_size;
- cost += 2;
- }
-
- return cost;
- }
-
- return (((tune_flags & FL_FAST_MULT) ? 8 : 30)
- + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4)
- + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4));
+ /* This should have been handled by the CPU specific routines. */
+ gcc_unreachable ();
case TRUNCATE:
- if (arm_fast_multiply && mode == SImode
+ if (arm_arch3m && mode == SImode
&& GET_CODE (XEXP (x, 0)) == LSHIFTRT
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
&& (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0))
@@ -3495,48 +4594,527 @@ arm_rtx_costs_1 (rtx x, enum rtx_code code, enum rtx_code outer)
return 1;
default:
- break;
+ gcc_unreachable ();
}
- abort ();
+ gcc_unreachable ();
- case CONST_INT:
- if (const_ok_for_arm (INTVAL (x)))
- return outer == SET ? 2 : -1;
- else if (outer == AND
- && const_ok_for_arm (~INTVAL (x)))
- return -1;
- else if ((outer == COMPARE
- || outer == PLUS || outer == MINUS)
- && const_ok_for_arm (-INTVAL (x)))
- return -1;
- else
+ case CONST_INT:
+ if (const_ok_for_arm (INTVAL (x)))
+ return outer == SET ? 2 : -1;
+ else if (outer == AND
+ && const_ok_for_arm (~INTVAL (x)))
+ return -1;
+ else if ((outer == COMPARE
+ || outer == PLUS || outer == MINUS)
+ && const_ok_for_arm (-INTVAL (x)))
+ return -1;
+ else
return 5;
-
- case CONST:
- case LABEL_REF:
- case SYMBOL_REF:
+
+ case CONST:
+ case LABEL_REF:
+ case SYMBOL_REF:
return 6;
-
- case CONST_DOUBLE:
- if (const_double_rtx_ok_for_fpa (x))
- return outer == SET ? 2 : -1;
- else if ((outer == COMPARE || outer == PLUS)
- && neg_const_double_rtx_ok_for_fpa (x))
- return -1;
+
+ case CONST_DOUBLE:
+ if (arm_const_double_rtx (x))
+ return outer == SET ? 2 : -1;
+ else if ((outer == COMPARE || outer == PLUS)
+ && neg_const_double_rtx_ok_for_fpa (x))
+ return -1;
return 7;
-
+
default:
return 99;
}
}
+/* RTX costs when optimizing for size. */
static bool
-arm_rtx_costs (rtx x, int code, int outer_code, int *total)
+arm_size_rtx_costs (rtx x, int code, int outer_code, int *total)
{
- *total = arm_rtx_costs_1 (x, code, outer_code);
- return true;
+ enum machine_mode mode = GET_MODE (x);
+
+ if (TARGET_THUMB)
+ {
+ /* XXX TBD. For now, use the standard costs. */
+ *total = thumb_rtx_costs (x, code, outer_code);
+ return true;
+ }
+
+ switch (code)
+ {
+ case MEM:
+ /* A memory access costs 1 insn if the mode is small, or the address is
+ a single register, otherwise it costs one insn per word. */
+ if (REG_P (XEXP (x, 0)))
+ *total = COSTS_N_INSNS (1);
+ else
+ *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
+ return true;
+
+ case DIV:
+ case MOD:
+ case UDIV:
+ case UMOD:
+ /* Needs a libcall, so it costs about this. */
+ *total = COSTS_N_INSNS (2);
+ return false;
+
+ case ROTATE:
+ if (mode == SImode && GET_CODE (XEXP (x, 1)) == REG)
+ {
+ *total = COSTS_N_INSNS (2) + rtx_cost (XEXP (x, 0), code);
+ return true;
+ }
+ /* Fall through */
+ case ROTATERT:
+ case ASHIFT:
+ case LSHIFTRT:
+ case ASHIFTRT:
+ if (mode == DImode && GET_CODE (XEXP (x, 1)) == CONST_INT)
+ {
+ *total = COSTS_N_INSNS (3) + rtx_cost (XEXP (x, 0), code);
+ return true;
+ }
+ else if (mode == SImode)
+ {
+ *total = COSTS_N_INSNS (1) + rtx_cost (XEXP (x, 0), code);
+ /* Slightly disparage register shifts, but not by much. */
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ *total += 1 + rtx_cost (XEXP (x, 1), code);
+ return true;
+ }
+
+ /* Needs a libcall. */
+ *total = COSTS_N_INSNS (2);
+ return false;
+
+ case MINUS:
+ if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
+ {
+ *total = COSTS_N_INSNS (1);
+ return false;
+ }
+
+ if (mode == SImode)
+ {
+ enum rtx_code subcode0 = GET_CODE (XEXP (x, 0));
+ enum rtx_code subcode1 = GET_CODE (XEXP (x, 1));
+
+ if (subcode0 == ROTATE || subcode0 == ROTATERT || subcode0 == ASHIFT
+ || subcode0 == LSHIFTRT || subcode0 == ASHIFTRT
+ || subcode1 == ROTATE || subcode1 == ROTATERT
+ || subcode1 == ASHIFT || subcode1 == LSHIFTRT
+ || subcode1 == ASHIFTRT)
+ {
+ /* It's just the cost of the two operands. */
+ *total = 0;
+ return false;
+ }
+
+ *total = COSTS_N_INSNS (1);
+ return false;
+ }
+
+ *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
+ return false;
+
+ case PLUS:
+ if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
+ {
+ *total = COSTS_N_INSNS (1);
+ return false;
+ }
+
+ /* Fall through */
+ case AND: case XOR: case IOR:
+ if (mode == SImode)
+ {
+ enum rtx_code subcode = GET_CODE (XEXP (x, 0));
+
+ if (subcode == ROTATE || subcode == ROTATERT || subcode == ASHIFT
+ || subcode == LSHIFTRT || subcode == ASHIFTRT
+ || (code == AND && subcode == NOT))
+ {
+ /* It's just the cost of the two operands. */
+ *total = 0;
+ return false;
+ }
+ }
+
+ *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
+ return false;
+
+ case MULT:
+ *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
+ return false;
+
+ case NEG:
+ if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
+ *total = COSTS_N_INSNS (1);
+ /* Fall through */
+ case NOT:
+ *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
+
+ return false;
+
+ case IF_THEN_ELSE:
+ *total = 0;
+ return false;
+
+ case COMPARE:
+ if (cc_register (XEXP (x, 0), VOIDmode))
+ * total = 0;
+ else
+ *total = COSTS_N_INSNS (1);
+ return false;
+
+ case ABS:
+ if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
+ *total = COSTS_N_INSNS (1);
+ else
+ *total = COSTS_N_INSNS (1 + ARM_NUM_REGS (mode));
+ return false;
+
+ case SIGN_EXTEND:
+ *total = 0;
+ if (GET_MODE_SIZE (GET_MODE (XEXP (x, 0))) < 4)
+ {
+ if (!(arm_arch4 && MEM_P (XEXP (x, 0))))
+ *total += COSTS_N_INSNS (arm_arch6 ? 1 : 2);
+ }
+ if (mode == DImode)
+ *total += COSTS_N_INSNS (1);
+ return false;
+
+ case ZERO_EXTEND:
+ *total = 0;
+ if (!(arm_arch4 && MEM_P (XEXP (x, 0))))
+ {
+ switch (GET_MODE (XEXP (x, 0)))
+ {
+ case QImode:
+ *total += COSTS_N_INSNS (1);
+ break;
+
+ case HImode:
+ *total += COSTS_N_INSNS (arm_arch6 ? 1 : 2);
+
+ case SImode:
+ break;
+
+ default:
+ *total += COSTS_N_INSNS (2);
+ }
+ }
+
+ if (mode == DImode)
+ *total += COSTS_N_INSNS (1);
+
+ return false;
+
+ case CONST_INT:
+ if (const_ok_for_arm (INTVAL (x)))
+ *total = COSTS_N_INSNS (outer_code == SET ? 1 : 0);
+ else if (const_ok_for_arm (~INTVAL (x)))
+ *total = COSTS_N_INSNS (outer_code == AND ? 0 : 1);
+ else if (const_ok_for_arm (-INTVAL (x)))
+ {
+ if (outer_code == COMPARE || outer_code == PLUS
+ || outer_code == MINUS)
+ *total = 0;
+ else
+ *total = COSTS_N_INSNS (1);
+ }
+ else
+ *total = COSTS_N_INSNS (2);
+ return true;
+
+ case CONST:
+ case LABEL_REF:
+ case SYMBOL_REF:
+ *total = COSTS_N_INSNS (2);
+ return true;
+
+ case CONST_DOUBLE:
+ *total = COSTS_N_INSNS (4);
+ return true;
+
+ default:
+ if (mode != VOIDmode)
+ *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
+ else
+ *total = COSTS_N_INSNS (4); /* How knows? */
+ return false;
+ }
+}
+
+/* RTX costs for cores with a slow MUL implementation. */
+
+static bool
+arm_slowmul_rtx_costs (rtx x, int code, int outer_code, int *total)
+{
+ enum machine_mode mode = GET_MODE (x);
+
+ if (TARGET_THUMB)
+ {
+ *total = thumb_rtx_costs (x, code, outer_code);
+ return true;
+ }
+
+ switch (code)
+ {
+ case MULT:
+ if (GET_MODE_CLASS (mode) == MODE_FLOAT
+ || mode == DImode)
+ {
+ *total = 30;
+ return true;
+ }
+
+ if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+ {
+ unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1))
+ & (unsigned HOST_WIDE_INT) 0xffffffff);
+ int cost, const_ok = const_ok_for_arm (i);
+ int j, booth_unit_size;
+
+ /* Tune as appropriate. */
+ cost = const_ok ? 4 : 8;
+ booth_unit_size = 2;
+ for (j = 0; i && j < 32; j += booth_unit_size)
+ {
+ i >>= booth_unit_size;
+ cost += 2;
+ }
+
+ *total = cost;
+ return true;
+ }
+
+ *total = 30 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4)
+ + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4);
+ return true;
+
+ default:
+ *total = arm_rtx_costs_1 (x, code, outer_code);
+ return true;
+ }
}
+
+/* RTX cost for cores with a fast multiply unit (M variants). */
+
+static bool
+arm_fastmul_rtx_costs (rtx x, int code, int outer_code, int *total)
+{
+ enum machine_mode mode = GET_MODE (x);
+
+ if (TARGET_THUMB)
+ {
+ *total = thumb_rtx_costs (x, code, outer_code);
+ return true;
+ }
+
+ switch (code)
+ {
+ case MULT:
+ /* There is no point basing this on the tuning, since it is always the
+ fast variant if it exists at all. */
+ if (mode == DImode
+ && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1)))
+ && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
+ || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
+ {
+ *total = 8;
+ return true;
+ }
+
+
+ if (GET_MODE_CLASS (mode) == MODE_FLOAT
+ || mode == DImode)
+ {
+ *total = 30;
+ return true;
+ }
+
+ if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+ {
+ unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1))
+ & (unsigned HOST_WIDE_INT) 0xffffffff);
+ int cost, const_ok = const_ok_for_arm (i);
+ int j, booth_unit_size;
+
+ /* Tune as appropriate. */
+ cost = const_ok ? 4 : 8;
+ booth_unit_size = 8;
+ for (j = 0; i && j < 32; j += booth_unit_size)
+ {
+ i >>= booth_unit_size;
+ cost += 2;
+ }
+
+ *total = cost;
+ return true;
+ }
+
+ *total = 8 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4)
+ + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4);
+ return true;
+
+ default:
+ *total = arm_rtx_costs_1 (x, code, outer_code);
+ return true;
+ }
+}
+
+
+/* RTX cost for XScale CPUs. */
+
+static bool
+arm_xscale_rtx_costs (rtx x, int code, int outer_code, int *total)
+{
+ enum machine_mode mode = GET_MODE (x);
+
+ if (TARGET_THUMB)
+ {
+ *total = thumb_rtx_costs (x, code, outer_code);
+ return true;
+ }
+
+ switch (code)
+ {
+ case MULT:
+ /* There is no point basing this on the tuning, since it is always the
+ fast variant if it exists at all. */
+ if (mode == DImode
+ && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1)))
+ && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
+ || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
+ {
+ *total = 8;
+ return true;
+ }
+
+
+ if (GET_MODE_CLASS (mode) == MODE_FLOAT
+ || mode == DImode)
+ {
+ *total = 30;
+ return true;
+ }
+
+ if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+ {
+ unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1))
+ & (unsigned HOST_WIDE_INT) 0xffffffff);
+ int cost, const_ok = const_ok_for_arm (i);
+ unsigned HOST_WIDE_INT masked_const;
+
+ /* The cost will be related to two insns.
+ First a load of the constant (MOV or LDR), then a multiply. */
+ cost = 2;
+ if (! const_ok)
+ cost += 1; /* LDR is probably more expensive because
+ of longer result latency. */
+ masked_const = i & 0xffff8000;
+ if (masked_const != 0 && masked_const != 0xffff8000)
+ {
+ masked_const = i & 0xf8000000;
+ if (masked_const == 0 || masked_const == 0xf8000000)
+ cost += 1;
+ else
+ cost += 2;
+ }
+ *total = cost;
+ return true;
+ }
+
+ *total = 8 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4)
+ + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4);
+ return true;
+
+ case COMPARE:
+ /* A COMPARE of a MULT is slow on XScale; the muls instruction
+ will stall until the multiplication is complete. */
+ if (GET_CODE (XEXP (x, 0)) == MULT)
+ *total = 4 + rtx_cost (XEXP (x, 0), code);
+ else
+ *total = arm_rtx_costs_1 (x, code, outer_code);
+ return true;
+
+ default:
+ *total = arm_rtx_costs_1 (x, code, outer_code);
+ return true;
+ }
+}
+
+
+/* RTX costs for 9e (and later) cores. */
+
+static bool
+arm_9e_rtx_costs (rtx x, int code, int outer_code, int *total)
+{
+ enum machine_mode mode = GET_MODE (x);
+ int nonreg_cost;
+ int cost;
+
+ if (TARGET_THUMB)
+ {
+ switch (code)
+ {
+ case MULT:
+ *total = COSTS_N_INSNS (3);
+ return true;
+
+ default:
+ *total = thumb_rtx_costs (x, code, outer_code);
+ return true;
+ }
+ }
+
+ switch (code)
+ {
+ case MULT:
+ /* There is no point basing this on the tuning, since it is always the
+ fast variant if it exists at all. */
+ if (mode == DImode
+ && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1)))
+ && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
+ || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
+ {
+ *total = 3;
+ return true;
+ }
+
+
+ if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+ {
+ *total = 30;
+ return true;
+ }
+ if (mode == DImode)
+ {
+ cost = 7;
+ nonreg_cost = 8;
+ }
+ else
+ {
+ cost = 2;
+ nonreg_cost = 4;
+ }
+
+
+ *total = cost + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : nonreg_cost)
+ + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : nonreg_cost);
+ return true;
+
+ default:
+ *total = arm_rtx_costs_1 (x, code, outer_code);
+ return true;
+ }
+}
/* All address computations that can be done are free, but rtx cost returns
the same for practically all of them. So we weight the different types
of address here in the order (most pref first):
@@ -3553,13 +5131,10 @@ arm_arm_address_cost (rtx x)
if (c == PLUS || c == MINUS)
{
- char cl0 = GET_RTX_CLASS (GET_CODE (XEXP (x, 0)));
- char cl1 = GET_RTX_CLASS (GET_CODE (XEXP (x, 1)));
-
if (GET_CODE (XEXP (x, 0)) == CONST_INT)
return 2;
- if (cl0 == '2' || cl0 == 'c' || cl1 == '2' || cl1 == 'c')
+ if (ARITHMETIC_P (XEXP (x, 0)) || ARITHMETIC_P (XEXP (x, 1)))
return 3;
return 4;
@@ -3590,12 +5165,6 @@ arm_address_cost (rtx x)
}
static int
-arm_use_dfa_pipeline_interface (void)
-{
- return true;
-}
-
-static int
arm_adjust_cost (rtx insn, rtx link, rtx dep, int cost)
{
rtx i_pat, d_pat;
@@ -3614,11 +5183,12 @@ arm_adjust_cost (rtx insn, rtx link, rtx dep, int cost)
operand for INSN. If we have a shifted input operand and the
instruction we depend on is another ALU instruction, then we may
have to account for an additional stall. */
- if (shift_opnum != 0 && attr_type == TYPE_NORMAL)
+ if (shift_opnum != 0
+ && (attr_type == TYPE_ALU_SHIFT || attr_type == TYPE_ALU_SHIFT_REG))
{
rtx shifted_operand;
int opno;
-
+
/* Get the shifted operand. */
extract_insn (insn);
shifted_operand = recog_data.operand[shift_opnum];
@@ -3659,9 +5229,9 @@ arm_adjust_cost (rtx insn, rtx link, rtx dep, int cost)
rtx src_mem = XEXP (SET_SRC (i_pat), 0);
/* This is a load after a store, there is no conflict if the load reads
from a cached area. Assume that loads from the stack, and from the
- constant pool are cached, and that others will miss. This is a
+ constant pool are cached, and that others will miss. This is a
hack. */
-
+
if ((GET_CODE (src_mem) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (src_mem))
|| reg_mentioned_p (stack_pointer_rtx, src_mem)
|| reg_mentioned_p (frame_pointer_rtx, src_mem)
@@ -3672,47 +5242,51 @@ arm_adjust_cost (rtx insn, rtx link, rtx dep, int cost)
return cost;
}
-static int fpa_consts_inited = 0;
+static int fp_consts_inited = 0;
-static const char * const strings_fpa[8] =
+/* Only zero is valid for VFP. Other values are also valid for FPA. */
+static const char * const strings_fp[8] =
{
"0", "1", "2", "3",
"4", "5", "0.5", "10"
};
-static REAL_VALUE_TYPE values_fpa[8];
+static REAL_VALUE_TYPE values_fp[8];
static void
-init_fpa_table (void)
+init_fp_table (void)
{
int i;
REAL_VALUE_TYPE r;
- for (i = 0; i < 8; i++)
+ if (TARGET_VFP)
+ fp_consts_inited = 1;
+ else
+ fp_consts_inited = 8;
+
+ for (i = 0; i < fp_consts_inited; i++)
{
- r = REAL_VALUE_ATOF (strings_fpa[i], DFmode);
- values_fpa[i] = r;
+ r = REAL_VALUE_ATOF (strings_fp[i], DFmode);
+ values_fp[i] = r;
}
-
- fpa_consts_inited = 1;
}
-/* Return TRUE if rtx X is a valid immediate FPA constant. */
+/* Return TRUE if rtx X is a valid immediate FP constant. */
int
-const_double_rtx_ok_for_fpa (rtx x)
+arm_const_double_rtx (rtx x)
{
REAL_VALUE_TYPE r;
int i;
-
- if (!fpa_consts_inited)
- init_fpa_table ();
-
+
+ if (!fp_consts_inited)
+ init_fp_table ();
+
REAL_VALUE_FROM_CONST_DOUBLE (r, x);
if (REAL_VALUE_MINUS_ZERO (r))
return 0;
- for (i = 0; i < 8; i++)
- if (REAL_VALUES_EQUAL (r, values_fpa[i]))
+ for (i = 0; i < fp_consts_inited; i++)
+ if (REAL_VALUES_EQUAL (r, values_fp[i]))
return 1;
return 0;
@@ -3724,17 +5298,17 @@ neg_const_double_rtx_ok_for_fpa (rtx x)
{
REAL_VALUE_TYPE r;
int i;
-
- if (!fpa_consts_inited)
- init_fpa_table ();
-
+
+ if (!fp_consts_inited)
+ init_fp_table ();
+
REAL_VALUE_FROM_CONST_DOUBLE (r, x);
r = REAL_VALUE_NEGATE (r);
if (REAL_VALUE_MINUS_ZERO (r))
return 0;
for (i = 0; i < 8; i++)
- if (REAL_VALUES_EQUAL (r, values_fpa[i]))
+ if (REAL_VALUES_EQUAL (r, values_fp[i]))
return 1;
return 0;
@@ -3742,244 +5316,6 @@ neg_const_double_rtx_ok_for_fpa (rtx x)
/* Predicates for `match_operand' and `match_operator'. */
-/* s_register_operand is the same as register_operand, but it doesn't accept
- (SUBREG (MEM)...).
-
- This function exists because at the time it was put in it led to better
- code. SUBREG(MEM) always needs a reload in the places where
- s_register_operand is used, and this seemed to lead to excessive
- reloading. */
-int
-s_register_operand (rtx op, enum machine_mode mode)
-{
- if (GET_MODE (op) != mode && mode != VOIDmode)
- return 0;
-
- if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
-
- /* We don't consider registers whose class is NO_REGS
- to be a register operand. */
- /* XXX might have to check for lo regs only for thumb ??? */
- return (GET_CODE (op) == REG
- && (REGNO (op) >= FIRST_PSEUDO_REGISTER
- || REGNO_REG_CLASS (REGNO (op)) != NO_REGS));
-}
-
-/* A hard register operand (even before reload. */
-int
-arm_hard_register_operand (rtx op, enum machine_mode mode)
-{
- if (GET_MODE (op) != mode && mode != VOIDmode)
- return 0;
-
- return (GET_CODE (op) == REG
- && REGNO (op) < FIRST_PSEUDO_REGISTER);
-}
-
-/* Only accept reg, subreg(reg), const_int. */
-int
-reg_or_int_operand (rtx op, enum machine_mode mode)
-{
- if (GET_CODE (op) == CONST_INT)
- return 1;
-
- if (GET_MODE (op) != mode && mode != VOIDmode)
- return 0;
-
- if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
-
- /* We don't consider registers whose class is NO_REGS
- to be a register operand. */
- return (GET_CODE (op) == REG
- && (REGNO (op) >= FIRST_PSEUDO_REGISTER
- || REGNO_REG_CLASS (REGNO (op)) != NO_REGS));
-}
-
-/* Return 1 if OP is an item in memory, given that we are in reload. */
-int
-arm_reload_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- int regno = true_regnum (op);
-
- return (!CONSTANT_P (op)
- && (regno == -1
- || (GET_CODE (op) == REG
- && REGNO (op) >= FIRST_PSEUDO_REGISTER)));
-}
-
-/* Return 1 if OP is a valid memory address, but not valid for a signed byte
- memory access (architecture V4).
- MODE is QImode if called when computing constraints, or VOIDmode when
- emitting patterns. In this latter case we cannot use memory_operand()
- because it will fail on badly formed MEMs, which is precisely what we are
- trying to catch. */
-int
-bad_signed_byte_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- if (GET_CODE (op) != MEM)
- return 0;
-
- op = XEXP (op, 0);
-
- /* A sum of anything more complex than reg + reg or reg + const is bad. */
- if ((GET_CODE (op) == PLUS || GET_CODE (op) == MINUS)
- && (!s_register_operand (XEXP (op, 0), VOIDmode)
- || (!s_register_operand (XEXP (op, 1), VOIDmode)
- && GET_CODE (XEXP (op, 1)) != CONST_INT)))
- return 1;
-
- /* Big constants are also bad. */
- if (GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT
- && (INTVAL (XEXP (op, 1)) > 0xff
- || -INTVAL (XEXP (op, 1)) > 0xff))
- return 1;
-
- /* Everything else is good, or can will automatically be made so. */
- return 0;
-}
-
-/* Return TRUE for valid operands for the rhs of an ARM instruction. */
-int
-arm_rhs_operand (rtx op, enum machine_mode mode)
-{
- return (s_register_operand (op, mode)
- || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op))));
-}
-
-/* Return TRUE for valid operands for the
- rhs of an ARM instruction, or a load. */
-int
-arm_rhsm_operand (rtx op, enum machine_mode mode)
-{
- return (s_register_operand (op, mode)
- || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op)))
- || memory_operand (op, mode));
-}
-
-/* Return TRUE for valid operands for the rhs of an ARM instruction, or if a
- constant that is valid when negated. */
-int
-arm_add_operand (rtx op, enum machine_mode mode)
-{
- if (TARGET_THUMB)
- return thumb_cmp_operand (op, mode);
-
- return (s_register_operand (op, mode)
- || (GET_CODE (op) == CONST_INT
- && (const_ok_for_arm (INTVAL (op))
- || const_ok_for_arm (-INTVAL (op)))));
-}
-
-/* Return TRUE for valid ARM constants (or when valid if negated). */
-int
-arm_addimm_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return (GET_CODE (op) == CONST_INT
- && (const_ok_for_arm (INTVAL (op))
- || const_ok_for_arm (-INTVAL (op))));
-}
-
-int
-arm_not_operand (rtx op, enum machine_mode mode)
-{
- return (s_register_operand (op, mode)
- || (GET_CODE (op) == CONST_INT
- && (const_ok_for_arm (INTVAL (op))
- || const_ok_for_arm (~INTVAL (op)))));
-}
-
-/* Return TRUE if the operand is a memory reference which contains an
- offsettable address. */
-int
-offsettable_memory_operand (rtx op, enum machine_mode mode)
-{
- if (mode == VOIDmode)
- mode = GET_MODE (op);
-
- return (mode == GET_MODE (op)
- && GET_CODE (op) == MEM
- && offsettable_address_p (reload_completed | reload_in_progress,
- mode, XEXP (op, 0)));
-}
-
-/* Return TRUE if the operand is a memory reference which is, or can be
- made word aligned by adjusting the offset. */
-int
-alignable_memory_operand (rtx op, enum machine_mode mode)
-{
- rtx reg;
-
- if (mode == VOIDmode)
- mode = GET_MODE (op);
-
- if (mode != GET_MODE (op) || GET_CODE (op) != MEM)
- return 0;
-
- op = XEXP (op, 0);
-
- return ((GET_CODE (reg = op) == REG
- || (GET_CODE (op) == SUBREG
- && GET_CODE (reg = SUBREG_REG (op)) == REG)
- || (GET_CODE (op) == PLUS
- && GET_CODE (XEXP (op, 1)) == CONST_INT
- && (GET_CODE (reg = XEXP (op, 0)) == REG
- || (GET_CODE (XEXP (op, 0)) == SUBREG
- && GET_CODE (reg = SUBREG_REG (XEXP (op, 0))) == REG))))
- && REGNO_POINTER_ALIGN (REGNO (reg)) >= 32);
-}
-
-/* Similar to s_register_operand, but does not allow hard integer
- registers. */
-int
-f_register_operand (rtx op, enum machine_mode mode)
-{
- if (GET_MODE (op) != mode && mode != VOIDmode)
- return 0;
-
- if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
-
- /* We don't consider registers whose class is NO_REGS
- to be a register operand. */
- return (GET_CODE (op) == REG
- && (REGNO (op) >= FIRST_PSEUDO_REGISTER
- || REGNO_REG_CLASS (REGNO (op)) == FPA_REGS));
-}
-
-/* Return TRUE for valid operands for the rhs of an FPA instruction. */
-int
-fpa_rhs_operand (rtx op, enum machine_mode mode)
-{
- if (s_register_operand (op, mode))
- return TRUE;
-
- if (GET_MODE (op) != mode && mode != VOIDmode)
- return FALSE;
-
- if (GET_CODE (op) == CONST_DOUBLE)
- return const_double_rtx_ok_for_fpa (op);
-
- return FALSE;
-}
-
-int
-fpa_add_operand (rtx op, enum machine_mode mode)
-{
- if (s_register_operand (op, mode))
- return TRUE;
-
- if (GET_MODE (op) != mode && mode != VOIDmode)
- return FALSE;
-
- if (GET_CODE (op) == CONST_DOUBLE)
- return (const_double_rtx_ok_for_fpa (op)
- || neg_const_double_rtx_ok_for_fpa (op));
-
- return FALSE;
-}
-
/* Return nonzero if OP is a valid Cirrus memory address pattern. */
int
cirrus_memory_offset (rtx op)
@@ -4017,43 +5353,70 @@ cirrus_memory_offset (rtx op)
return 0;
}
-/* Return nonzero if OP is a Cirrus or general register. */
+/* Return TRUE if OP is a valid coprocessor memory address pattern.
+ WB if true if writeback address modes are allowed. */
+
int
-cirrus_register_operand (rtx op, enum machine_mode mode)
+arm_coproc_mem_operand (rtx op, bool wb)
{
- if (GET_MODE (op) != mode && mode != VOIDmode)
- return FALSE;
-
- if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
+ rtx ind;
- return (GET_CODE (op) == REG
- && (REGNO_REG_CLASS (REGNO (op)) == CIRRUS_REGS
- || REGNO_REG_CLASS (REGNO (op)) == GENERAL_REGS));
-}
+ /* Reject eliminable registers. */
+ if (! (reload_in_progress || reload_completed)
+ && ( reg_mentioned_p (frame_pointer_rtx, op)
+ || reg_mentioned_p (arg_pointer_rtx, op)
+ || reg_mentioned_p (virtual_incoming_args_rtx, op)
+ || reg_mentioned_p (virtual_outgoing_args_rtx, op)
+ || reg_mentioned_p (virtual_stack_dynamic_rtx, op)
+ || reg_mentioned_p (virtual_stack_vars_rtx, op)))
+ return FALSE;
-/* Return nonzero if OP is a cirrus FP register. */
-int
-cirrus_fp_register (rtx op, enum machine_mode mode)
-{
- if (GET_MODE (op) != mode && mode != VOIDmode)
+ /* Constants are converted into offsets from labels. */
+ if (GET_CODE (op) != MEM)
return FALSE;
- if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
+ ind = XEXP (op, 0);
- return (GET_CODE (op) == REG
- && (REGNO (op) >= FIRST_PSEUDO_REGISTER
- || REGNO_REG_CLASS (REGNO (op)) == CIRRUS_REGS));
-}
+ if (reload_completed
+ && (GET_CODE (ind) == LABEL_REF
+ || (GET_CODE (ind) == CONST
+ && GET_CODE (XEXP (ind, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (ind, 0), 0)) == LABEL_REF
+ && GET_CODE (XEXP (XEXP (ind, 0), 1)) == CONST_INT)))
+ return TRUE;
-/* Return nonzero if OP is a 6bit constant (0..63). */
-int
-cirrus_shift_const (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return (GET_CODE (op) == CONST_INT
- && INTVAL (op) >= 0
- && INTVAL (op) < 64);
+ /* Match: (mem (reg)). */
+ if (GET_CODE (ind) == REG)
+ return arm_address_register_rtx_p (ind, 0);
+
+ /* Autoincremment addressing modes. */
+ if (wb
+ && (GET_CODE (ind) == PRE_INC
+ || GET_CODE (ind) == POST_INC
+ || GET_CODE (ind) == PRE_DEC
+ || GET_CODE (ind) == POST_DEC))
+ return arm_address_register_rtx_p (XEXP (ind, 0), 0);
+
+ if (wb
+ && (GET_CODE (ind) == POST_MODIFY || GET_CODE (ind) == PRE_MODIFY)
+ && arm_address_register_rtx_p (XEXP (ind, 0), 0)
+ && GET_CODE (XEXP (ind, 1)) == PLUS
+ && rtx_equal_p (XEXP (XEXP (ind, 1), 0), XEXP (ind, 0)))
+ ind = XEXP (ind, 1);
+
+ /* Match:
+ (plus (reg)
+ (const)). */
+ if (GET_CODE (ind) == PLUS
+ && GET_CODE (XEXP (ind, 0)) == REG
+ && REG_MODE_OK_FOR_BASE_P (XEXP (ind, 0), VOIDmode)
+ && GET_CODE (XEXP (ind, 1)) == CONST_INT
+ && INTVAL (XEXP (ind, 1)) > -1024
+ && INTVAL (XEXP (ind, 1)) < 1024
+ && (INTVAL (XEXP (ind, 1)) & 3) == 0)
+ return TRUE;
+
+ return FALSE;
}
/* Return true if X is a register that will be eliminated later on. */
@@ -4066,6 +5429,30 @@ arm_eliminable_register (rtx x)
&& REGNO (x) <= LAST_VIRTUAL_REGISTER));
}
+/* Return GENERAL_REGS if a scratch register required to reload x to/from
+ coprocessor registers. Otherwise return NO_REGS. */
+
+enum reg_class
+coproc_secondary_reload_class (enum machine_mode mode, rtx x, bool wb)
+{
+ if (arm_coproc_mem_operand (x, wb) || s_register_operand (x, mode))
+ return NO_REGS;
+
+ return GENERAL_REGS;
+}
+
+/* Values which must be returned in the most-significant end of the return
+ register. */
+
+static bool
+arm_return_in_msb (tree valtype)
+{
+ return (TARGET_AAPCS_BASED
+ && BYTES_BIG_ENDIAN
+ && (AGGREGATE_TYPE_P (valtype)
+ || TREE_CODE (valtype) == COMPLEX_TYPE));
+}
+
/* Returns TRUE if INSN is an "LDR REG, ADDR" instruction.
Use by the Cirrus Maverick code which has to workaround
a hardware bug triggered by such instructions. */
@@ -4107,7 +5494,7 @@ arm_cirrus_insn_p (rtx insn)
{
enum attr_cirrus attr;
- /* get_attr aborts on USE and CLOBBER. */
+ /* get_attr cannot accept USE or CLOBBER. */
if (!insn
|| GET_CODE (insn) != INSN
|| GET_CODE (PATTERN (insn)) == USE
@@ -4179,10 +5566,11 @@ cirrus_reorg (rtx first)
/* Get Arm register number for ldr insn. */
if (GET_CODE (lhs) == REG)
arm_regno = REGNO (lhs);
- else if (GET_CODE (rhs) == REG)
- arm_regno = REGNO (rhs);
else
- abort ();
+ {
+ gcc_assert (GET_CODE (rhs) == REG);
+ arm_regno = REGNO (rhs);
+ }
/* Next insn. */
first = next_nonnote_insn (first);
@@ -4208,7 +5596,7 @@ cirrus_reorg (rtx first)
}
}
- /* get_attr aborts on USE and CLOBBER. */
+ /* get_attr cannot accept USE or CLOBBER. */
if (!first
|| GET_CODE (first) != INSN
|| GET_CODE (PATTERN (first)) == USE
@@ -4238,262 +5626,6 @@ cirrus_reorg (rtx first)
}
}
-/* Return nonzero if OP is a constant power of two. */
-int
-power_of_two_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- if (GET_CODE (op) == CONST_INT)
- {
- HOST_WIDE_INT value = INTVAL (op);
-
- return value != 0 && (value & (value - 1)) == 0;
- }
-
- return FALSE;
-}
-
-/* Return TRUE for a valid operand of a DImode operation.
- Either: REG, SUBREG, CONST_DOUBLE or MEM(DImode_address).
- Note that this disallows MEM(REG+REG), but allows
- MEM(PRE/POST_INC/DEC(REG)). */
-int
-di_operand (rtx op, enum machine_mode mode)
-{
- if (s_register_operand (op, mode))
- return TRUE;
-
- if (mode != VOIDmode && GET_MODE (op) != VOIDmode && GET_MODE (op) != DImode)
- return FALSE;
-
- if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
-
- switch (GET_CODE (op))
- {
- case CONST_DOUBLE:
- case CONST_INT:
- return TRUE;
-
- case MEM:
- return memory_address_p (DImode, XEXP (op, 0));
-
- default:
- return FALSE;
- }
-}
-
-/* Like di_operand, but don't accept constants. */
-int
-nonimmediate_di_operand (rtx op, enum machine_mode mode)
-{
- if (s_register_operand (op, mode))
- return TRUE;
-
- if (mode != VOIDmode && GET_MODE (op) != VOIDmode && GET_MODE (op) != DImode)
- return FALSE;
-
- if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
-
- if (GET_CODE (op) == MEM)
- return memory_address_p (DImode, XEXP (op, 0));
-
- return FALSE;
-}
-
-/* Return TRUE for a valid operand of a DFmode operation when -msoft-float.
- Either: REG, SUBREG, CONST_DOUBLE or MEM(DImode_address).
- Note that this disallows MEM(REG+REG), but allows
- MEM(PRE/POST_INC/DEC(REG)). */
-int
-soft_df_operand (rtx op, enum machine_mode mode)
-{
- if (s_register_operand (op, mode))
- return TRUE;
-
- if (mode != VOIDmode && GET_MODE (op) != mode)
- return FALSE;
-
- if (GET_CODE (op) == SUBREG && CONSTANT_P (SUBREG_REG (op)))
- return FALSE;
-
- if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
-
- switch (GET_CODE (op))
- {
- case CONST_DOUBLE:
- return TRUE;
-
- case MEM:
- return memory_address_p (DFmode, XEXP (op, 0));
-
- default:
- return FALSE;
- }
-}
-
-/* Like soft_df_operand, but don't accept constants. */
-int
-nonimmediate_soft_df_operand (rtx op, enum machine_mode mode)
-{
- if (s_register_operand (op, mode))
- return TRUE;
-
- if (mode != VOIDmode && GET_MODE (op) != mode)
- return FALSE;
-
- if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
-
- if (GET_CODE (op) == MEM)
- return memory_address_p (DFmode, XEXP (op, 0));
- return FALSE;
-}
-
-/* Return TRUE for valid index operands. */
-int
-index_operand (rtx op, enum machine_mode mode)
-{
- return (s_register_operand (op, mode)
- || (immediate_operand (op, mode)
- && (GET_CODE (op) != CONST_INT
- || (INTVAL (op) < 4096 && INTVAL (op) > -4096))));
-}
-
-/* Return TRUE for valid shifts by a constant. This also accepts any
- power of two on the (somewhat overly relaxed) assumption that the
- shift operator in this case was a mult. */
-int
-const_shift_operand (rtx op, enum machine_mode mode)
-{
- return (power_of_two_operand (op, mode)
- || (immediate_operand (op, mode)
- && (GET_CODE (op) != CONST_INT
- || (INTVAL (op) < 32 && INTVAL (op) > 0))));
-}
-
-/* Return TRUE for arithmetic operators which can be combined with a multiply
- (shift). */
-int
-shiftable_operator (rtx x, enum machine_mode mode)
-{
- enum rtx_code code;
-
- if (GET_MODE (x) != mode)
- return FALSE;
-
- code = GET_CODE (x);
-
- return (code == PLUS || code == MINUS
- || code == IOR || code == XOR || code == AND);
-}
-
-/* Return TRUE for binary logical operators. */
-int
-logical_binary_operator (rtx x, enum machine_mode mode)
-{
- enum rtx_code code;
-
- if (GET_MODE (x) != mode)
- return FALSE;
-
- code = GET_CODE (x);
-
- return (code == IOR || code == XOR || code == AND);
-}
-
-/* Return TRUE for shift operators. */
-int
-shift_operator (rtx x,enum machine_mode mode)
-{
- enum rtx_code code;
-
- if (GET_MODE (x) != mode)
- return FALSE;
-
- code = GET_CODE (x);
-
- if (code == MULT)
- return power_of_two_operand (XEXP (x, 1), mode);
-
- return (code == ASHIFT || code == ASHIFTRT || code == LSHIFTRT
- || code == ROTATERT);
-}
-
-/* Return TRUE if x is EQ or NE. */
-int
-equality_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return GET_CODE (x) == EQ || GET_CODE (x) == NE;
-}
-
-/* Return TRUE if x is a comparison operator other than LTGT or UNEQ. */
-int
-arm_comparison_operator (rtx x, enum machine_mode mode)
-{
- return (comparison_operator (x, mode)
- && GET_CODE (x) != LTGT
- && GET_CODE (x) != UNEQ);
-}
-
-/* Return TRUE for SMIN SMAX UMIN UMAX operators. */
-int
-minmax_operator (rtx x, enum machine_mode mode)
-{
- enum rtx_code code = GET_CODE (x);
-
- if (GET_MODE (x) != mode)
- return FALSE;
-
- return code == SMIN || code == SMAX || code == UMIN || code == UMAX;
-}
-
-/* Return TRUE if this is the condition code register, if we aren't given
- a mode, accept any class CCmode register. */
-int
-cc_register (rtx x, enum machine_mode mode)
-{
- if (mode == VOIDmode)
- {
- mode = GET_MODE (x);
-
- if (GET_MODE_CLASS (mode) != MODE_CC)
- return FALSE;
- }
-
- if ( GET_MODE (x) == mode
- && GET_CODE (x) == REG
- && REGNO (x) == CC_REGNUM)
- return TRUE;
-
- return FALSE;
-}
-
-/* Return TRUE if this is the condition code register, if we aren't given
- a mode, accept any class CCmode register which indicates a dominance
- expression. */
-int
-dominant_cc_register (rtx x, enum machine_mode mode)
-{
- if (mode == VOIDmode)
- {
- mode = GET_MODE (x);
-
- if (GET_MODE_CLASS (mode) != MODE_CC)
- return FALSE;
- }
-
- if (mode != CC_DNEmode && mode != CC_DEQmode
- && mode != CC_DLEmode && mode != CC_DLTmode
- && mode != CC_DGEmode && mode != CC_DGTmode
- && mode != CC_DLEUmode && mode != CC_DLTUmode
- && mode != CC_DGEUmode && mode != CC_DGTUmode)
- return FALSE;
-
- return cc_register (x, mode);
-}
-
/* Return TRUE if X references a SYMBOL_REF. */
int
symbol_mentioned_p (rtx x)
@@ -4504,8 +5636,13 @@ symbol_mentioned_p (rtx x)
if (GET_CODE (x) == SYMBOL_REF)
return 1;
+ /* UNSPEC_TLS entries for a symbol include the SYMBOL_REF, but they
+ are constant offsets, not symbols. */
+ if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
+ return 0;
+
fmt = GET_RTX_FORMAT (GET_CODE (x));
-
+
for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
{
if (fmt[i] == 'E')
@@ -4533,6 +5670,11 @@ label_mentioned_p (rtx x)
if (GET_CODE (x) == LABEL_REF)
return 1;
+ /* UNSPEC_TLS entries for a symbol include a LABEL_REF for the referencing
+ instruction, but they are constant offsets, not symbols. */
+ if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
+ return 0;
+
fmt = GET_RTX_FORMAT (GET_CODE (x));
for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
{
@@ -4551,27 +5693,76 @@ label_mentioned_p (rtx x)
return 0;
}
+int
+tls_mentioned_p (rtx x)
+{
+ switch (GET_CODE (x))
+ {
+ case CONST:
+ return tls_mentioned_p (XEXP (x, 0));
+
+ case UNSPEC:
+ if (XINT (x, 1) == UNSPEC_TLS)
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/* Must not copy a SET whose source operand is PC-relative. */
+
+static bool
+arm_cannot_copy_insn_p (rtx insn)
+{
+ rtx pat = PATTERN (insn);
+
+ if (GET_CODE (pat) == PARALLEL
+ && GET_CODE (XVECEXP (pat, 0, 0)) == SET)
+ {
+ rtx rhs = SET_SRC (XVECEXP (pat, 0, 0));
+
+ if (GET_CODE (rhs) == UNSPEC
+ && XINT (rhs, 1) == UNSPEC_PIC_BASE)
+ return TRUE;
+
+ if (GET_CODE (rhs) == MEM
+ && GET_CODE (XEXP (rhs, 0)) == UNSPEC
+ && XINT (XEXP (rhs, 0), 1) == UNSPEC_PIC_BASE)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
enum rtx_code
minmax_code (rtx x)
{
enum rtx_code code = GET_CODE (x);
- if (code == SMAX)
- return GE;
- else if (code == SMIN)
- return LE;
- else if (code == UMIN)
- return LEU;
- else if (code == UMAX)
- return GEU;
-
- abort ();
+ switch (code)
+ {
+ case SMAX:
+ return GE;
+ case SMIN:
+ return LE;
+ case UMIN:
+ return LEU;
+ case UMAX:
+ return GEU;
+ default:
+ gcc_unreachable ();
+ }
}
/* Return 1 if memory locations are adjacent. */
int
adjacent_mem_locations (rtx a, rtx b)
{
+ /* We don't guarantee to preserve the order of these memory refs. */
+ if (volatile_refs_p (a) || volatile_refs_p (b))
+ return 0;
+
if ((GET_CODE (XEXP (a, 0)) == REG
|| (GET_CODE (XEXP (a, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (a, 0), 1)) == CONST_INT))
@@ -4611,6 +5802,17 @@ adjacent_mem_locations (rtx a, rtx b)
return 0;
val_diff = val1 - val0;
+
+ if (arm_ld_sched)
+ {
+ /* If the target has load delay slots, then there's no benefit
+ to using an ldm instruction unless the offset is zero and
+ we are optimizing for size. */
+ return (optimize_size && (REGNO (reg0) == REGNO (reg1))
+ && (val0 == 0 || val1 == 0 || val0 == 4 || val1 == 4)
+ && (val_diff == 4 || val_diff == -4));
+ }
+
return ((REGNO (reg0) == REGNO (reg1))
&& (val_diff == 4 || val_diff == -4));
}
@@ -4618,124 +5820,6 @@ adjacent_mem_locations (rtx a, rtx b)
return 0;
}
-/* Return 1 if OP is a load multiple operation. It is known to be
- parallel and the first section will be tested. */
-int
-load_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- HOST_WIDE_INT count = XVECLEN (op, 0);
- int dest_regno;
- rtx src_addr;
- HOST_WIDE_INT i = 1, base = 0;
- rtx elt;
-
- if (count <= 1
- || GET_CODE (XVECEXP (op, 0, 0)) != SET)
- return 0;
-
- /* Check to see if this might be a write-back. */
- if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS)
- {
- i++;
- base = 1;
-
- /* Now check it more carefully. */
- if (GET_CODE (SET_DEST (elt)) != REG
- || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG
- || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT
- || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 1) * 4)
- return 0;
- }
-
- /* Perform a quick check so we don't blow up below. */
- if (count <= i
- || GET_CODE (XVECEXP (op, 0, i - 1)) != SET
- || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != REG
- || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != MEM)
- return 0;
-
- dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, i - 1)));
- src_addr = XEXP (SET_SRC (XVECEXP (op, 0, i - 1)), 0);
-
- for (; i < count; i++)
- {
- elt = XVECEXP (op, 0, i);
-
- if (GET_CODE (elt) != SET
- || GET_CODE (SET_DEST (elt)) != REG
- || GET_MODE (SET_DEST (elt)) != SImode
- || REGNO (SET_DEST (elt)) != (unsigned int)(dest_regno + i - base)
- || GET_CODE (SET_SRC (elt)) != MEM
- || GET_MODE (SET_SRC (elt)) != SImode
- || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
- || !rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
- || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
- || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != (i - base) * 4)
- return 0;
- }
-
- return 1;
-}
-
-/* Return 1 if OP is a store multiple operation. It is known to be
- parallel and the first section will be tested. */
-int
-store_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- HOST_WIDE_INT count = XVECLEN (op, 0);
- int src_regno;
- rtx dest_addr;
- HOST_WIDE_INT i = 1, base = 0;
- rtx elt;
-
- if (count <= 1
- || GET_CODE (XVECEXP (op, 0, 0)) != SET)
- return 0;
-
- /* Check to see if this might be a write-back. */
- if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS)
- {
- i++;
- base = 1;
-
- /* Now check it more carefully. */
- if (GET_CODE (SET_DEST (elt)) != REG
- || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG
- || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT
- || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 1) * 4)
- return 0;
- }
-
- /* Perform a quick check so we don't blow up below. */
- if (count <= i
- || GET_CODE (XVECEXP (op, 0, i - 1)) != SET
- || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != MEM
- || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != REG)
- return 0;
-
- src_regno = REGNO (SET_SRC (XVECEXP (op, 0, i - 1)));
- dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, i - 1)), 0);
-
- for (; i < count; i++)
- {
- elt = XVECEXP (op, 0, i);
-
- if (GET_CODE (elt) != SET
- || GET_CODE (SET_SRC (elt)) != REG
- || GET_MODE (SET_SRC (elt)) != SImode
- || REGNO (SET_SRC (elt)) != (unsigned int)(src_regno + i - base)
- || GET_CODE (SET_DEST (elt)) != MEM
- || GET_MODE (SET_DEST (elt)) != SImode
- || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
- || !rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
- || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
- || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != (i - base) * 4)
- return 0;
- }
-
- return 1;
-}
-
int
load_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
HOST_WIDE_INT *load_offset)
@@ -4748,11 +5832,10 @@ load_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
/* Can only handle 2, 3, or 4 insns at present,
though could be easily extended if required. */
- if (nops < 2 || nops > 4)
- abort ();
+ gcc_assert (nops >= 2 && nops <= 4);
/* Loop over the operands and check that the memory references are
- suitable (ie immediate offsets from the same base register). At
+ suitable (i.e. immediate offsets from the same base register). At
the same time, extract the target register, and the memory
offsets. */
for (i = 0; i < nops; i++)
@@ -4764,8 +5847,7 @@ load_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
if (GET_CODE (operands[nops + i]) == SUBREG)
operands[nops + i] = alter_subreg (operands + (nops + i));
- if (GET_CODE (operands[nops + i]) != MEM)
- abort ();
+ gcc_assert (GET_CODE (operands[nops + i]) == MEM);
/* Don't reorder volatile memory references; it doesn't seem worth
looking for the case where the order is ok anyway. */
@@ -4793,7 +5875,7 @@ load_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
: REGNO (SUBREG_REG (operands[i])));
order[0] = 0;
}
- else
+ else
{
if (base_reg != (int) REGNO (reg))
/* Not addressed from the same base register. */
@@ -4879,15 +5961,15 @@ load_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
scratch register (one of the result regs) and then doing a load
multiple actually becomes slower (and no smaller in code size).
That is the transformation
-
+
ldr rd1, [rbase + offset]
ldr rd2, [rbase + offset + 4]
-
+
to
-
+
add rd1, rbase, offset
ldmia rd1, {rd1, rd2}
-
+
produces worse code -- '3 cycles + any stalls on rd2' instead of
'2 cycles + any stalls on rd2'. On ARMs with only one cache
access per cycle, the first sequence could never complete in less
@@ -4903,7 +5985,7 @@ load_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
/* Can't do it without setting up the offset, only do this if it takes
no more than one insn. */
- return (const_ok_for_arm (unsorted_offsets[order[0]])
+ return (const_ok_for_arm (unsorted_offsets[order[0]])
|| const_ok_for_arm (-unsorted_offsets[order[0]])) ? 5 : 0;
}
@@ -4949,10 +6031,10 @@ emit_ldm_seq (rtx *operands, int nops)
break;
default:
- abort ();
+ gcc_unreachable ();
}
- sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX,
+ sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX,
reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]);
for (i = 1; i < nops; i++)
@@ -4977,11 +6059,10 @@ store_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
/* Can only handle 2, 3, or 4 insns at present, though could be easily
extended if required. */
- if (nops < 2 || nops > 4)
- abort ();
+ gcc_assert (nops >= 2 && nops <= 4);
/* Loop over the operands and check that the memory references are
- suitable (ie immediate offsets from the same base register). At
+ suitable (i.e. immediate offsets from the same base register). At
the same time, extract the target register, and the memory
offsets. */
for (i = 0; i < nops; i++)
@@ -4993,8 +6074,7 @@ store_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
if (GET_CODE (operands[nops + i]) == SUBREG)
operands[nops + i] = alter_subreg (operands + (nops + i));
- if (GET_CODE (operands[nops + i]) != MEM)
- abort ();
+ gcc_assert (GET_CODE (operands[nops + i]) == MEM);
/* Don't reorder volatile memory references; it doesn't seem worth
looking for the case where the order is ok anyway. */
@@ -5022,7 +6102,7 @@ store_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
: REGNO (SUBREG_REG (operands[i])));
order[0] = 0;
}
- else
+ else
{
if (base_reg != (int) REGNO (reg))
/* Not addressed from the same base register. */
@@ -5126,10 +6206,10 @@ emit_stm_seq (rtx *operands, int nops)
break;
default:
- abort ();
+ gcc_unreachable ();
}
- sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX,
+ sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX,
reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]);
for (i = 1; i < nops; i++)
@@ -5141,18 +6221,6 @@ emit_stm_seq (rtx *operands, int nops)
output_asm_insn (buf, operands);
return "";
}
-
-int
-multi_register_push (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- if (GET_CODE (op) != PARALLEL
- || (GET_CODE (XVECEXP (op, 0, 0)) != SET)
- || (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC)
- || (XINT (SET_SRC (XVECEXP (op, 0, 0)), 1) != UNSPEC_PUSH_MULT))
- return 0;
-
- return 1;
-}
/* Routines for use in generating RTL. */
@@ -5167,7 +6235,7 @@ arm_gen_load_multiple (int base_regno, int count, rtx from, int up,
rtx mem, addr;
/* XScale has load-store double instructions, but they have stricter
- alignment requirements than load-store multiple, so we can not
+ alignment requirements than load-store multiple, so we cannot
use them.
For XScale ldm requires 2 + NREGS cycles to complete and blocks
@@ -5197,9 +6265,9 @@ arm_gen_load_multiple (int base_regno, int count, rtx from, int up,
if (arm_tune_xscale && count <= 2 && ! optimize_size)
{
rtx seq;
-
+
start_sequence ();
-
+
for (i = 0; i < count; i++)
{
addr = plus_constant (from, i * 4 * sign);
@@ -5216,7 +6284,7 @@ arm_gen_load_multiple (int base_regno, int count, rtx from, int up,
seq = get_insns ();
end_sequence ();
-
+
return seq;
}
@@ -5225,8 +6293,7 @@ arm_gen_load_multiple (int base_regno, int count, rtx from, int up,
if (write_back)
{
XVECEXP (result, 0, 0)
- = gen_rtx_SET (GET_MODE (from), from,
- plus_constant (from, count * 4 * sign));
+ = gen_rtx_SET (VOIDmode, from, plus_constant (from, count * 4 * sign));
i = 1;
count++;
}
@@ -5261,9 +6328,9 @@ arm_gen_store_multiple (int base_regno, int count, rtx to, int up,
if (arm_tune_xscale && count <= 2 && ! optimize_size)
{
rtx seq;
-
+
start_sequence ();
-
+
for (i = 0; i < count; i++)
{
addr = plus_constant (to, i * 4 * sign);
@@ -5280,7 +6347,7 @@ arm_gen_store_multiple (int base_regno, int count, rtx to, int up,
seq = get_insns ();
end_sequence ();
-
+
return seq;
}
@@ -5289,7 +6356,7 @@ arm_gen_store_multiple (int base_regno, int count, rtx to, int up,
if (write_back)
{
XVECEXP (result, 0, 0)
- = gen_rtx_SET (GET_MODE (to), to,
+ = gen_rtx_SET (VOIDmode, to,
plus_constant (to, count * 4 * sign));
i = 1;
count++;
@@ -5311,7 +6378,7 @@ arm_gen_store_multiple (int base_regno, int count, rtx to, int up,
}
int
-arm_gen_movstrqi (rtx *operands)
+arm_gen_movmemqi (rtx *operands)
{
HOST_WIDE_INT in_words_to_go, out_words_to_go, last_bytes;
HOST_WIDE_INT srcoffset, dstoffset;
@@ -5328,7 +6395,7 @@ arm_gen_movstrqi (rtx *operands)
dstbase = operands[0];
srcbase = operands[1];
-
+
dst = copy_to_mode_reg (SImode, XEXP (dstbase, 0));
src = copy_to_mode_reg (SImode, XEXP (srcbase, 0));
@@ -5336,7 +6403,7 @@ arm_gen_movstrqi (rtx *operands)
out_words_to_go = INTVAL (operands[2]) / 4;
last_bytes = INTVAL (operands[2]) & 3;
dstoffset = srcoffset = 0;
-
+
if (out_words_to_go != in_words_to_go && ((in_words_to_go - 1) & 3) != 0)
part_bytes_reg = gen_rtx_REG (SImode, (in_words_to_go - 1) & 3);
@@ -5346,7 +6413,7 @@ arm_gen_movstrqi (rtx *operands)
emit_insn (arm_gen_load_multiple (0, 4, src, TRUE, TRUE,
srcbase, &srcoffset));
else
- emit_insn (arm_gen_load_multiple (0, in_words_to_go, src, TRUE,
+ emit_insn (arm_gen_load_multiple (0, in_words_to_go, src, TRUE,
FALSE, srcbase, &srcoffset));
if (out_words_to_go)
@@ -5354,10 +6421,9 @@ arm_gen_movstrqi (rtx *operands)
if (out_words_to_go > 4)
emit_insn (arm_gen_store_multiple (0, 4, dst, TRUE, TRUE,
dstbase, &dstoffset));
-
else if (out_words_to_go != 1)
emit_insn (arm_gen_store_multiple (0, out_words_to_go,
- dst, TRUE,
+ dst, TRUE,
(last_bytes == 0
? FALSE : TRUE),
dstbase, &dstoffset));
@@ -5388,22 +6454,19 @@ arm_gen_movstrqi (rtx *operands)
mem = adjust_automodify_address (dstbase, SImode, dst, dstoffset);
emit_move_insn (mem, sreg);
in_words_to_go--;
-
- if (in_words_to_go) /* Sanity check */
- abort ();
+
+ gcc_assert (!in_words_to_go); /* Sanity check */
}
if (in_words_to_go)
{
- if (in_words_to_go < 0)
- abort ();
+ gcc_assert (in_words_to_go > 0);
mem = adjust_automodify_address (srcbase, SImode, src, srcoffset);
part_bytes_reg = copy_to_mode_reg (SImode, mem);
}
- if (last_bytes && part_bytes_reg == NULL)
- abort ();
+ gcc_assert (!last_bytes || part_bytes_reg);
if (BYTES_BIG_ENDIAN && last_bytes)
{
@@ -5413,7 +6476,7 @@ arm_gen_movstrqi (rtx *operands)
emit_insn (gen_lshrsi3 (tmp, part_bytes_reg,
GEN_INT (8 * (4 - last_bytes))));
part_bytes_reg = tmp;
-
+
while (last_bytes)
{
mem = adjust_automodify_address (dstbase, QImode,
@@ -5428,7 +6491,7 @@ arm_gen_movstrqi (rtx *operands)
part_bytes_reg = tmp;
}
}
-
+
}
else
{
@@ -5440,14 +6503,13 @@ arm_gen_movstrqi (rtx *operands)
if (last_bytes)
{
rtx tmp = gen_reg_rtx (SImode);
-
- emit_insn (gen_addsi3 (dst, dst, GEN_INT (2)));
+ emit_insn (gen_addsi3 (dst, dst, const2_rtx));
emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (16)));
part_bytes_reg = tmp;
dstoffset += 2;
}
}
-
+
if (last_bytes)
{
mem = adjust_automodify_address (dstbase, QImode, dst, dstoffset);
@@ -5458,42 +6520,13 @@ arm_gen_movstrqi (rtx *operands)
return 1;
}
-/* Generate a memory reference for a half word, such that it will be loaded
- into the top 16 bits of the word. We can assume that the address is
- known to be alignable and of the form reg, or plus (reg, const). */
-
-rtx
-arm_gen_rotated_half_load (rtx memref)
-{
- HOST_WIDE_INT offset = 0;
- rtx base = XEXP (memref, 0);
-
- if (GET_CODE (base) == PLUS)
- {
- offset = INTVAL (XEXP (base, 1));
- base = XEXP (base, 0);
- }
-
- /* If we aren't allowed to generate unaligned addresses, then fail. */
- if (TARGET_MMU_TRAPS
- && ((BYTES_BIG_ENDIAN ? 1 : 0) ^ ((offset & 2) == 0)))
- return NULL;
-
- base = gen_rtx_MEM (SImode, plus_constant (base, offset & ~2));
-
- if ((BYTES_BIG_ENDIAN ? 1 : 0) ^ ((offset & 2) == 2))
- return base;
-
- return gen_rtx_ROTATE (SImode, base, GEN_INT (16));
-}
-
/* Select a dominance comparison mode if possible for a test of the general
form (OP (COND_OR (X) (Y)) (const_int 0)). We support three forms.
- COND_OR == DOM_CC_X_AND_Y => (X && Y)
+ COND_OR == DOM_CC_X_AND_Y => (X && Y)
COND_OR == DOM_CC_NX_OR_Y => ((! X) || Y)
- COND_OR == DOM_CC_X_OR_Y => (X || Y)
+ COND_OR == DOM_CC_X_OR_Y => (X || Y)
In all cases OP will be either EQ or NE, but we don't need to know which
- here. If we are unable to support a dominance comparison we return
+ here. If we are unable to support a dominance comparison we return
CC mode. This will then fail to match for the RTL expressions that
generate this call. */
enum machine_mode
@@ -5519,7 +6552,7 @@ arm_select_dominance_cc_mode (rtx x, rtx y, HOST_WIDE_INT cond_or)
/* If the comparisons are not equal, and one doesn't dominate the other,
then we can't do this. */
- if (cond1 != cond2
+ if (cond1 != cond2
&& !comparison_dominates_p (cond1, cond2)
&& (swapped = 1, !comparison_dominates_p (cond2, cond1)))
return CCmode;
@@ -5534,78 +6567,108 @@ arm_select_dominance_cc_mode (rtx x, rtx y, HOST_WIDE_INT cond_or)
switch (cond1)
{
case EQ:
- if (cond2 == EQ || cond_or == DOM_CC_X_AND_Y)
+ if (cond_or == DOM_CC_X_AND_Y)
return CC_DEQmode;
switch (cond2)
{
+ case EQ: return CC_DEQmode;
case LE: return CC_DLEmode;
case LEU: return CC_DLEUmode;
case GE: return CC_DGEmode;
case GEU: return CC_DGEUmode;
- default: break;
+ default: gcc_unreachable ();
}
- break;
-
case LT:
- if (cond2 == LT || cond_or == DOM_CC_X_AND_Y)
+ if (cond_or == DOM_CC_X_AND_Y)
return CC_DLTmode;
- if (cond2 == LE)
- return CC_DLEmode;
- if (cond2 == NE)
- return CC_DNEmode;
- break;
+
+ switch (cond2)
+ {
+ case LT:
+ return CC_DLTmode;
+ case LE:
+ return CC_DLEmode;
+ case NE:
+ return CC_DNEmode;
+ default:
+ gcc_unreachable ();
+ }
case GT:
- if (cond2 == GT || cond_or == DOM_CC_X_AND_Y)
+ if (cond_or == DOM_CC_X_AND_Y)
return CC_DGTmode;
- if (cond2 == GE)
- return CC_DGEmode;
- if (cond2 == NE)
- return CC_DNEmode;
- break;
-
+
+ switch (cond2)
+ {
+ case GT:
+ return CC_DGTmode;
+ case GE:
+ return CC_DGEmode;
+ case NE:
+ return CC_DNEmode;
+ default:
+ gcc_unreachable ();
+ }
+
case LTU:
- if (cond2 == LTU || cond_or == DOM_CC_X_AND_Y)
+ if (cond_or == DOM_CC_X_AND_Y)
return CC_DLTUmode;
- if (cond2 == LEU)
- return CC_DLEUmode;
- if (cond2 == NE)
- return CC_DNEmode;
- break;
+
+ switch (cond2)
+ {
+ case LTU:
+ return CC_DLTUmode;
+ case LEU:
+ return CC_DLEUmode;
+ case NE:
+ return CC_DNEmode;
+ default:
+ gcc_unreachable ();
+ }
case GTU:
- if (cond2 == GTU || cond_or == DOM_CC_X_AND_Y)
+ if (cond_or == DOM_CC_X_AND_Y)
return CC_DGTUmode;
- if (cond2 == GEU)
- return CC_DGEUmode;
- if (cond2 == NE)
- return CC_DNEmode;
- break;
+
+ switch (cond2)
+ {
+ case GTU:
+ return CC_DGTUmode;
+ case GEU:
+ return CC_DGEUmode;
+ case NE:
+ return CC_DNEmode;
+ default:
+ gcc_unreachable ();
+ }
/* The remaining cases only occur when both comparisons are the
same. */
case NE:
+ gcc_assert (cond1 == cond2);
return CC_DNEmode;
case LE:
+ gcc_assert (cond1 == cond2);
return CC_DLEmode;
case GE:
+ gcc_assert (cond1 == cond2);
return CC_DGEmode;
case LEU:
+ gcc_assert (cond1 == cond2);
return CC_DLEUmode;
case GEU:
+ gcc_assert (cond1 == cond2);
return CC_DGEUmode;
default:
- break;
+ gcc_unreachable ();
}
-
- abort ();
}
enum machine_mode
@@ -5633,15 +6696,15 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
case LE:
case GT:
case GE:
- if (TARGET_CIRRUS)
+ if (TARGET_HARD_FLOAT && TARGET_MAVERICK)
return CCFPmode;
return CCFPEmode;
default:
- abort ();
+ gcc_unreachable ();
}
}
-
+
/* A compare with a shifted operand. Because of canonicalization, the
comparison will have to be swapped when we emit the assembler. */
if (GET_MODE (y) == SImode && GET_CODE (y) == REG
@@ -5650,7 +6713,14 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
|| GET_CODE (x) == ROTATERT))
return CC_SWPmode;
- /* This is a special case that is used by combine to allow a
+ /* This operation is performed swapped, but since we only rely on the Z
+ flag we don't need an additional mode. */
+ if (GET_MODE (y) == SImode && REG_P (y)
+ && GET_CODE (x) == NEG
+ && (op == EQ || op == NE))
+ return CC_Zmode;
+
+ /* This is a special case that is used by combine to allow a
comparison of a shifted byte load to be split into a zero-extend
followed by a comparison of the shifted integer (only valid for
equalities and unsigned inequalities). */
@@ -5672,21 +6742,21 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
if (GET_CODE (x) == IF_THEN_ELSE
&& (XEXP (x, 2) == const0_rtx
|| XEXP (x, 2) == const1_rtx)
- && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
- && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<')
- return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
+ && COMPARISON_P (XEXP (x, 0))
+ && COMPARISON_P (XEXP (x, 1)))
+ return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
INTVAL (XEXP (x, 2)));
/* Alternate canonicalizations of the above. These are somewhat cleaner. */
if (GET_CODE (x) == AND
- && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
- && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<')
+ && COMPARISON_P (XEXP (x, 0))
+ && COMPARISON_P (XEXP (x, 1)))
return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
DOM_CC_X_AND_Y);
if (GET_CODE (x) == IOR
- && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
- && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<')
+ && COMPARISON_P (XEXP (x, 0))
+ && COMPARISON_P (XEXP (x, 1)))
return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
DOM_CC_X_OR_Y);
@@ -5696,7 +6766,8 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
if (TARGET_THUMB
&& GET_MODE (x) == SImode
&& (op == EQ || op == NE)
- && (GET_CODE (x) == ZERO_EXTRACT))
+ && GET_CODE (x) == ZERO_EXTRACT
+ && XEXP (x, 1) == const1_rtx)
return CC_Nmode;
/* An operation that sets the condition codes as a side-effect, the
@@ -5736,8 +6807,7 @@ arm_gen_compare_reg (enum rtx_code code, rtx x, rtx y)
enum machine_mode mode = SELECT_CC_MODE (code, x, y);
rtx cc_reg = gen_rtx_REG (mode, CC_REGNUM);
- emit_insn (gen_rtx_SET (VOIDmode, cc_reg,
- gen_rtx_COMPARE (mode, x, y)));
+ emit_set_insn (cc_reg, gen_rtx_COMPARE (mode, x, y));
return cc_reg;
}
@@ -5791,7 +6861,7 @@ arm_reload_in_hi (rtx *operands)
{
rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
- emit_insn (gen_rtx_SET (VOIDmode, base_plus, base));
+ emit_set_insn (base_plus, base);
base = base_plus;
}
else if (GET_CODE (base) == PLUS)
@@ -5818,8 +6888,7 @@ arm_reload_in_hi (rtx *operands)
^ (HOST_WIDE_INT) 0x80000000)
- (HOST_WIDE_INT) 0x80000000);
- if (hi + lo != offset)
- abort ();
+ gcc_assert (hi + lo == offset);
if (hi != 0)
{
@@ -5846,24 +6915,23 @@ arm_reload_in_hi (rtx *operands)
plus_constant (base,
offset))));
emit_insn (gen_zero_extendqisi2 (gen_rtx_SUBREG (SImode, operands[0], 0),
- gen_rtx_MEM (QImode,
+ gen_rtx_MEM (QImode,
plus_constant (base,
offset + 1))));
if (!BYTES_BIG_ENDIAN)
- emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_SUBREG (SImode, operands[0], 0),
- gen_rtx_IOR (SImode,
- gen_rtx_ASHIFT
- (SImode,
- gen_rtx_SUBREG (SImode, operands[0], 0),
- GEN_INT (8)),
- scratch)));
+ emit_set_insn (gen_rtx_SUBREG (SImode, operands[0], 0),
+ gen_rtx_IOR (SImode,
+ gen_rtx_ASHIFT
+ (SImode,
+ gen_rtx_SUBREG (SImode, operands[0], 0),
+ GEN_INT (8)),
+ scratch));
else
- emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_SUBREG (SImode, operands[0], 0),
- gen_rtx_IOR (SImode,
- gen_rtx_ASHIFT (SImode, scratch,
- GEN_INT (8)),
- gen_rtx_SUBREG (SImode, operands[0],
- 0))));
+ emit_set_insn (gen_rtx_SUBREG (SImode, operands[0], 0),
+ gen_rtx_IOR (SImode,
+ gen_rtx_ASHIFT (SImode, scratch,
+ GEN_INT (8)),
+ gen_rtx_SUBREG (SImode, operands[0], 0)));
}
/* Handle storing a half-word to memory during reload by synthesizing as two
@@ -5938,7 +7006,7 @@ arm_reload_out_hi (rtx *operands)
}
}
- emit_insn (gen_rtx_SET (VOIDmode, base_plus, base));
+ emit_set_insn (base_plus, base);
base = base_plus;
}
else if (GET_CODE (base) == PLUS)
@@ -5965,8 +7033,7 @@ arm_reload_out_hi (rtx *operands)
^ (HOST_WIDE_INT) 0x80000000)
- (HOST_WIDE_INT) 0x80000000);
- if (hi + lo != offset)
- abort ();
+ gcc_assert (hi + lo == offset);
if (hi != 0)
{
@@ -6008,7 +7075,7 @@ arm_reload_out_hi (rtx *operands)
if (BYTES_BIG_ENDIAN)
{
- emit_insn (gen_movqi (gen_rtx_MEM (QImode,
+ emit_insn (gen_movqi (gen_rtx_MEM (QImode,
plus_constant (base, offset + 1)),
gen_lowpart (QImode, outval)));
emit_insn (gen_lshrsi3 (scratch,
@@ -6029,6 +7096,60 @@ arm_reload_out_hi (rtx *operands)
gen_lowpart (QImode, scratch)));
}
}
+
+/* Return true if a type must be passed in memory. For AAPCS, small aggregates
+ (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)
+{
+ if (TARGET_AAPCS_BASED)
+ return must_pass_in_stack_var_size (mode, type);
+ else
+ return must_pass_in_stack_var_size_or_pad (mode, type);
+}
+
+
+/* For use by FUNCTION_ARG_PADDING (MODE, TYPE).
+ Return true if an argument passed on the stack should be padded upwards,
+ i.e. if the least-significant byte has useful data.
+ For legacy APCS ABIs we use the default. For AAPCS based ABIs small
+ aggregate types are placed in the lowest memory address. */
+
+bool
+arm_pad_arg_upward (enum machine_mode mode, tree type)
+{
+ if (!TARGET_AAPCS_BASED)
+ return DEFAULT_FUNCTION_ARG_PADDING(mode, type) == upward;
+
+ if (type && BYTES_BIG_ENDIAN && INTEGRAL_TYPE_P (type))
+ return false;
+
+ return true;
+}
+
+
+/* Similarly, for use by BLOCK_REG_PADDING (MODE, TYPE, FIRST).
+ For non-AAPCS, return !BYTES_BIG_ENDIAN if the least significant
+ byte of the register has useful data, and return the opposite if the
+ most significant byte does.
+ For AAPCS, small aggregates and small complex types are always padded
+ upwards. */
+
+bool
+arm_pad_reg_upward (enum machine_mode mode ATTRIBUTE_UNUSED,
+ tree type, int first ATTRIBUTE_UNUSED)
+{
+ if (TARGET_AAPCS_BASED
+ && BYTES_BIG_ENDIAN
+ && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE)
+ && int_size_in_bytes (type) <= 4)
+ return true;
+
+ /* Otherwise, use default padding. */
+ return !BYTES_BIG_ENDIAN;
+}
+
/* Print a symbolic form of X to the debug file, F. */
static void
@@ -6205,6 +7326,7 @@ struct minipool_fixup
static Mnode * minipool_vector_head;
static Mnode * minipool_vector_tail;
static rtx minipool_vector_label;
+static int minipool_pad;
/* The linked list of all minipool fixes required for this function. */
Mfix * minipool_fix_head;
@@ -6218,7 +7340,7 @@ static rtx
is_jump_table (rtx insn)
{
rtx table;
-
+
if (GET_CODE (insn) == JUMP_INSN
&& JUMP_LABEL (insn) != NULL
&& ((table = next_real_insn (JUMP_LABEL (insn)))
@@ -6241,11 +7363,7 @@ get_jump_table_size (rtx insn)
{
/* ADDR_VECs only take room if read-only data does into the text
section. */
- if (JUMP_TABLES_IN_TEXT_SECTION
-#if !defined(READONLY_DATA_SECTION) && !defined(READONLY_DATA_SECTION_ASM_OP)
- || 1
-#endif
- )
+ if (JUMP_TABLES_IN_TEXT_SECTION || readonly_data_section == text_section)
{
rtx body = PATTERN (insn);
int elt = GET_CODE (body) == ADDR_DIFF_VEC ? 1 : 0;
@@ -6263,10 +7381,8 @@ static Mnode *
move_minipool_fix_forward_ref (Mnode *mp, Mnode *max_mp,
HOST_WIDE_INT max_address)
{
- /* This should never be true and the code below assumes these are
- different. */
- if (mp == max_mp)
- abort ();
+ /* The code below assumes these are different. */
+ gcc_assert (mp != max_mp);
if (max_mp == NULL)
{
@@ -6292,7 +7408,7 @@ move_minipool_fix_forward_ref (Mnode *mp, Mnode *max_mp,
mp->next = max_mp;
mp->prev = max_mp->prev;
max_mp->prev = mp;
-
+
if (mp->prev != NULL)
mp->prev->next = mp;
else
@@ -6322,16 +7438,16 @@ add_minipool_forward_ref (Mfix *fix)
/* If set, max_mp is the first pool_entry that has a lower
constraint than the one we are trying to add. */
Mnode * max_mp = NULL;
- HOST_WIDE_INT max_address = fix->address + fix->forwards;
+ HOST_WIDE_INT max_address = fix->address + fix->forwards - minipool_pad;
Mnode * mp;
-
- /* If this fix's address is greater than the address of the first
- entry, then we can't put the fix in this pool. We subtract the
- size of the current fix to ensure that if the table is fully
- packed we still have enough room to insert this value by suffling
- the other fixes forwards. */
+
+ /* If the minipool starts before the end of FIX->INSN then this FIX
+ can not be placed into the current pool. Furthermore, adding the
+ new constant pool entry may cause the pool to start FIX_SIZE bytes
+ earlier. */
if (minipool_vector_head &&
- fix->address >= minipool_vector_head->max_address - fix->fix_size)
+ (fix->address + get_attr_length (fix->insn)
+ >= minipool_vector_head->max_address - fix->fix_size))
return NULL;
/* Scan the pool to see if a constant with the same value has
@@ -6361,7 +7477,7 @@ add_minipool_forward_ref (Mfix *fix)
we have not already found an insertion point, then
make sure that all such 8-byte aligned quantities are
placed at the start of the pool. */
- if (TARGET_REALLY_IWMMXT
+ if (ARM_DOUBLEWORD_ALIGN
&& max_mp == NULL
&& fix->fix_size == 8
&& mp->fix_size != 8)
@@ -6377,7 +7493,7 @@ add_minipool_forward_ref (Mfix *fix)
any existing entry. Otherwise, we insert the new fix before
MAX_MP and, if necessary, adjust the constraints on the other
entries. */
- mp = xmalloc (sizeof (* mp));
+ mp = XNEW (Mnode);
mp->fix_size = fix->fix_size;
mp->mode = fix->mode;
mp->value = fix->value;
@@ -6438,10 +7554,8 @@ move_minipool_fix_backward_ref (Mnode *mp, Mnode *min_mp,
{
HOST_WIDE_INT offset;
- /* This should never be true, and the code below assumes these are
- different. */
- if (mp == min_mp)
- abort ();
+ /* The code below assumes these are different. */
+ gcc_assert (mp != min_mp);
if (min_mp == NULL)
{
@@ -6485,10 +7599,10 @@ move_minipool_fix_backward_ref (Mnode *mp, Mnode *min_mp,
}
return min_mp;
-}
+}
/* Add a constant to the minipool for a backward reference. Returns the
- node added or NULL if the constant will not fit in this pool.
+ node added or NULL if the constant will not fit in this pool.
Note that the code for insertion for a backwards reference can be
somewhat confusing because the calculated offsets for each fix do
@@ -6527,8 +7641,8 @@ add_minipool_backward_ref (Mfix *fix)
&& rtx_equal_p (fix->value, mp->value)
/* Check that there is enough slack to move this entry to the
end of the table (this is conservative). */
- && (mp->max_address
- > (minipool_barrier->address
+ && (mp->max_address
+ > (minipool_barrier->address
+ minipool_vector_tail->offset
+ minipool_vector_tail->fix_size)))
{
@@ -6545,7 +7659,8 @@ add_minipool_backward_ref (Mfix *fix)
{
/* For now, we do not allow the insertion of 8-byte alignment
requiring nodes anywhere but at the start of the pool. */
- if (TARGET_REALLY_IWMMXT && fix->fix_size == 8 && mp->fix_size != 8)
+ if (ARM_DOUBLEWORD_ALIGN
+ && fix->fix_size == 8 && mp->fix_size != 8)
return NULL;
else
min_mp = mp;
@@ -6564,7 +7679,7 @@ add_minipool_backward_ref (Mfix *fix)
we have not already found an insertion point, then
make sure that all such 8-byte aligned quantities are
placed at the start of the pool. */
- else if (TARGET_REALLY_IWMMXT
+ else if (ARM_DOUBLEWORD_ALIGN
&& min_mp == NULL
&& fix->fix_size == 8
&& mp->fix_size < 8)
@@ -6576,7 +7691,7 @@ add_minipool_backward_ref (Mfix *fix)
}
/* We need to create a new entry. */
- mp = xmalloc (sizeof (* mp));
+ mp = XNEW (Mnode);
mp->fix_size = fix->fix_size;
mp->mode = fix->mode;
mp->value = fix->value;
@@ -6605,7 +7720,7 @@ add_minipool_backward_ref (Mfix *fix)
mp->next = min_mp->next;
mp->prev = min_mp;
min_mp->next = mp;
-
+
if (mp->next != NULL)
mp->next->prev = mp;
else
@@ -6648,7 +7763,7 @@ assign_minipool_offsets (Mfix *barrier)
for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
{
mp->offset = offset;
-
+
if (mp->refcount > 0)
offset += mp->fix_size;
}
@@ -6662,7 +7777,7 @@ dump_minipool (rtx scan)
Mnode * nmp;
int align64 = 0;
- if (TARGET_REALLY_IWMMXT)
+ if (ARM_DOUBLEWORD_ALIGN)
for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
if (mp->refcount > 0 && mp->fix_size == 8)
{
@@ -6670,8 +7785,8 @@ dump_minipool (rtx scan)
break;
}
- if (rtl_dump_file)
- fprintf (rtl_dump_file,
+ if (dump_file)
+ fprintf (dump_file,
";; Emitting minipool after insn %u; address %ld; align %d (bytes)\n",
INSN_UID (scan), (unsigned long) minipool_barrier->address, align64 ? 8 : 4);
@@ -6683,14 +7798,14 @@ dump_minipool (rtx scan)
{
if (mp->refcount > 0)
{
- if (rtl_dump_file)
+ if (dump_file)
{
- fprintf (rtl_dump_file,
+ fprintf (dump_file,
";; Offset %u, min %ld, max %ld ",
(unsigned) mp->offset, (unsigned long) mp->min_address,
(unsigned long) mp->max_address);
- arm_print_value (rtl_dump_file, mp->value);
- fputc ('\n', rtl_dump_file);
+ arm_print_value (dump_file, mp->value);
+ fputc ('\n', dump_file);
}
switch (mp->fix_size)
@@ -6720,8 +7835,7 @@ dump_minipool (rtx scan)
#endif
default:
- abort ();
- break;
+ gcc_unreachable ();
}
}
@@ -6752,7 +7866,7 @@ arm_barrier_cost (rtx insn)
case CODE_LABEL:
/* It will always be better to place the table before the label, rather
than after it. */
- return 50;
+ return 50;
case INSN:
case CALL_INSN:
@@ -6776,8 +7890,10 @@ create_fix_barrier (Mfix *fix, HOST_WIDE_INT max_address)
HOST_WIDE_INT count = 0;
rtx barrier;
rtx from = fix->insn;
- rtx selected = from;
+ /* The instruction after which we will insert the jump. */
+ rtx selected = NULL;
int selected_cost;
+ /* The address at which the jump instruction will be placed. */
HOST_WIDE_INT selected_address;
Mfix * new_fix;
HOST_WIDE_INT max_count = max_address - fix->address;
@@ -6793,8 +7909,7 @@ create_fix_barrier (Mfix *fix, HOST_WIDE_INT max_address)
/* This code shouldn't have been called if there was a natural barrier
within range. */
- if (GET_CODE (from) == BARRIER)
- abort ();
+ gcc_assert (GET_CODE (from) != BARRIER);
/* Count the length of this insn. */
count += get_attr_length (from);
@@ -6810,7 +7925,8 @@ create_fix_barrier (Mfix *fix, HOST_WIDE_INT max_address)
still put the pool after the table. */
new_cost = arm_barrier_cost (from);
- if (count < max_count && new_cost <= selected_cost)
+ if (count < max_count
+ && (!selected || new_cost <= selected_cost))
{
selected = tmp;
selected_cost = new_cost;
@@ -6823,8 +7939,9 @@ create_fix_barrier (Mfix *fix, HOST_WIDE_INT max_address)
}
new_cost = arm_barrier_cost (from);
-
- if (count < max_count && new_cost <= selected_cost)
+
+ if (count < max_count
+ && (!selected || new_cost <= selected_cost))
{
selected = from;
selected_cost = new_cost;
@@ -6834,6 +7951,9 @@ create_fix_barrier (Mfix *fix, HOST_WIDE_INT max_address)
from = NEXT_INSN (from);
}
+ /* Make sure that we found a place to insert the jump. */
+ gcc_assert (selected);
+
/* Create a new JUMP_INSN that branches around a barrier. */
from = emit_jump_insn_after (gen_jump (label), selected);
JUMP_LABEL (from) = label;
@@ -6899,32 +8019,30 @@ push_minipool_fix (rtx insn, HOST_WIDE_INT address, rtx *loc,
fix->minipool = NULL;
/* If an insn doesn't have a range defined for it, then it isn't
- expecting to be reworked by this code. Better to abort now than
+ expecting to be reworked by this code. Better to stop now than
to generate duff assembly code. */
- if (fix->forwards == 0 && fix->backwards == 0)
- abort ();
+ gcc_assert (fix->forwards || fix->backwards);
- /* With iWMMXt enabled, the pool is aligned to an 8-byte boundary.
- So there might be an empty word before the start of the pool.
- Hence we reduce the forward range by 4 to allow for this
- possibility. */
- if (TARGET_REALLY_IWMMXT && fix->fix_size == 8)
- fix->forwards -= 4;
+ /* If an entry requires 8-byte alignment then assume all constant pools
+ require 4 bytes of padding. Trying to do this later on a per-pool
+ basis is awkward because existing pool entries have to be modified. */
+ if (ARM_DOUBLEWORD_ALIGN && fix->fix_size == 8)
+ minipool_pad = 4;
- if (rtl_dump_file)
+ if (dump_file)
{
- fprintf (rtl_dump_file,
+ fprintf (dump_file,
";; %smode fixup for i%d; addr %lu, range (%ld,%ld): ",
GET_MODE_NAME (mode),
- INSN_UID (insn), (unsigned long) address,
+ INSN_UID (insn), (unsigned long) address,
-1 * (long)fix->backwards, (long)fix->forwards);
- arm_print_value (rtl_dump_file, fix->value);
- fprintf (rtl_dump_file, "\n");
+ arm_print_value (dump_file, fix->value);
+ fprintf (dump_file, "\n");
}
/* Add it to the chain of fixes. */
fix->next = NULL;
-
+
if (minipool_fix_head != NULL)
minipool_fix_tail->next = fix;
else
@@ -6933,9 +8051,72 @@ push_minipool_fix (rtx insn, HOST_WIDE_INT address, rtx *loc,
minipool_fix_tail = fix;
}
+/* Return the cost of synthesizing a 64-bit constant VAL inline.
+ Returns the number of insns needed, or 99 if we don't know how to
+ do it. */
+int
+arm_const_double_inline_cost (rtx val)
+{
+ rtx lowpart, highpart;
+ enum machine_mode mode;
+
+ mode = GET_MODE (val);
+
+ if (mode == VOIDmode)
+ mode = DImode;
+
+ gcc_assert (GET_MODE_SIZE (mode) == 8);
+
+ lowpart = gen_lowpart (SImode, val);
+ highpart = gen_highpart_mode (SImode, mode, val);
+
+ gcc_assert (GET_CODE (lowpart) == CONST_INT);
+ gcc_assert (GET_CODE (highpart) == CONST_INT);
+
+ return (arm_gen_constant (SET, SImode, NULL_RTX, INTVAL (lowpart),
+ NULL_RTX, NULL_RTX, 0, 0)
+ + arm_gen_constant (SET, SImode, NULL_RTX, INTVAL (highpart),
+ NULL_RTX, NULL_RTX, 0, 0));
+}
+
+/* Return true if it is worthwhile to split a 64-bit constant into two
+ 32-bit operations. This is the case if optimizing for size, or
+ if we have load delay slots, or if one 32-bit part can be done with
+ a single data operation. */
+bool
+arm_const_double_by_parts (rtx val)
+{
+ enum machine_mode mode = GET_MODE (val);
+ rtx part;
+
+ if (optimize_size || arm_ld_sched)
+ return true;
+
+ if (mode == VOIDmode)
+ mode = DImode;
+
+ part = gen_highpart_mode (SImode, mode, val);
+
+ gcc_assert (GET_CODE (part) == CONST_INT);
+
+ if (const_ok_for_arm (INTVAL (part))
+ || const_ok_for_arm (~INTVAL (part)))
+ return true;
+
+ part = gen_lowpart (SImode, val);
+
+ gcc_assert (GET_CODE (part) == CONST_INT);
+
+ if (const_ok_for_arm (INTVAL (part))
+ || const_ok_for_arm (~INTVAL (part)))
+ return true;
+
+ return false;
+}
+
/* Scan INSN and note any of its operands that need fixing.
If DO_PUSHES is false we do not actually push any of the fixups
- needed. The function returns TRUE is any fixups were needed/pushed.
+ needed. The function returns TRUE if any fixups were needed/pushed.
This is used by arm_memory_load_p() which needs to know about loads
of constants that will be converted into minipool loads. */
static bool
@@ -6952,7 +8133,8 @@ note_invalid_constants (rtx insn, HOST_WIDE_INT address, int do_pushes)
if (recog_data.n_alternatives == 0)
return false;
- /* Fill in recog_op_alt with information about the constraints of this insn. */
+ /* Fill in recog_op_alt with information about the constraints of
+ this insn. */
preprocess_constraints ();
for (opno = 0; opno < recog_data.n_operands; opno++)
@@ -6987,7 +8169,7 @@ note_invalid_constants (rtx insn, HOST_WIDE_INT address, int do_pushes)
/* Casting the address of something to a mode narrower
than a word can cause avoid_constant_pool_reference()
to return the pool reference itself. That's no good to
- us here. Lets just hope that we can use the
+ us here. Lets just hope that we can use the
constant pool value directly. */
if (op == cop)
cop = get_pool_constant (XEXP (op, 0));
@@ -7021,8 +8203,8 @@ arm_reorg (void)
/* The first insn must always be a note, or the code below won't
scan it properly. */
insn = get_insns ();
- if (GET_CODE (insn) != NOTE)
- abort ();
+ gcc_assert (GET_CODE (insn) == NOTE);
+ minipool_pad = 0;
/* Scan all the insns and record the operands that will need fixing. */
for (insn = next_nonnote_insn (insn); insn; insn = next_nonnote_insn (insn))
@@ -7053,7 +8235,7 @@ arm_reorg (void)
}
fix = minipool_fix_head;
-
+
/* Now scan the fixups and perform the required changes. */
while (fix)
{
@@ -7093,7 +8275,7 @@ arm_reorg (void)
the next mini-pool. */
if (last_barrier != NULL)
{
- /* Reduce the refcount for those fixes that won't go into this
+ /* Reduce the refcount for those fixes that won't go into this
pool after all. */
for (fdel = last_barrier->next;
fdel && fdel != ftmp;
@@ -7116,16 +8298,17 @@ arm_reorg (void)
/* The last item on the list of fixes must be a barrier, so
we can never run off the end of the list of fixes without
last_barrier being set. */
- if (ftmp == NULL)
- abort ();
+ gcc_assert (ftmp);
max_address = minipool_vector_head->max_address;
/* Check that there isn't another fix that is in range that
we couldn't fit into this pool because the pool was
already too large: we need to put the pool before such an
- instruction. */
+ instruction. The pool itself may come just after the
+ fix because create_fix_barrier also allows space for a
+ jump instruction. */
if (ftmp->address < max_address)
- max_address = ftmp->address;
+ max_address = ftmp->address + 1;
last_barrier = create_fix_barrier (last_added_fix, max_address);
}
@@ -7149,7 +8332,7 @@ arm_reorg (void)
if (GET_CODE (this_fix->insn) != BARRIER)
{
rtx addr
- = plus_constant (gen_rtx_LABEL_REF (VOIDmode,
+ = plus_constant (gen_rtx_LABEL_REF (VOIDmode,
minipool_vector_label),
this_fix->minipool->offset);
*this_fix->loc = gen_rtx_MEM (this_fix->mode, addr);
@@ -7178,16 +8361,16 @@ fp_immediate_constant (rtx x)
{
REAL_VALUE_TYPE r;
int i;
-
- if (!fpa_consts_inited)
- init_fpa_table ();
-
+
+ if (!fp_consts_inited)
+ init_fp_table ();
+
REAL_VALUE_FROM_CONST_DOUBLE (r, x);
for (i = 0; i < 8; i++)
- if (REAL_VALUES_EQUAL (r, values_fpa[i]))
- return strings_fpa[i];
+ if (REAL_VALUES_EQUAL (r, values_fp[i]))
+ return strings_fp[i];
- abort ();
+ gcc_unreachable ();
}
/* As for fp_immediate_constant, but value is passed directly, not in rtx. */
@@ -7196,75 +8379,200 @@ fp_const_from_val (REAL_VALUE_TYPE *r)
{
int i;
- if (!fpa_consts_inited)
- init_fpa_table ();
+ if (!fp_consts_inited)
+ init_fp_table ();
for (i = 0; i < 8; i++)
- if (REAL_VALUES_EQUAL (*r, values_fpa[i]))
- return strings_fpa[i];
+ if (REAL_VALUES_EQUAL (*r, values_fp[i]))
+ return strings_fp[i];
- abort ();
+ gcc_unreachable ();
}
/* Output the operands of a LDM/STM instruction to STREAM.
MASK is the ARM register set mask of which only bits 0-15 are important.
REG is the base register, either the frame pointer or the stack pointer,
INSTR is the possibly suffixed load or store instruction. */
+
static void
-print_multi_reg (FILE *stream, const char *instr, int reg, int mask)
+print_multi_reg (FILE *stream, const char *instr, unsigned reg,
+ unsigned long mask)
{
- int i;
- int not_first = FALSE;
+ unsigned i;
+ bool not_first = FALSE;
fputc ('\t', stream);
asm_fprintf (stream, instr, reg);
fputs (", {", stream);
-
+
for (i = 0; i <= LAST_ARM_REGNUM; i++)
if (mask & (1 << i))
{
if (not_first)
fprintf (stream, ", ");
-
+
asm_fprintf (stream, "%r", i);
not_first = TRUE;
}
- fprintf (stream, "}");
-
- /* Add a ^ character for the 26-bit ABI, but only if we were loading
- the PC. Otherwise we would generate an UNPREDICTABLE instruction.
- Strictly speaking the instruction would be unpredicatble only if
- we were writing back the base register as well, but since we never
- want to generate an LDM type 2 instruction (register bank switching)
- which is what you get if the PC is not being loaded, we do not need
- to check for writeback. */
- if (! TARGET_APCS_32
- && ((mask & (1 << PC_REGNUM)) != 0))
- fprintf (stream, "^");
-
- fprintf (stream, "\n");
+ fprintf (stream, "}\n");
}
+
+/* Output a FLDMX instruction to STREAM.
+ BASE if the register containing the address.
+ REG and COUNT specify the register range.
+ Extra registers may be added to avoid hardware bugs. */
+
+static void
+arm_output_fldmx (FILE * stream, unsigned int base, int reg, int count)
+{
+ int i;
+
+ /* Workaround ARM10 VFPr1 bug. */
+ if (count == 2 && !arm_arch6)
+ {
+ if (reg == 15)
+ reg--;
+ count++;
+ }
+
+ fputc ('\t', stream);
+ asm_fprintf (stream, "fldmfdx\t%r!, {", base);
+
+ for (i = reg; i < reg + count; i++)
+ {
+ if (i > reg)
+ fputs (", ", stream);
+ asm_fprintf (stream, "d%d", i);
+ }
+ fputs ("}\n", stream);
+
+}
+
+
+/* Output the assembly for a store multiple. */
+
+const char *
+vfp_output_fstmx (rtx * operands)
+{
+ char pattern[100];
+ int p;
+ int base;
+ int i;
+
+ strcpy (pattern, "fstmfdx\t%m0!, {%P1");
+ p = strlen (pattern);
+
+ gcc_assert (GET_CODE (operands[1]) == REG);
+
+ base = (REGNO (operands[1]) - FIRST_VFP_REGNUM) / 2;
+ for (i = 1; i < XVECLEN (operands[2], 0); i++)
+ {
+ p += sprintf (&pattern[p], ", d%d", base + i);
+ }
+ strcpy (&pattern[p], "}");
+
+ output_asm_insn (pattern, operands);
+ return "";
+}
+
+
+/* Emit RTL to save block of VFP register pairs to the stack. Returns the
+ number of bytes pushed. */
+
+static int
+vfp_emit_fstmx (int base_reg, int count)
+{
+ rtx par;
+ rtx dwarf;
+ rtx tmp, reg;
+ int i;
+
+ /* Workaround ARM10 VFPr1 bug. Data corruption can occur when exactly two
+ register pairs are stored by a store multiple insn. We avoid this
+ by pushing an extra pair. */
+ if (count == 2 && !arm_arch6)
+ {
+ if (base_reg == LAST_VFP_REGNUM - 3)
+ base_reg -= 2;
+ count++;
+ }
+
+ /* ??? The frame layout is implementation defined. We describe
+ standard format 1 (equivalent to a FSTMD insn and unused pad word).
+ We really need some way of representing the whole block so that the
+ unwinder can figure it out at runtime. */
+ par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
+ dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (count + 1));
+
+ reg = gen_rtx_REG (DFmode, base_reg);
+ base_reg += 2;
+
+ XVECEXP (par, 0, 0)
+ = gen_rtx_SET (VOIDmode,
+ gen_frame_mem (BLKmode,
+ gen_rtx_PRE_DEC (BLKmode,
+ stack_pointer_rtx)),
+ gen_rtx_UNSPEC (BLKmode,
+ gen_rtvec (1, reg),
+ UNSPEC_PUSH_MULT));
+
+ tmp = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+ plus_constant (stack_pointer_rtx, -(count * 8 + 4)));
+ RTX_FRAME_RELATED_P (tmp) = 1;
+ XVECEXP (dwarf, 0, 0) = tmp;
+
+ tmp = gen_rtx_SET (VOIDmode,
+ gen_frame_mem (DFmode, stack_pointer_rtx),
+ reg);
+ RTX_FRAME_RELATED_P (tmp) = 1;
+ XVECEXP (dwarf, 0, 1) = tmp;
+
+ for (i = 1; i < count; i++)
+ {
+ reg = gen_rtx_REG (DFmode, base_reg);
+ base_reg += 2;
+ XVECEXP (par, 0, i) = gen_rtx_USE (VOIDmode, reg);
+
+ tmp = gen_rtx_SET (VOIDmode,
+ gen_frame_mem (DFmode,
+ plus_constant (stack_pointer_rtx,
+ i * 8)),
+ reg);
+ RTX_FRAME_RELATED_P (tmp) = 1;
+ XVECEXP (dwarf, 0, i + 1) = tmp;
+ }
+
+ par = emit_insn (par);
+ REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
+ REG_NOTES (par));
+ RTX_FRAME_RELATED_P (par) = 1;
+
+ return count * 8 + 4;
+}
+
+
/* Output a 'call' insn. */
const char *
output_call (rtx *operands)
{
- /* Handle calls to lr using ip (which may be clobbered in subr anyway). */
+ gcc_assert (!arm_arch5); /* Patterns should call blx <reg> directly. */
+ /* Handle calls to lr using ip (which may be clobbered in subr anyway). */
if (REGNO (operands[0]) == LR_REGNUM)
{
operands[0] = gen_rtx_REG (SImode, IP_REGNUM);
output_asm_insn ("mov%?\t%0, %|lr", operands);
}
-
+
output_asm_insn ("mov%?\t%|lr, %|pc", operands);
-
- if (TARGET_INTERWORK)
+
+ if (TARGET_INTERWORK || arm_arch4t)
output_asm_insn ("bx%?\t%0", operands);
else
output_asm_insn ("mov%?\t%|pc, %0", operands);
-
+
return "";
}
@@ -7272,7 +8580,7 @@ output_call (rtx *operands)
const char *
output_call_mem (rtx *operands)
{
- if (TARGET_INTERWORK)
+ if (TARGET_INTERWORK && !arm_arch5)
{
output_asm_insn ("ldr%?\t%|ip, %0", operands);
output_asm_insn ("mov%?\t%|lr, %|pc", operands);
@@ -7284,8 +8592,16 @@ output_call_mem (rtx *operands)
first instruction. It's safe to use IP as the target of the
load since the call will kill it anyway. */
output_asm_insn ("ldr%?\t%|ip, %0", operands);
- output_asm_insn ("mov%?\t%|lr, %|pc", operands);
- output_asm_insn ("mov%?\t%|pc, %|ip", operands);
+ if (arm_arch5)
+ output_asm_insn ("blx%?\t%|ip", operands);
+ else
+ {
+ output_asm_insn ("mov%?\t%|lr, %|pc", operands);
+ if (arm_arch4t)
+ output_asm_insn ("bx%?\t%|ip", operands);
+ else
+ output_asm_insn ("mov%?\t%|pc, %|ip", operands);
+ }
}
else
{
@@ -7296,6 +8612,7 @@ output_call_mem (rtx *operands)
return "";
}
+
/* Output a move from arm registers to an fpa registers.
OPERANDS[0] is an fpa register.
OPERANDS[1] is the first registers of an arm register pair. */
@@ -7305,16 +8622,15 @@ output_mov_long_double_fpa_from_arm (rtx *operands)
int arm_reg0 = REGNO (operands[1]);
rtx ops[3];
- if (arm_reg0 == IP_REGNUM)
- abort ();
+ gcc_assert (arm_reg0 != IP_REGNUM);
ops[0] = gen_rtx_REG (SImode, arm_reg0);
ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
ops[2] = gen_rtx_REG (SImode, 2 + arm_reg0);
-
+
output_asm_insn ("stm%?fd\t%|sp!, {%0, %1, %2}", ops);
output_asm_insn ("ldf%?e\t%0, [%|sp], #12", operands);
-
+
return "";
}
@@ -7327,8 +8643,7 @@ output_mov_long_double_arm_from_fpa (rtx *operands)
int arm_reg0 = REGNO (operands[0]);
rtx ops[3];
- if (arm_reg0 == IP_REGNUM)
- abort ();
+ gcc_assert (arm_reg0 != IP_REGNUM);
ops[0] = gen_rtx_REG (SImode, arm_reg0);
ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
@@ -7383,9 +8698,8 @@ output_mov_double_fpa_from_arm (rtx *operands)
int arm_reg0 = REGNO (operands[1]);
rtx ops[2];
- if (arm_reg0 == IP_REGNUM)
- abort ();
-
+ gcc_assert (arm_reg0 != IP_REGNUM);
+
ops[0] = gen_rtx_REG (SImode, arm_reg0);
ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
output_asm_insn ("stm%?fd\t%|sp!, {%0, %1}", ops);
@@ -7402,8 +8716,7 @@ output_mov_double_arm_from_fpa (rtx *operands)
int arm_reg0 = REGNO (operands[0]);
rtx ops[2];
- if (arm_reg0 == IP_REGNUM)
- abort ();
+ gcc_assert (arm_reg0 != IP_REGNUM);
ops[0] = gen_rtx_REG (SImode, arm_reg0);
ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
@@ -7427,267 +8740,177 @@ output_move_double (rtx *operands)
int reg0 = REGNO (operands[0]);
otherops[0] = gen_rtx_REG (SImode, 1 + reg0);
-
- if (code1 == REG)
- {
- int reg1 = REGNO (operands[1]);
- if (reg1 == IP_REGNUM)
- abort ();
- /* Ensure the second source is not overwritten. */
- if (reg1 == reg0 + (WORDS_BIG_ENDIAN ? -1 : 1))
- output_asm_insn ("mov%?\t%Q0, %Q1\n\tmov%?\t%R0, %R1", operands);
- else
- output_asm_insn ("mov%?\t%R0, %R1\n\tmov%?\t%Q0, %Q1", operands);
- }
- else if (code1 == CONST_VECTOR)
- {
- HOST_WIDE_INT hint = 0;
+ gcc_assert (code1 == MEM); /* Constraints should ensure this. */
- switch (GET_MODE (operands[1]))
- {
- case V2SImode:
- otherops[1] = GEN_INT (INTVAL (CONST_VECTOR_ELT (operands[1], 1)));
- operands[1] = GEN_INT (INTVAL (CONST_VECTOR_ELT (operands[1], 0)));
- break;
-
- case V4HImode:
- if (BYTES_BIG_ENDIAN)
- {
- hint = INTVAL (CONST_VECTOR_ELT (operands[1], 2));
- hint <<= 16;
- hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 3));
- }
- else
- {
- hint = INTVAL (CONST_VECTOR_ELT (operands[1], 3));
- hint <<= 16;
- hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 2));
- }
+ switch (GET_CODE (XEXP (operands[1], 0)))
+ {
+ case REG:
+ output_asm_insn ("ldm%?ia\t%m1, %M0", operands);
+ break;
- otherops[1] = GEN_INT (hint);
- hint = 0;
+ case PRE_INC:
+ gcc_assert (TARGET_LDRD);
+ output_asm_insn ("ldr%?d\t%0, [%m1, #8]!", operands);
+ break;
- if (BYTES_BIG_ENDIAN)
- {
- hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 0));
- hint <<= 16;
- hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 1));
- }
- else
- {
- hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 1));
- hint <<= 16;
- hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 0));
- }
+ case PRE_DEC:
+ output_asm_insn ("ldm%?db\t%m1!, %M0", operands);
+ break;
- operands[1] = GEN_INT (hint);
- break;
+ case POST_INC:
+ output_asm_insn ("ldm%?ia\t%m1!, %M0", operands);
+ break;
- case V8QImode:
- if (BYTES_BIG_ENDIAN)
- {
- hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 4));
- hint <<= 8;
- hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 5));
- hint <<= 8;
- hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 6));
- hint <<= 8;
- hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 7));
- }
- else
- {
- hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 7));
- hint <<= 8;
- hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 6));
- hint <<= 8;
- hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 5));
- hint <<= 8;
- hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 4));
- }
+ case POST_DEC:
+ gcc_assert (TARGET_LDRD);
+ output_asm_insn ("ldr%?d\t%0, [%m1], #-8", operands);
+ break;
- otherops[1] = GEN_INT (hint);
- hint = 0;
+ case PRE_MODIFY:
+ case POST_MODIFY:
+ otherops[0] = operands[0];
+ otherops[1] = XEXP (XEXP (XEXP (operands[1], 0), 1), 0);
+ otherops[2] = XEXP (XEXP (XEXP (operands[1], 0), 1), 1);
- if (BYTES_BIG_ENDIAN)
+ if (GET_CODE (XEXP (operands[1], 0)) == PRE_MODIFY)
+ {
+ if (reg_overlap_mentioned_p (otherops[0], otherops[2]))
{
- hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 0));
- hint <<= 8;
- hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 1));
- hint <<= 8;
- hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 2));
- hint <<= 8;
- hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 3));
+ /* Registers overlap so split out the increment. */
+ output_asm_insn ("add%?\t%1, %1, %2", otherops);
+ output_asm_insn ("ldr%?d\t%0, [%1] @split", otherops);
}
else
{
- hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 3));
- hint <<= 8;
- hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 2));
- hint <<= 8;
- hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 1));
- hint <<= 8;
- hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 0));
+ /* IWMMXT allows offsets larger than ldrd can handle,
+ fix these up with a pair of ldr. */
+ if (GET_CODE (otherops[2]) == CONST_INT
+ && (INTVAL(otherops[2]) <= -256
+ || INTVAL(otherops[2]) >= 256))
+ {
+ output_asm_insn ("ldr%?\t%0, [%1, %2]!", otherops);
+ otherops[0] = gen_rtx_REG (SImode, 1 + reg0);
+ output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
+ }
+ else
+ output_asm_insn ("ldr%?d\t%0, [%1, %2]!", otherops);
}
-
- operands[1] = GEN_INT (hint);
- break;
-
- default:
- abort ();
- }
- output_mov_immediate (operands);
- output_mov_immediate (otherops);
- }
- else if (code1 == CONST_DOUBLE)
- {
- if (GET_MODE (operands[1]) == DFmode)
- {
- REAL_VALUE_TYPE r;
- long l[2];
-
- REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
- REAL_VALUE_TO_TARGET_DOUBLE (r, l);
- otherops[1] = GEN_INT (l[1]);
- operands[1] = GEN_INT (l[0]);
- }
- else if (GET_MODE (operands[1]) != VOIDmode)
- abort ();
- else if (WORDS_BIG_ENDIAN)
- {
- otherops[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
- operands[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
- }
- else
- {
- otherops[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
- operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
- }
-
- output_mov_immediate (operands);
- output_mov_immediate (otherops);
- }
- else if (code1 == CONST_INT)
- {
-#if HOST_BITS_PER_WIDE_INT > 32
- /* If HOST_WIDE_INT is more than 32 bits, the intval tells us
- what the upper word is. */
- if (WORDS_BIG_ENDIAN)
- {
- otherops[1] = GEN_INT (ARM_SIGN_EXTEND (INTVAL (operands[1])));
- operands[1] = GEN_INT (INTVAL (operands[1]) >> 32);
}
else
{
- otherops[1] = GEN_INT (INTVAL (operands[1]) >> 32);
- operands[1] = GEN_INT (ARM_SIGN_EXTEND (INTVAL (operands[1])));
- }
-#else
- /* Sign extend the intval into the high-order word. */
- if (WORDS_BIG_ENDIAN)
- {
- otherops[1] = operands[1];
- operands[1] = (INTVAL (operands[1]) < 0
- ? constm1_rtx : const0_rtx);
+ /* IWMMXT allows offsets larger than ldrd can handle,
+ fix these up with a pair of ldr. */
+ if (GET_CODE (otherops[2]) == CONST_INT
+ && (INTVAL(otherops[2]) <= -256
+ || INTVAL(otherops[2]) >= 256))
+ {
+ otherops[0] = gen_rtx_REG (SImode, 1 + reg0);
+ output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
+ otherops[0] = operands[0];
+ output_asm_insn ("ldr%?\t%0, [%1], %2", otherops);
+ }
+ else
+ /* We only allow constant increments, so this is safe. */
+ output_asm_insn ("ldr%?d\t%0, [%1], %2", otherops);
}
- else
- otherops[1] = INTVAL (operands[1]) < 0 ? constm1_rtx : const0_rtx;
-#endif
- output_mov_immediate (otherops);
- output_mov_immediate (operands);
- }
- else if (code1 == MEM)
- {
- switch (GET_CODE (XEXP (operands[1], 0)))
- {
- case REG:
- output_asm_insn ("ldm%?ia\t%m1, %M0", operands);
- break;
-
- case PRE_INC:
- abort (); /* Should never happen now. */
- break;
-
- case PRE_DEC:
- output_asm_insn ("ldm%?db\t%m1!, %M0", operands);
- break;
-
- case POST_INC:
- output_asm_insn ("ldm%?ia\t%m1!, %M0", operands);
- break;
+ break;
- case POST_DEC:
- abort (); /* Should never happen now. */
- break;
+ case LABEL_REF:
+ case CONST:
+ output_asm_insn ("adr%?\t%0, %1", operands);
+ output_asm_insn ("ldm%?ia\t%0, %M0", operands);
+ break;
- case LABEL_REF:
- case CONST:
- output_asm_insn ("adr%?\t%0, %1", operands);
- output_asm_insn ("ldm%?ia\t%0, %M0", operands);
- break;
+ default:
+ if (arm_add_operand (XEXP (XEXP (operands[1], 0), 1),
+ GET_MODE (XEXP (XEXP (operands[1], 0), 1))))
+ {
+ otherops[0] = operands[0];
+ otherops[1] = XEXP (XEXP (operands[1], 0), 0);
+ otherops[2] = XEXP (XEXP (operands[1], 0), 1);
- default:
- if (arm_add_operand (XEXP (XEXP (operands[1], 0), 1),
- GET_MODE (XEXP (XEXP (operands[1], 0), 1))))
+ if (GET_CODE (XEXP (operands[1], 0)) == PLUS)
{
- otherops[0] = operands[0];
- otherops[1] = XEXP (XEXP (operands[1], 0), 0);
- otherops[2] = XEXP (XEXP (operands[1], 0), 1);
-
- if (GET_CODE (XEXP (operands[1], 0)) == PLUS)
+ if (GET_CODE (otherops[2]) == CONST_INT)
{
- if (GET_CODE (otherops[2]) == CONST_INT)
+ switch ((int) INTVAL (otherops[2]))
{
- switch ((int) INTVAL (otherops[2]))
- {
- case -8:
- output_asm_insn ("ldm%?db\t%1, %M0", otherops);
- return "";
- case -4:
- output_asm_insn ("ldm%?da\t%1, %M0", otherops);
- return "";
- case 4:
- output_asm_insn ("ldm%?ib\t%1, %M0", otherops);
- return "";
- }
-
- if (!(const_ok_for_arm (INTVAL (otherops[2]))))
- output_asm_insn ("sub%?\t%0, %1, #%n2", otherops);
- else
- output_asm_insn ("add%?\t%0, %1, %2", otherops);
+ case -8:
+ output_asm_insn ("ldm%?db\t%1, %M0", otherops);
+ return "";
+ case -4:
+ output_asm_insn ("ldm%?da\t%1, %M0", otherops);
+ return "";
+ case 4:
+ output_asm_insn ("ldm%?ib\t%1, %M0", otherops);
+ return "";
}
- else
- output_asm_insn ("add%?\t%0, %1, %2", otherops);
}
- else
- output_asm_insn ("sub%?\t%0, %1, %2", otherops);
-
- return "ldm%?ia\t%0, %M0";
- }
- else
- {
- otherops[1] = adjust_address (operands[1], SImode, 4);
- /* Take care of overlapping base/data reg. */
- if (reg_mentioned_p (operands[0], operands[1]))
+ if (TARGET_LDRD
+ && (GET_CODE (otherops[2]) == REG
+ || (GET_CODE (otherops[2]) == CONST_INT
+ && INTVAL (otherops[2]) > -256
+ && INTVAL (otherops[2]) < 256)))
{
- output_asm_insn ("ldr%?\t%0, %1", otherops);
- output_asm_insn ("ldr%?\t%0, %1", operands);
+ if (reg_overlap_mentioned_p (otherops[0],
+ otherops[2]))
+ {
+ /* Swap base and index registers over to
+ avoid a conflict. */
+ otherops[1] = XEXP (XEXP (operands[1], 0), 1);
+ otherops[2] = XEXP (XEXP (operands[1], 0), 0);
+ }
+ /* If both registers conflict, it will usually
+ have been fixed by a splitter. */
+ if (reg_overlap_mentioned_p (otherops[0], otherops[2]))
+ {
+ output_asm_insn ("add%?\t%1, %1, %2", otherops);
+ output_asm_insn ("ldr%?d\t%0, [%1]",
+ otherops);
+ }
+ else
+ output_asm_insn ("ldr%?d\t%0, [%1, %2]", otherops);
+ return "";
}
- else
+
+ if (GET_CODE (otherops[2]) == CONST_INT)
{
- output_asm_insn ("ldr%?\t%0, %1", operands);
- output_asm_insn ("ldr%?\t%0, %1", otherops);
+ if (!(const_ok_for_arm (INTVAL (otherops[2]))))
+ output_asm_insn ("sub%?\t%0, %1, #%n2", otherops);
+ else
+ output_asm_insn ("add%?\t%0, %1, %2", otherops);
}
+ else
+ output_asm_insn ("add%?\t%0, %1, %2", otherops);
+ }
+ else
+ output_asm_insn ("sub%?\t%0, %1, %2", otherops);
+
+ return "ldm%?ia\t%0, %M0";
+ }
+ else
+ {
+ otherops[1] = adjust_address (operands[1], SImode, 4);
+ /* Take care of overlapping base/data reg. */
+ if (reg_mentioned_p (operands[0], operands[1]))
+ {
+ output_asm_insn ("ldr%?\t%0, %1", otherops);
+ output_asm_insn ("ldr%?\t%0, %1", operands);
+ }
+ else
+ {
+ output_asm_insn ("ldr%?\t%0, %1", operands);
+ output_asm_insn ("ldr%?\t%0, %1", otherops);
}
}
}
- else
- abort (); /* Constraints should prevent this. */
}
- else if (code0 == MEM && code1 == REG)
+ else
{
- if (REGNO (operands[1]) == IP_REGNUM)
- abort ();
+ /* Constraints should ensure this. */
+ gcc_assert (code0 == MEM && code1 == REG);
+ gcc_assert (REGNO (operands[1]) != IP_REGNUM);
switch (GET_CODE (XEXP (operands[0], 0)))
{
@@ -7696,7 +8919,8 @@ output_move_double (rtx *operands)
break;
case PRE_INC:
- abort (); /* Should never happen now. */
+ gcc_assert (TARGET_LDRD);
+ output_asm_insn ("str%?d\t%1, [%m0, #8]!", operands);
break;
case PRE_DEC:
@@ -7708,11 +8932,47 @@ output_move_double (rtx *operands)
break;
case POST_DEC:
- abort (); /* Should never happen now. */
+ gcc_assert (TARGET_LDRD);
+ output_asm_insn ("str%?d\t%1, [%m0], #-8", operands);
+ break;
+
+ case PRE_MODIFY:
+ case POST_MODIFY:
+ otherops[0] = operands[1];
+ otherops[1] = XEXP (XEXP (XEXP (operands[0], 0), 1), 0);
+ otherops[2] = XEXP (XEXP (XEXP (operands[0], 0), 1), 1);
+
+ /* IWMMXT allows offsets larger than ldrd can handle,
+ fix these up with a pair of ldr. */
+ if (GET_CODE (otherops[2]) == CONST_INT
+ && (INTVAL(otherops[2]) <= -256
+ || INTVAL(otherops[2]) >= 256))
+ {
+ rtx reg1;
+ reg1 = gen_rtx_REG (SImode, 1 + REGNO (operands[1]));
+ if (GET_CODE (XEXP (operands[0], 0)) == PRE_MODIFY)
+ {
+ output_asm_insn ("ldr%?\t%0, [%1, %2]!", otherops);
+ otherops[0] = reg1;
+ output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
+ }
+ else
+ {
+ otherops[0] = reg1;
+ output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
+ otherops[0] = operands[1];
+ output_asm_insn ("ldr%?\t%0, [%1], %2", otherops);
+ }
+ }
+ else if (GET_CODE (XEXP (operands[0], 0)) == PRE_MODIFY)
+ output_asm_insn ("str%?d\t%0, [%1, %2]!", otherops);
+ else
+ output_asm_insn ("str%?d\t%0, [%1], %2", otherops);
break;
case PLUS:
- if (GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT)
+ otherops[2] = XEXP (XEXP (operands[0], 0), 1);
+ if (GET_CODE (otherops[2]) == CONST_INT)
{
switch ((int) INTVAL (XEXP (XEXP (operands[0], 0), 1)))
{
@@ -7729,6 +8989,17 @@ output_move_double (rtx *operands)
return "";
}
}
+ if (TARGET_LDRD
+ && (GET_CODE (otherops[2]) == REG
+ || (GET_CODE (otherops[2]) == CONST_INT
+ && INTVAL (otherops[2]) > -256
+ && INTVAL (otherops[2]) < 256)))
+ {
+ otherops[0] = operands[1];
+ otherops[1] = XEXP (XEXP (operands[0], 0), 0);
+ output_asm_insn ("str%?d\t%0, [%1, %2]", otherops);
+ return "";
+ }
/* Fall through */
default:
@@ -7738,46 +9009,6 @@ output_move_double (rtx *operands)
output_asm_insn ("str%?\t%1, %0", otherops);
}
}
- else
- /* Constraints should prevent this. */
- abort ();
-
- return "";
-}
-
-
-/* Output an arbitrary MOV reg, #n.
- OPERANDS[0] is a register. OPERANDS[1] is a const_int. */
-const char *
-output_mov_immediate (rtx *operands)
-{
- HOST_WIDE_INT n = INTVAL (operands[1]);
-
- /* Try to use one MOV. */
- if (const_ok_for_arm (n))
- output_asm_insn ("mov%?\t%0, %1", operands);
-
- /* Try to use one MVN. */
- else if (const_ok_for_arm (~n))
- {
- operands[1] = GEN_INT (~n);
- output_asm_insn ("mvn%?\t%0, %1", operands);
- }
- else
- {
- int n_ones = 0;
- int i;
-
- /* If all else fails, make it out of ORRs or BICs as appropriate. */
- for (i = 0; i < 32; i++)
- if (n & 1 << i)
- n_ones++;
-
- if (n_ones > 16) /* Shorter to use MVN with BIC in this case. */
- output_multi_immediate (operands, "mvn%?\t%0, %1", "bic%?\t%0, %0, %1", 1, ~ n);
- else
- output_multi_immediate (operands, "mov%?\t%0, %1", "orr%?\t%0, %0, %1", 1, n);
- }
return "";
}
@@ -7841,7 +9072,7 @@ output_multi_immediate (rtx *operands, const char *instr1, const char *instr2,
}
}
}
-
+
return "";
}
@@ -7870,7 +9101,7 @@ arithmetic_instr (rtx op, int shift_first_arg)
return "and";
default:
- abort ();
+ gcc_unreachable ();
}
}
@@ -7885,12 +9116,20 @@ shift_op (rtx op, HOST_WIDE_INT *amountp)
const char * mnem;
enum rtx_code code = GET_CODE (op);
- if (GET_CODE (XEXP (op, 1)) == REG || GET_CODE (XEXP (op, 1)) == SUBREG)
- *amountp = -1;
- else if (GET_CODE (XEXP (op, 1)) == CONST_INT)
- *amountp = INTVAL (XEXP (op, 1));
- else
- abort ();
+ switch (GET_CODE (XEXP (op, 1)))
+ {
+ case REG:
+ case SUBREG:
+ *amountp = -1;
+ break;
+
+ case CONST_INT:
+ *amountp = INTVAL (XEXP (op, 1));
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
switch (code)
{
@@ -7906,6 +9145,12 @@ shift_op (rtx op, HOST_WIDE_INT *amountp)
mnem = "lsr";
break;
+ case ROTATE:
+ gcc_assert (*amountp != -1);
+ *amountp = 32 - *amountp;
+
+ /* Fall through. */
+
case ROTATERT:
mnem = "ror";
break;
@@ -7913,14 +9158,12 @@ shift_op (rtx op, HOST_WIDE_INT *amountp)
case MULT:
/* We never have to worry about the amount being other than a
power of 2, since this case can never be reloaded from a reg. */
- if (*amountp != -1)
- *amountp = int_log2 (*amountp);
- else
- abort ();
+ gcc_assert (*amountp != -1);
+ *amountp = int_log2 (*amountp);
return "asl";
default:
- abort ();
+ gcc_unreachable ();
}
if (*amountp != -1)
@@ -7930,7 +9173,7 @@ shift_op (rtx op, HOST_WIDE_INT *amountp)
shift. >=32 is not a valid shift for "asl", so we must try and
output a shift that produces the correct arithmetical result.
Using lsr #32 is identical except for the fact that the carry bit
- is not set correctly if we set the flags; but we never use the
+ is not set correctly if we set the flags; but we never use the
carry bit from such an operation, so we can ignore that. */
if (code == ROTATERT)
/* Rotate is just modulo 32. */
@@ -7945,7 +9188,7 @@ shift_op (rtx op, HOST_WIDE_INT *amountp)
/* Shifts of 0 are no-ops. */
if (*amountp == 0)
return NULL;
- }
+ }
return mnem;
}
@@ -7959,16 +9202,21 @@ int_log2 (HOST_WIDE_INT power)
while ((((HOST_WIDE_INT) 1 << shift) & power) == 0)
{
- if (shift > 31)
- abort ();
+ gcc_assert (shift <= 31);
shift++;
}
return shift;
}
-/* Output a .ascii pseudo-op, keeping track of lengths. This is because
- /bin/as is horribly restrictive. */
+/* Output a .ascii pseudo-op, keeping track of lengths. This is
+ because /bin/as is horribly restrictive. The judgement about
+ whether or not each character is 'printable' (and can be output as
+ is) or not (and must be printed with an octal escape) must be made
+ with reference to the *host* character set -- the situation is
+ similar to that discussed in the comments above pp_c_char in
+ c-pretty-print.c. */
+
#define MAX_ASCII_LEN 51
void
@@ -7978,7 +9226,7 @@ output_ascii_pseudo_op (FILE *stream, const unsigned char *p, int len)
int len_so_far = 0;
fputs ("\t.ascii\t\"", stream);
-
+
for (i = 0; i < len; i++)
{
int c = p[i];
@@ -7989,71 +9237,34 @@ output_ascii_pseudo_op (FILE *stream, const unsigned char *p, int len)
len_so_far = 0;
}
- switch (c)
+ if (ISPRINT (c))
{
- case TARGET_TAB:
- fputs ("\\t", stream);
- len_so_far += 2;
- break;
-
- case TARGET_FF:
- fputs ("\\f", stream);
- len_so_far += 2;
- break;
-
- case TARGET_BS:
- fputs ("\\b", stream);
- len_so_far += 2;
- break;
-
- case TARGET_CR:
- fputs ("\\r", stream);
- len_so_far += 2;
- break;
-
- case TARGET_NEWLINE:
- fputs ("\\n", stream);
- c = p [i + 1];
- if ((c >= ' ' && c <= '~')
- || c == TARGET_TAB)
- /* This is a good place for a line break. */
- len_so_far = MAX_ASCII_LEN;
- else
- len_so_far += 2;
- break;
-
- case '\"':
- case '\\':
- putc ('\\', stream);
- len_so_far++;
- /* Drop through. */
-
- default:
- if (c >= ' ' && c <= '~')
+ if (c == '\\' || c == '\"')
{
- putc (c, stream);
+ putc ('\\', stream);
len_so_far++;
}
- else
- {
- fprintf (stream, "\\%03o", c);
- len_so_far += 4;
- }
- break;
+ putc (c, stream);
+ len_so_far++;
+ }
+ else
+ {
+ fprintf (stream, "\\%03o", c);
+ len_so_far += 4;
}
}
fputs ("\"\n", stream);
}
-/* Compute the register sabe mask for registers 0 through 12
- inclusive. This code is used by both arm_compute_save_reg_mask
- and arm_compute_initial_elimination_offset. */
+/* Compute the register save mask for registers 0 through 12
+ inclusive. This code is used by arm_compute_save_reg_mask. */
+
static unsigned long
arm_compute_save_reg0_reg12_mask (void)
{
unsigned long func_type = arm_current_func_type ();
- unsigned int save_reg_mask = 0;
+ unsigned long save_reg_mask = 0;
unsigned int reg;
if (IS_INTERRUPT (func_type))
@@ -8074,11 +9285,18 @@ arm_compute_save_reg0_reg12_mask (void)
max_reg = 7;
else
max_reg = 12;
-
+
for (reg = 0; reg <= max_reg; reg++)
if (regs_ever_live[reg]
|| (! current_function_is_leaf && call_used_regs [reg]))
save_reg_mask |= (1 << reg);
+
+ /* Also save the pic base register if necessary. */
+ if (flag_pic
+ && !TARGET_SINGLE_PIC_BASE
+ && arm_pic_register != INVALID_REGNUM
+ && current_function_uses_pic_offset_table)
+ save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
}
else
{
@@ -8098,11 +9316,27 @@ arm_compute_save_reg0_reg12_mask (void)
/* If we aren't loading the PIC register,
don't stack it even though it may be live. */
if (flag_pic
- && ! TARGET_SINGLE_PIC_BASE
- && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
+ && !TARGET_SINGLE_PIC_BASE
+ && arm_pic_register != INVALID_REGNUM
+ && (regs_ever_live[PIC_OFFSET_TABLE_REGNUM]
+ || current_function_uses_pic_offset_table))
save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
}
+ /* Save registers so the exception handler can modify them. */
+ if (current_function_calls_eh_return)
+ {
+ unsigned int i;
+
+ for (i = 0; ; i++)
+ {
+ reg = EH_RETURN_DATA_REGNO (i);
+ if (reg == INVALID_REGNUM)
+ break;
+ save_reg_mask |= 1 << reg;
+ }
+ }
+
return save_reg_mask;
}
@@ -8147,7 +9381,8 @@ arm_compute_save_reg_mask (void)
if (regs_ever_live [LR_REGNUM]
|| (save_reg_mask
&& optimize_size
- && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL))
+ && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
+ && !current_function_calls_eh_return))
save_reg_mask |= 1 << LR_REGNUM;
if (cfun->machine->lr_save_eliminated)
@@ -8184,6 +9419,97 @@ arm_compute_save_reg_mask (void)
return save_reg_mask;
}
+
+/* Compute a bit mask of which registers need to be
+ saved on the stack for the current function. */
+static unsigned long
+thumb_compute_save_reg_mask (void)
+{
+ unsigned long mask;
+ unsigned reg;
+
+ mask = 0;
+ for (reg = 0; reg < 12; reg ++)
+ if (regs_ever_live[reg] && !call_used_regs[reg])
+ mask |= 1 << reg;
+
+ if (flag_pic
+ && !TARGET_SINGLE_PIC_BASE
+ && arm_pic_register != INVALID_REGNUM
+ && current_function_uses_pic_offset_table)
+ mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
+
+ /* See if we might need r11 for calls to _interwork_r11_call_via_rN(). */
+ if (!frame_pointer_needed && CALLER_INTERWORKING_SLOT_SIZE > 0)
+ mask |= 1 << ARM_HARD_FRAME_POINTER_REGNUM;
+
+ /* LR will also be pushed if any lo regs are pushed. */
+ if (mask & 0xff || thumb_force_lr_save ())
+ mask |= (1 << LR_REGNUM);
+
+ /* Make sure we have a low work register if we need one.
+ We will need one if we are going to push a high register,
+ but we are not currently intending to push a low register. */
+ if ((mask & 0xff) == 0
+ && ((mask & 0x0f00) || TARGET_BACKTRACE))
+ {
+ /* Use thumb_find_work_register to choose which register
+ we will use. If the register is live then we will
+ have to push it. Use LAST_LO_REGNUM as our fallback
+ choice for the register to select. */
+ reg = thumb_find_work_register (1 << LAST_LO_REGNUM);
+
+ if (! call_used_regs[reg])
+ mask |= 1 << reg;
+ }
+
+ return mask;
+}
+
+
+/* Return the number of bytes required to save VFP registers. */
+static int
+arm_get_vfp_saved_size (void)
+{
+ unsigned int regno;
+ int count;
+ int saved;
+
+ saved = 0;
+ /* Space for saved VFP registers. */
+ if (TARGET_HARD_FLOAT && TARGET_VFP)
+ {
+ count = 0;
+ for (regno = FIRST_VFP_REGNUM;
+ regno < LAST_VFP_REGNUM;
+ regno += 2)
+ {
+ if ((!regs_ever_live[regno] || call_used_regs[regno])
+ && (!regs_ever_live[regno + 1] || call_used_regs[regno + 1]))
+ {
+ if (count > 0)
+ {
+ /* Workaround ARM10 VFPr1 bug. */
+ if (count == 2 && !arm_arch6)
+ count++;
+ saved += count * 8 + 4;
+ }
+ count = 0;
+ }
+ else
+ count++;
+ }
+ if (count > 0)
+ {
+ if (count == 2 && !arm_arch6)
+ count++;
+ saved += count * 8 + 4;
+ }
+ }
+ return saved;
+}
+
+
/* Generate a function exit sequence. If REALLY_RETURN is false, then do
everything bar the final return instruction. */
const char *
@@ -8191,9 +9517,10 @@ output_return_instruction (rtx operand, int really_return, int reverse)
{
char conditional[10];
char instr[100];
- int reg;
+ unsigned reg;
unsigned long live_regs_mask;
unsigned long func_type;
+ arm_stack_offsets *offsets;
func_type = arm_current_func_type ();
@@ -8208,20 +9535,19 @@ output_return_instruction (rtx operand, int really_return, int reverse)
if (really_return)
{
rtx ops[2];
-
+
/* Otherwise, trap an attempted return by aborting. */
ops[0] = operand;
- ops[1] = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)"
+ ops[1] = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)"
: "abort");
assemble_external_libcall (ops[1]);
output_asm_insn (reverse ? "bl%D0\t%a1" : "bl%d0\t%a1", ops);
}
-
+
return "";
}
- if (current_function_calls_alloca && !really_return)
- abort ();
+ gcc_assert (!current_function_calls_alloca || really_return);
sprintf (conditional, "%%?%%%c0", reverse ? 'D' : 'd');
@@ -8233,8 +9559,8 @@ output_return_instruction (rtx operand, int really_return, int reverse)
{
const char * return_reg;
- /* If we do not have any special requirements for function exit
- (eg interworking, or ISR) then we can load the return address
+ /* If we do not have any special requirements for function exit
+ (e.g. interworking, or ISR) then we can load the return address
directly into the PC. Otherwise we must load it into LR. */
if (really_return
&& ! TARGET_INTERWORK)
@@ -8256,11 +9582,7 @@ output_return_instruction (rtx operand, int really_return, int reverse)
live_regs_mask |= (1 << SP_REGNUM);
}
else
- {
- if (! IS_INTERRUPT (func_type)
- && ! TARGET_REALLY_IWMMXT)
- abort ();
- }
+ gcc_assert (IS_INTERRUPT (func_type) || TARGET_REALLY_IWMMXT);
}
/* On some ARM architectures it is faster to use LDR rather than
@@ -8269,16 +9591,15 @@ output_return_instruction (rtx operand, int really_return, int reverse)
we have to use LDM to load the PC so that the CPSR is also
restored. */
for (reg = 0; reg <= LAST_ARM_REGNUM; reg++)
- {
- if (live_regs_mask == (unsigned int)(1 << reg))
- break;
- }
+ if (live_regs_mask == (1U << reg))
+ break;
+
if (reg <= LAST_ARM_REGNUM
&& (reg != LR_REGNUM
- || ! really_return
- || (TARGET_APCS_32 && ! IS_INTERRUPT (func_type))))
+ || ! really_return
+ || ! IS_INTERRUPT (func_type)))
{
- sprintf (instr, "ldr%s\t%%|%s, [%%|sp], #4", conditional,
+ sprintf (instr, "ldr%s\t%%|%s, [%%|sp], #4", conditional,
(reg == LR_REGNUM) ? return_reg : reg_names[reg]);
}
else
@@ -8292,18 +9613,18 @@ output_return_instruction (rtx operand, int really_return, int reverse)
points to the base of the saved core registers. */
if (live_regs_mask & (1 << SP_REGNUM))
{
- unsigned HOST_WIDE_INT stack_adjust =
- arm_get_frame_size () + current_function_outgoing_args_size;
-
- if (stack_adjust != 0 && stack_adjust != 4)
- abort ();
+ unsigned HOST_WIDE_INT stack_adjust;
+
+ offsets = arm_get_frame_offsets ();
+ stack_adjust = offsets->outgoing_args - offsets->saved_regs;
+ gcc_assert (stack_adjust == 0 || stack_adjust == 4);
if (stack_adjust && arm_arch5)
sprintf (instr, "ldm%sib\t%%|sp, {", conditional);
else
{
- /* If we can't use ldmib (SA110 bug), then try to pop r3
- instead. */
+ /* If we can't use ldmib (SA110 bug),
+ then try to pop r3 instead. */
if (stack_adjust)
live_regs_mask |= 1 << 3;
sprintf (instr, "ldm%sfd\t%%|sp, {", conditional);
@@ -8331,24 +9652,12 @@ output_return_instruction (rtx operand, int really_return, int reverse)
memcpy (p + 2, reg_names[reg], l);
p += l + 2;
}
-
+
if (live_regs_mask & (1 << LR_REGNUM))
{
sprintf (p, "%s%%|%s}", first ? "" : ", ", return_reg);
- /* Decide if we need to add the ^ symbol to the end of the
- register list. This causes the saved condition codes
- register to be copied into the current condition codes
- register. We do the copy if we are conforming to the 32-bit
- ABI and this is an interrupt function, or if we are
- conforming to the 26-bit ABI. There is a special case for
- the 26-bit ABI however, which is if we are writing back the
- stack pointer but not loading the PC. In this case adding
- the ^ symbol would create a type 2 LDM instruction, where
- writeback is UNPREDICTABLE. We are safe in leaving the ^
- character off in this case however, since the actual return
- instruction will be a MOVS which will restore the CPSR. */
- if ((TARGET_APCS_32 && IS_INTERRUPT (func_type))
- || (! TARGET_APCS_32 && really_return))
+ /* If returning from an interrupt, restore the CPSR. */
+ if (IS_INTERRUPT (func_type))
strcat (p, "^");
}
else
@@ -8387,13 +9696,11 @@ output_return_instruction (rtx operand, int really_return, int reverse)
break;
default:
- /* ARMv5 implementations always provide BX, so interworking
- is the default unless APCS-26 is in use. */
- if ((insn_flags & FL_ARCH5) != 0 && TARGET_APCS_32)
- sprintf (instr, "bx%s\t%%|lr", conditional);
+ /* Use bx if it's available. */
+ if (arm_arch5 || arm_arch4t)
+ sprintf (instr, "bx%s\t%%|lr", conditional);
else
- sprintf (instr, "mov%s%s\t%%|pc, %%|lr",
- conditional, TARGET_APCS_32 ? "" : "s");
+ sprintf (instr, "mov%s\t%%|pc, %%|lr", conditional);
break;
}
@@ -8438,7 +9745,7 @@ arm_poke_function_name (FILE *stream, const char *name)
length = strlen (name) + 1;
alignlength = ROUND_UP_WORD (length);
-
+
ASM_OUTPUT_ASCII (stream, name, length);
ASM_OUTPUT_ALIGN (stream, 2);
x = GEN_INT ((unsigned HOST_WIDE_INT) 0xff000000 + alignlength);
@@ -8457,13 +9764,12 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
thumb_output_function_prologue (f, frame_size);
return;
}
-
+
/* Sanity check. */
- if (arm_ccfsm_state || arm_target_insn)
- abort ();
+ gcc_assert (!arm_ccfsm_state && !arm_target_insn);
func_type = arm_current_func_type ();
-
+
switch ((int) ARM_FUNC_TYPE (func_type))
{
default:
@@ -8472,9 +9778,6 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
case ARM_FT_INTERWORKED:
asm_fprintf (f, "\t%@ Function supports interworking.\n");
break;
- case ARM_FT_EXCEPTION_HANDLER:
- asm_fprintf (f, "\t%@ C++ Exception Handler.\n");
- break;
case ARM_FT_ISR:
asm_fprintf (f, "\t%@ Interrupt Service Routine.\n");
break;
@@ -8485,7 +9788,7 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
asm_fprintf (f, "\t%@ ARM Exception Handler.\n");
break;
}
-
+
if (IS_NAKED (func_type))
asm_fprintf (f, "\t%@ Naked Function: prologue and epilogue provided by programmer.\n");
@@ -8494,7 +9797,7 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
if (IS_NESTED (func_type))
asm_fprintf (f, "\t%@ Nested: function declared inside another function.\n");
-
+
asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %wd\n",
current_function_args_size,
current_function_pretend_args_size, frame_size);
@@ -8506,12 +9809,15 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
if (cfun->machine->lr_save_eliminated)
asm_fprintf (f, "\t%@ link register save eliminated.\n");
+ 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;
+ return_used_this_function = 0;
}
const char *
@@ -8520,15 +9826,15 @@ arm_output_epilogue (rtx sibling)
int reg;
unsigned long saved_regs_mask;
unsigned long func_type;
- /* Floats_offset is the offset from the "virtual" frame. In an APCS
+ /* Floats_offset is the offset from the "virtual" frame. In an APCS
frame that is $fp + 4 for a non-variadic function. */
int floats_offset = 0;
rtx operands[3];
- int frame_size = arm_get_frame_size ();
FILE * f = asm_out_file;
- rtx eh_ofs = cfun->machine->eh_epilogue_sp_ofs;
unsigned int lrm_count = 0;
int really_return = (sibling == NULL);
+ int start_reg;
+ arm_stack_offsets *offsets;
/* If we have already generated the return instruction
then it is futile to generate anything else. */
@@ -8544,58 +9850,56 @@ arm_output_epilogue (rtx sibling)
if (IS_VOLATILE (func_type) && TARGET_ABORT_NORETURN)
{
rtx op;
-
+
/* A volatile function should never return. Call abort. */
op = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)" : "abort");
assemble_external_libcall (op);
output_asm_insn ("bl\t%a0", &op);
-
+
return "";
}
- if (ARM_FUNC_TYPE (func_type) == ARM_FT_EXCEPTION_HANDLER
- && ! really_return)
- /* If we are throwing an exception, then we really must
- be doing a return, so we can't tail-call. */
- abort ();
-
+ /* If we are throwing an exception, then we really must be doing a
+ return, so we can't tail-call. */
+ gcc_assert (!current_function_calls_eh_return || really_return);
+
+ offsets = arm_get_frame_offsets ();
saved_regs_mask = arm_compute_save_reg_mask ();
if (TARGET_IWMMXT)
lrm_count = bit_count (saved_regs_mask);
- /* XXX We should adjust floats_offset for any anonymous args, and then
- re-adjust vfp_offset below to compensate. */
-
+ floats_offset = offsets->saved_args;
/* Compute how far away the floats will be. */
for (reg = 0; reg <= LAST_ARM_REGNUM; reg++)
if (saved_regs_mask & (1 << reg))
floats_offset += 4;
-
+
if (frame_pointer_needed)
{
- int vfp_offset = 4;
+ /* This variable is for the Virtual Frame Pointer, not VFP regs. */
+ int vfp_offset = offsets->frame;
if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
{
- for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg--)
+ for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
if (regs_ever_live[reg] && !call_used_regs[reg])
{
floats_offset += 12;
- asm_fprintf (f, "\tldfe\t%r, [%r, #-%d]\n",
+ asm_fprintf (f, "\tldfe\t%r, [%r, #-%d]\n",
reg, FP_REGNUM, floats_offset - vfp_offset);
}
}
else
{
- int start_reg = LAST_ARM_FP_REGNUM;
+ start_reg = LAST_FPA_REGNUM;
- for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg--)
+ for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
{
if (regs_ever_live[reg] && !call_used_regs[reg])
{
floats_offset += 12;
-
+
/* We can't unstack more than four registers at once. */
if (start_reg - reg == 3)
{
@@ -8621,6 +9925,39 @@ arm_output_epilogue (rtx sibling)
FP_REGNUM, floats_offset - vfp_offset);
}
+ if (TARGET_HARD_FLOAT && TARGET_VFP)
+ {
+ int saved_size;
+
+ /* The fldmx insn does not have base+offset addressing modes,
+ so we use IP to hold the address. */
+ saved_size = arm_get_vfp_saved_size ();
+
+ if (saved_size > 0)
+ {
+ floats_offset += saved_size;
+ asm_fprintf (f, "\tsub\t%r, %r, #%d\n", IP_REGNUM,
+ FP_REGNUM, floats_offset - vfp_offset);
+ }
+ start_reg = FIRST_VFP_REGNUM;
+ for (reg = FIRST_VFP_REGNUM; reg < LAST_VFP_REGNUM; reg += 2)
+ {
+ if ((!regs_ever_live[reg] || call_used_regs[reg])
+ && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1]))
+ {
+ if (start_reg != reg)
+ arm_output_fldmx (f, IP_REGNUM,
+ (start_reg - FIRST_VFP_REGNUM) / 2,
+ (reg - start_reg) / 2);
+ start_reg = reg + 2;
+ }
+ }
+ if (start_reg != reg)
+ arm_output_fldmx (f, IP_REGNUM,
+ (start_reg - FIRST_VFP_REGNUM) / 2,
+ (reg - start_reg) / 2);
+ }
+
if (TARGET_IWMMXT)
{
/* The frame pointer is guaranteed to be non-double-word aligned.
@@ -8631,13 +9968,13 @@ arm_output_epilogue (rtx sibling)
We can ignore floats_offset since that was already included in
the live_regs_mask. */
lrm_count += (lrm_count % 2 ? 2 : 1);
-
- for (reg = FIRST_IWMMXT_REGNUM; reg <= LAST_IWMMXT_REGNUM; reg++)
+
+ for (reg = LAST_IWMMXT_REGNUM; reg >= FIRST_IWMMXT_REGNUM; reg--)
if (regs_ever_live[reg] && !call_used_regs[reg])
{
- asm_fprintf (f, "\twldrd\t%r, [%r, #-%d]\n",
+ asm_fprintf (f, "\twldrd\t%r, [%r, #-%d]\n",
reg, FP_REGNUM, lrm_count * 4);
- lrm_count += 2;
+ lrm_count += 2;
}
}
@@ -8645,8 +9982,7 @@ arm_output_epilogue (rtx sibling)
frame generation actually contains the old stack pointer. So a
quick way to unwind the stack is just pop the IP register directly
into the stack pointer. */
- if ((saved_regs_mask & (1 << IP_REGNUM)) == 0)
- abort ();
+ gcc_assert (saved_regs_mask & (1 << IP_REGNUM));
saved_regs_mask &= ~ (1 << IP_REGNUM);
saved_regs_mask |= (1 << SP_REGNUM);
@@ -8654,7 +9990,9 @@ arm_output_epilogue (rtx sibling)
only need to restore the LR register (the return address), but to
save time we can load it directly into the PC, unless we need a
special function exit sequence, or we are not really returning. */
- if (really_return && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL)
+ if (really_return
+ && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
+ && !current_function_calls_eh_return)
/* Delete the LR from the register mask, so that the LR on
the stack is loaded into the PC in the register mask. */
saved_regs_mask &= ~ (1 << LR_REGNUM);
@@ -8670,8 +10008,7 @@ arm_output_epilogue (rtx sibling)
be reset correctly to the original value, should an interrupt
occur. If the stack pointer already points at the right
place, then omit the subtraction. */
- if (((frame_size + current_function_outgoing_args_size + floats_offset)
- != 4 * (1 + (int) bit_count (saved_regs_mask)))
+ if (offsets->outgoing_args != (1 + (int) bit_count (saved_regs_mask))
|| current_function_calls_alloca)
asm_fprintf (f, "\tsub\t%r, %r, #%d\n", SP_REGNUM, FP_REGNUM,
4 * bit_count (saved_regs_mask));
@@ -8685,26 +10022,25 @@ arm_output_epilogue (rtx sibling)
else
{
/* Restore stack pointer if necessary. */
- if (frame_size + current_function_outgoing_args_size != 0)
+ if (offsets->outgoing_args != offsets->saved_regs)
{
operands[0] = operands[1] = stack_pointer_rtx;
- operands[2] = GEN_INT (frame_size
- + current_function_outgoing_args_size);
+ operands[2] = GEN_INT (offsets->outgoing_args - offsets->saved_regs);
output_add_immediate (operands);
}
if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
{
- for (reg = FIRST_ARM_FP_REGNUM; reg <= LAST_ARM_FP_REGNUM; reg++)
+ for (reg = FIRST_FPA_REGNUM; reg <= LAST_FPA_REGNUM; reg++)
if (regs_ever_live[reg] && !call_used_regs[reg])
asm_fprintf (f, "\tldfe\t%r, [%r], #12\n",
reg, SP_REGNUM);
}
else
{
- int start_reg = FIRST_ARM_FP_REGNUM;
+ start_reg = FIRST_FPA_REGNUM;
- for (reg = FIRST_ARM_FP_REGNUM; reg <= LAST_ARM_FP_REGNUM; reg++)
+ for (reg = FIRST_FPA_REGNUM; reg <= LAST_FPA_REGNUM; reg++)
{
if (regs_ever_live[reg] && !call_used_regs[reg])
{
@@ -8721,7 +10057,7 @@ arm_output_epilogue (rtx sibling)
asm_fprintf (f, "\tlfmfd\t%r, %d, [%r]!\n",
start_reg, reg - start_reg,
SP_REGNUM);
-
+
start_reg = reg + 1;
}
}
@@ -8732,16 +10068,37 @@ arm_output_epilogue (rtx sibling)
start_reg, reg - start_reg, SP_REGNUM);
}
+ if (TARGET_HARD_FLOAT && TARGET_VFP)
+ {
+ start_reg = FIRST_VFP_REGNUM;
+ for (reg = FIRST_VFP_REGNUM; reg < LAST_VFP_REGNUM; reg += 2)
+ {
+ if ((!regs_ever_live[reg] || call_used_regs[reg])
+ && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1]))
+ {
+ if (start_reg != reg)
+ arm_output_fldmx (f, SP_REGNUM,
+ (start_reg - FIRST_VFP_REGNUM) / 2,
+ (reg - start_reg) / 2);
+ start_reg = reg + 2;
+ }
+ }
+ if (start_reg != reg)
+ arm_output_fldmx (f, SP_REGNUM,
+ (start_reg - FIRST_VFP_REGNUM) / 2,
+ (reg - start_reg) / 2);
+ }
if (TARGET_IWMMXT)
for (reg = FIRST_IWMMXT_REGNUM; reg <= LAST_IWMMXT_REGNUM; reg++)
if (regs_ever_live[reg] && !call_used_regs[reg])
- asm_fprintf (f, "\twldrd\t%r, [%r, #+8]!\n", reg, SP_REGNUM);
+ asm_fprintf (f, "\twldrd\t%r, [%r], #8\n", reg, SP_REGNUM);
/* If we can, restore the LR into the PC. */
if (ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
&& really_return
&& current_function_pretend_args_size == 0
- && saved_regs_mask & (1 << LR_REGNUM))
+ && saved_regs_mask & (1 << LR_REGNUM)
+ && !current_function_calls_eh_return)
{
saved_regs_mask &= ~ (1 << LR_REGNUM);
saved_regs_mask |= (1 << PC_REGNUM);
@@ -8751,18 +10108,13 @@ arm_output_epilogue (rtx sibling)
to load use the LDR instruction - it is faster. */
if (saved_regs_mask == (1 << LR_REGNUM))
{
- /* The exception handler ignores the LR, so we do
- not really need to load it off the stack. */
- if (eh_ofs)
- asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM);
- else
- asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM);
+ asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM);
}
else if (saved_regs_mask)
{
if (saved_regs_mask & (1 << SP_REGNUM))
/* Note - write back to the stack register is not enabled
- (ie "ldmfd sp!..."). We know that the stack pointer is
+ (i.e. "ldmfd sp!..."). We know that the stack pointer is
in the list of registers and if we add writeback the
instruction becomes UNPREDICTABLE. */
print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask);
@@ -8779,21 +10131,18 @@ arm_output_epilogue (rtx sibling)
}
}
- if (! really_return
- || (ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
- && current_function_pretend_args_size == 0
- && saved_regs_mask & (1 << PC_REGNUM)))
+ /* We may have already restored PC directly from the stack. */
+ if (!really_return || saved_regs_mask & (1 << PC_REGNUM))
return "";
+ /* Stack adjustment for exception handler. */
+ if (current_function_calls_eh_return)
+ asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
+ ARM_EH_STACKADJ_REGNUM);
+
/* Generate the return instruction. */
switch ((int) ARM_FUNC_TYPE (func_type))
{
- case ARM_FT_EXCEPTION_HANDLER:
- /* Even in 26-bit mode we do a mov (rather than a movs)
- because we don't have the PSR bits set in the address. */
- asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, EXCEPTION_LR_REGNUM);
- break;
-
case ARM_FT_ISR:
case ARM_FT_FIQ:
asm_fprintf (f, "\tsubs\t%r, %r, #4\n", PC_REGNUM, LR_REGNUM);
@@ -8808,21 +10157,10 @@ arm_output_epilogue (rtx sibling)
break;
default:
- if (frame_pointer_needed)
- /* If we used the frame pointer then the return address
- will have been loaded off the stack directly into the
- PC, so there is no need to issue a MOV instruction
- here. */
- ;
- else if (current_function_pretend_args_size == 0
- && (saved_regs_mask & (1 << LR_REGNUM)))
- /* Similarly we may have been able to load LR into the PC
- even if we did not create a stack frame. */
- ;
- else if (TARGET_APCS_32)
- asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, LR_REGNUM);
+ if (arm_arch5 || arm_arch4t)
+ asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM);
else
- asm_fprintf (f, "\tmovs\t%r, %r\n", PC_REGNUM, LR_REGNUM);
+ asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, LR_REGNUM);
break;
}
@@ -8831,10 +10169,29 @@ arm_output_epilogue (rtx sibling)
static void
arm_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
- HOST_WIDE_INT frame_size)
+ HOST_WIDE_INT frame_size ATTRIBUTE_UNUSED)
{
+ arm_stack_offsets *offsets;
+
if (TARGET_THUMB)
{
+ int regno;
+
+ /* Emit any call-via-reg trampolines that are needed for v4t support
+ of call_reg and call_value_reg type insns. */
+ for (regno = 0; regno < LR_REGNUM; regno++)
+ {
+ rtx label = cfun->machine->call_via[regno];
+
+ if (label != NULL)
+ {
+ switch_to_section (function_section (current_function_decl));
+ targetm.asm_out.internal_label (asm_out_file, "L",
+ CODE_LABEL_NUMBER (label));
+ asm_fprintf (asm_out_file, "\tbx\t%r\n", regno);
+ }
+ }
+
/* ??? Probably not safe to set this here, since it assumes that a
function will be emitted as assembly immediately after we generate
RTL for it. This does not happen for inline functions. */
@@ -8843,13 +10200,12 @@ arm_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
else
{
/* We need to take into account any stack-frame rounding. */
- frame_size = arm_get_frame_size ();
+ offsets = arm_get_frame_offsets ();
- if (use_return_insn (FALSE, NULL)
- && return_used_this_function
- && (frame_size + current_function_outgoing_args_size) != 0
- && !frame_pointer_needed)
- abort ();
+ gcc_assert (!use_return_insn (FALSE, NULL)
+ || !return_used_this_function
+ || offsets->saved_regs == offsets->outgoing_args
+ || frame_pointer_needed);
/* Reset the ARM-specific per-function variables. */
after_arm_reorg = 0;
@@ -8861,7 +10217,7 @@ arm_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
semantics of the operation, we need to annotate the insn for the benefit
of DWARF2 frame unwind information. */
static rtx
-emit_multi_reg_push (int mask)
+emit_multi_reg_push (unsigned long mask)
{
int num_regs = 0;
int num_dwarf_regs;
@@ -8875,8 +10231,7 @@ emit_multi_reg_push (int mask)
if (mask & (1 << i))
num_regs++;
- if (num_regs == 0 || num_regs > 16)
- abort ();
+ gcc_assert (num_regs && num_regs <= 16);
/* We don't record the PC in the dwarf frame information. */
num_dwarf_regs = num_regs;
@@ -8888,7 +10243,7 @@ emit_multi_reg_push (int mask)
by the push_multi pattern in the arm.md file. The insn looks
something like this:
- (parallel [
+ (parallel [
(set (mem:BLK (pre_dec:BLK (reg:SI sp)))
(unspec:BLK [(reg:SI r4)] UNSPEC_PUSH_MULT))
(use (reg:SI 11 fp))
@@ -8904,7 +10259,7 @@ emit_multi_reg_push (int mask)
stack decrement per instruction. The RTL we generate for the note looks
something like this:
- (sequence [
+ (sequence [
(set (reg:SI sp) (plus:SI (reg:SI sp) (const_int -20)))
(set (mem:SI (reg:SI sp)) (reg:SI r4))
(set (mem:SI (plus:SI (reg:SI sp) (const_int 4))) (reg:SI fp))
@@ -8914,7 +10269,7 @@ emit_multi_reg_push (int mask)
This sequence is used both by the code to support stack unwinding for
exceptions handlers and the code to generate dwarf2 frame debugging. */
-
+
par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_regs));
dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (num_dwarf_regs + 1));
dwarf_par_index = 1;
@@ -8927,9 +10282,9 @@ emit_multi_reg_push (int mask)
XVECEXP (par, 0, 0)
= gen_rtx_SET (VOIDmode,
- gen_rtx_MEM (BLKmode,
- gen_rtx_PRE_DEC (BLKmode,
- stack_pointer_rtx)),
+ gen_frame_mem (BLKmode,
+ gen_rtx_PRE_DEC (BLKmode,
+ stack_pointer_rtx)),
gen_rtx_UNSPEC (BLKmode,
gen_rtvec (1, reg),
UNSPEC_PUSH_MULT));
@@ -8937,7 +10292,7 @@ emit_multi_reg_push (int mask)
if (i != PC_REGNUM)
{
tmp = gen_rtx_SET (VOIDmode,
- gen_rtx_MEM (SImode, stack_pointer_rtx),
+ gen_frame_mem (SImode, stack_pointer_rtx),
reg);
RTX_FRAME_RELATED_P (tmp) = 1;
XVECEXP (dwarf, 0, dwarf_par_index) = tmp;
@@ -8958,11 +10313,12 @@ emit_multi_reg_push (int mask)
if (i != PC_REGNUM)
{
- tmp = gen_rtx_SET (VOIDmode,
- gen_rtx_MEM (SImode,
+ tmp
+ = gen_rtx_SET (VOIDmode,
+ gen_frame_mem (SImode,
plus_constant (stack_pointer_rtx,
4 * j)),
- reg);
+ reg);
RTX_FRAME_RELATED_P (tmp) = 1;
XVECEXP (dwarf, 0, dwarf_par_index++) = tmp;
}
@@ -8972,20 +10328,32 @@ emit_multi_reg_push (int mask)
}
par = emit_insn (par);
-
- tmp = gen_rtx_SET (SImode,
+
+ tmp = gen_rtx_SET (VOIDmode,
stack_pointer_rtx,
- gen_rtx_PLUS (SImode,
- stack_pointer_rtx,
- GEN_INT (-4 * num_regs)));
+ plus_constant (stack_pointer_rtx, -4 * num_regs));
RTX_FRAME_RELATED_P (tmp) = 1;
XVECEXP (dwarf, 0, 0) = tmp;
-
+
REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
REG_NOTES (par));
return par;
}
+/* Calculate the size of the return value that is passed in registers. */
+static int
+arm_size_return_regs (void)
+{
+ enum machine_mode mode;
+
+ if (current_function_return_rtx != 0)
+ mode = GET_MODE (current_function_return_rtx);
+ else
+ mode = DECL_MODE (DECL_RESULT (current_function_decl));
+
+ return GET_MODE_SIZE (mode);
+}
+
static rtx
emit_sfm (int base_reg, int count)
{
@@ -8995,48 +10363,67 @@ emit_sfm (int base_reg, int count)
int i;
par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
- dwarf = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
+ dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (count + 1));
reg = gen_rtx_REG (XFmode, base_reg++);
XVECEXP (par, 0, 0)
- = gen_rtx_SET (VOIDmode,
- gen_rtx_MEM (BLKmode,
- gen_rtx_PRE_DEC (BLKmode, stack_pointer_rtx)),
+ = gen_rtx_SET (VOIDmode,
+ gen_frame_mem (BLKmode,
+ gen_rtx_PRE_DEC (BLKmode,
+ stack_pointer_rtx)),
gen_rtx_UNSPEC (BLKmode,
gen_rtvec (1, reg),
UNSPEC_PUSH_MULT));
- tmp
- = gen_rtx_SET (VOIDmode,
- gen_rtx_MEM (XFmode,
- gen_rtx_PRE_DEC (BLKmode, stack_pointer_rtx)),
- reg);
+ tmp = gen_rtx_SET (VOIDmode,
+ gen_frame_mem (XFmode, stack_pointer_rtx), reg);
RTX_FRAME_RELATED_P (tmp) = 1;
- XVECEXP (dwarf, 0, count - 1) = tmp;
-
+ XVECEXP (dwarf, 0, 1) = tmp;
+
for (i = 1; i < count; i++)
{
reg = gen_rtx_REG (XFmode, base_reg++);
XVECEXP (par, 0, i) = gen_rtx_USE (VOIDmode, reg);
- tmp = gen_rtx_SET (VOIDmode,
- gen_rtx_MEM (XFmode,
- gen_rtx_PRE_DEC (BLKmode,
- stack_pointer_rtx)),
+ tmp = gen_rtx_SET (VOIDmode,
+ gen_frame_mem (XFmode,
+ plus_constant (stack_pointer_rtx,
+ i * 12)),
reg);
RTX_FRAME_RELATED_P (tmp) = 1;
- XVECEXP (dwarf, 0, count - i - 1) = tmp;
+ XVECEXP (dwarf, 0, i + 1) = tmp;
}
+ tmp = gen_rtx_SET (VOIDmode,
+ stack_pointer_rtx,
+ plus_constant (stack_pointer_rtx, -12 * count));
+
+ RTX_FRAME_RELATED_P (tmp) = 1;
+ XVECEXP (dwarf, 0, 0) = tmp;
+
par = emit_insn (par);
REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
REG_NOTES (par));
return par;
}
+
+/* Return true if the current function needs to save/restore LR. */
+
+static bool
+thumb_force_lr_save (void)
+{
+ return !cfun->machine->lr_save_eliminated
+ && (!leaf_function_p ()
+ || thumb_far_jump_used_p ()
+ || regs_ever_live [LR_REGNUM]);
+}
+
+
/* Compute the distance from register FROM to register TO.
These can be the arg pointer (26), the soft frame pointer (25),
the stack pointer (13) or the hard frame pointer (11).
+ In thumb mode r7 is used as the soft frame pointer, if needed.
Typical stack layout looks like this:
old stack pointer -> | |
@@ -9059,7 +10446,7 @@ emit_sfm (int base_reg, int count)
| | \
| | local
| | variables
- | | /
+ locals base pointer -> | | /
--
| | \
| | outgoing
@@ -9076,60 +10463,131 @@ emit_sfm (int base_reg, int count)
The sign of the number returned reflects the direction of stack
growth, so the values are positive for all eliminations except
- from the soft frame pointer to the hard frame pointer. */
-unsigned int
-arm_compute_initial_elimination_offset (unsigned int from, unsigned int to)
+ from the soft frame pointer to the hard frame pointer.
+
+ SFP may point just inside the local variables block to ensure correct
+ alignment. */
+
+
+/* Calculate stack offsets. These are used to calculate register elimination
+ offsets and in prologue/epilogue code. */
+
+static arm_stack_offsets *
+arm_get_frame_offsets (void)
{
- unsigned int local_vars = arm_get_frame_size ();
- unsigned int outgoing_args = current_function_outgoing_args_size;
- unsigned int stack_frame;
- unsigned int call_saved_registers;
+ struct arm_stack_offsets *offsets;
unsigned long func_type;
-
- func_type = arm_current_func_type ();
+ int leaf;
+ int saved;
+ HOST_WIDE_INT frame_size;
- /* Volatile functions never return, so there is
- no need to save call saved registers. */
- call_saved_registers = 0;
- if (! IS_VOLATILE (func_type))
+ offsets = &cfun->machine->stack_offsets;
+
+ /* We need to know if we are a leaf function. Unfortunately, it
+ is possible to be called after start_sequence has been called,
+ which causes get_insns to return the insns for the sequence,
+ not the function, which will cause leaf_function_p to return
+ the incorrect result.
+
+ to know about leaf functions once reload has completed, and the
+ frame size cannot be changed after that time, so we can safely
+ use the cached value. */
+
+ if (reload_completed)
+ return offsets;
+
+ /* Initially this is the size of the local variables. It will translated
+ into an offset once we have determined the size of preceding data. */
+ frame_size = ROUND_UP_WORD (get_frame_size ());
+
+ leaf = leaf_function_p ();
+
+ /* Space for variadic functions. */
+ offsets->saved_args = current_function_pretend_args_size;
+
+ offsets->frame = offsets->saved_args + (frame_pointer_needed ? 4 : 0);
+
+ if (TARGET_ARM)
{
- unsigned int reg_mask;
- unsigned int reg;
+ unsigned int regno;
- /* Make sure that we compute which registers will be saved
- on the stack using the same algorithm that is used by
- the prologue creation code. */
- reg_mask = arm_compute_save_reg_mask ();
-
- /* Now count the number of bits set in save_reg_mask.
- If we have already counted the registers in the stack
- frame, do not count them again. Non call-saved registers
- might be saved in the call-save area of the stack, if
- doing so will preserve the stack's alignment. Hence we
- must count them here. For each set bit we need 4 bytes
- of stack space. */
- if (frame_pointer_needed)
- reg_mask &= 0x07ff;
- call_saved_registers += 4 * bit_count (reg_mask);
+ saved = bit_count (arm_compute_save_reg_mask ()) * 4;
- /* If the hard floating point registers are going to be
- used then they must be saved on the stack as well.
- Each register occupies 12 bytes of stack space. */
- for (reg = FIRST_ARM_FP_REGNUM; reg <= LAST_ARM_FP_REGNUM; reg++)
- if (regs_ever_live[reg] && ! call_used_regs[reg])
- call_saved_registers += 12;
+ /* We know that SP will be doubleword aligned on entry, and we must
+ preserve that condition at any subroutine call. We also require the
+ soft frame pointer to be doubleword aligned. */
if (TARGET_REALLY_IWMMXT)
- /* Check for the call-saved iWMMXt registers. */
- for (reg = FIRST_IWMMXT_REGNUM; reg <= LAST_IWMMXT_REGNUM; reg++)
- if (regs_ever_live[reg] && ! call_used_regs [reg])
- call_saved_registers += 8;
+ {
+ /* Check for the call-saved iWMMXt registers. */
+ for (regno = FIRST_IWMMXT_REGNUM;
+ regno <= LAST_IWMMXT_REGNUM;
+ regno++)
+ if (regs_ever_live [regno] && ! call_used_regs [regno])
+ saved += 8;
+ }
+
+ func_type = arm_current_func_type ();
+ if (! IS_VOLATILE (func_type))
+ {
+ /* Space for saved FPA registers. */
+ for (regno = FIRST_FPA_REGNUM; regno <= LAST_FPA_REGNUM; regno++)
+ if (regs_ever_live[regno] && ! call_used_regs[regno])
+ saved += 12;
+
+ /* Space for saved VFP registers. */
+ if (TARGET_HARD_FLOAT && TARGET_VFP)
+ saved += arm_get_vfp_saved_size ();
+ }
+ }
+ else /* TARGET_THUMB */
+ {
+ saved = bit_count (thumb_compute_save_reg_mask ()) * 4;
+ if (TARGET_BACKTRACE)
+ saved += 16;
+ }
+
+ /* Saved registers include the stack frame. */
+ offsets->saved_regs = offsets->saved_args + saved;
+ offsets->soft_frame = offsets->saved_regs + CALLER_INTERWORKING_SLOT_SIZE;
+ /* A leaf function does not need any stack alignment if it has nothing
+ on the stack. */
+ if (leaf && frame_size == 0)
+ {
+ offsets->outgoing_args = offsets->soft_frame;
+ return offsets;
+ }
+
+ /* Ensure SFP has the correct alignment. */
+ if (ARM_DOUBLEWORD_ALIGN
+ && (offsets->soft_frame & 7))
+ offsets->soft_frame += 4;
+
+ offsets->locals_base = offsets->soft_frame + frame_size;
+ offsets->outgoing_args = (offsets->locals_base
+ + current_function_outgoing_args_size);
+
+ if (ARM_DOUBLEWORD_ALIGN)
+ {
+ /* Ensure SP remains doubleword aligned. */
+ if (offsets->outgoing_args & 7)
+ offsets->outgoing_args += 4;
+ gcc_assert (!(offsets->outgoing_args & 7));
}
- /* The stack frame contains 4 registers - the old frame pointer,
- the old stack pointer, the return address and PC of the start
- of the function. */
- stack_frame = frame_pointer_needed ? 16 : 0;
+ return offsets;
+}
+
+
+/* Calculate the relative offsets for the different stack pointers. Positive
+ offsets are in the direction of stack growth. */
+
+HOST_WIDE_INT
+arm_compute_initial_elimination_offset (unsigned int from, unsigned int to)
+{
+ arm_stack_offsets *offsets;
+
+ offsets = arm_get_frame_offsets ();
/* OK, now we have enough information to compute the distances.
There must be an entry in these switch tables for each pair
@@ -9146,29 +10604,27 @@ arm_compute_initial_elimination_offset (unsigned int from, unsigned int to)
case FRAME_POINTER_REGNUM:
/* This is the reverse of the soft frame pointer
to hard frame pointer elimination below. */
- if (call_saved_registers == 0 && stack_frame == 0)
- return 0;
- return (call_saved_registers + stack_frame - 4);
+ return offsets->soft_frame - offsets->saved_args;
case ARM_HARD_FRAME_POINTER_REGNUM:
/* If there is no stack frame then the hard
frame pointer and the arg pointer coincide. */
- if (stack_frame == 0 && call_saved_registers != 0)
+ if (offsets->frame == offsets->saved_regs)
return 0;
/* FIXME: Not sure about this. Maybe we should always return 0 ? */
return (frame_pointer_needed
- && current_function_needs_context
+ && cfun->static_chain_decl != NULL
&& ! cfun->machine->uses_anonymous_args) ? 4 : 0;
case STACK_POINTER_REGNUM:
/* If nothing has been pushed on the stack at all
then this will return -4. This *is* correct! */
- return call_saved_registers + stack_frame + local_vars + outgoing_args - 4;
+ return offsets->outgoing_args - (offsets->saved_args + 4);
default:
- abort ();
+ gcc_unreachable ();
}
- break;
+ gcc_unreachable ();
case FRAME_POINTER_REGNUM:
switch (to)
@@ -9181,17 +10637,16 @@ arm_compute_initial_elimination_offset (unsigned int from, unsigned int to)
stack frame. The soft frame pointer to the bottom entry
in the stack frame. If there is no stack frame at all,
then they are identical. */
- if (call_saved_registers == 0 && stack_frame == 0)
- return 0;
- return - (call_saved_registers + stack_frame - 4);
+
+ return offsets->frame - offsets->soft_frame;
case STACK_POINTER_REGNUM:
- return local_vars + outgoing_args;
+ return offsets->outgoing_args - offsets->soft_frame;
default:
- abort ();
+ gcc_unreachable ();
}
- break;
+ gcc_unreachable ();
default:
/* You cannot eliminate from the stack pointer.
@@ -9199,89 +10654,10 @@ arm_compute_initial_elimination_offset (unsigned int from, unsigned int to)
pointer to the stack pointer, but this will never
happen, since if a stack frame is not needed the
hard frame pointer will never be used. */
- abort ();
+ gcc_unreachable ();
}
}
-/* Calculate the size of the stack frame, taking into account any
- padding that is required to ensure stack-alignment. */
-HOST_WIDE_INT
-arm_get_frame_size (void)
-{
- int regno;
-
- int base_size = ROUND_UP_WORD (get_frame_size ());
- int entry_size = 0;
- unsigned long func_type = arm_current_func_type ();
- int leaf;
-
- if (! TARGET_ARM)
- abort();
-
- if (! TARGET_ATPCS)
- return base_size;
-
- /* We need to know if we are a leaf function. Unfortunately, it
- is possible to be called after start_sequence has been called,
- which causes get_insns to return the insns for the sequence,
- not the function, which will cause leaf_function_p to return
- the incorrect result.
-
- To work around this, we cache the computed frame size. This
- works because we will only be calling RTL expanders that need
- to know about leaf functions once reload has completed, and the
- frame size cannot be changed after that time, so we can safely
- use the cached value. */
-
- if (reload_completed)
- return cfun->machine->frame_size;
-
- leaf = leaf_function_p ();
-
- /* A leaf function does not need any stack alignment if it has nothing
- on the stack. */
- if (leaf && base_size == 0)
- {
- cfun->machine->frame_size = 0;
- return 0;
- }
-
- /* We know that SP will be word aligned on entry, and we must
- preserve that condition at any subroutine call. But those are
- the only constraints. */
-
- /* Space for variadic functions. */
- if (current_function_pretend_args_size)
- entry_size += current_function_pretend_args_size;
-
- /* Space for saved registers. */
- entry_size += bit_count (arm_compute_save_reg_mask ()) * 4;
-
- /* Space for saved FPA registers. */
- if (! IS_VOLATILE (func_type))
- {
- for (regno = FIRST_ARM_FP_REGNUM; regno <= LAST_ARM_FP_REGNUM; regno++)
- if (regs_ever_live[regno] && ! call_used_regs[regno])
- entry_size += 12;
- }
-
- if (TARGET_REALLY_IWMMXT)
- {
- /* Check for the call-saved iWMMXt registers. */
- for (regno = FIRST_IWMMXT_REGNUM; regno <= LAST_IWMMXT_REGNUM; regno++)
- if (regs_ever_live [regno] && ! call_used_regs [regno])
- entry_size += 8;
- }
-
- if ((entry_size + base_size + current_function_outgoing_args_size) & 7)
- base_size += 4;
- if ((entry_size + base_size + current_function_outgoing_args_size) & 7)
- abort ();
-
- cfun->machine->frame_size = base_size;
-
- return base_size;
-}
/* Generate the prologue instructions for entry into an ARM function. */
void
@@ -9295,7 +10671,9 @@ arm_expand_prologue (void)
unsigned long func_type;
int fp_offset = 0;
int saved_pretend_args = 0;
- unsigned int args_to_push;
+ int saved_regs = 0;
+ unsigned HOST_WIDE_INT args_to_push;
+ arm_stack_offsets *offsets;
func_type = arm_current_func_type ();
@@ -9305,7 +10683,7 @@ arm_expand_prologue (void)
/* Make a copy of c_f_p_a_s as we may need to modify it locally. */
args_to_push = current_function_pretend_args_size;
-
+
/* Compute which register we will have to save onto the stack. */
live_regs_mask = arm_compute_save_reg_mask ();
@@ -9325,7 +10703,7 @@ arm_expand_prologue (void)
stack decrement per function, and this is not it. If
this instruction is labeled as being part of the frame
creation sequence then dwarf2out_frame_debug_expr will
- abort when it encounters the assignment of IP to FP
+ die when it encounters the assignment of IP to FP
later on, since the use of SP here establishes SP as
the CFA register and not IP.
@@ -9339,7 +10717,7 @@ arm_expand_prologue (void)
To get around this need to find somewhere to store IP
whilst the frame is being created. We try the following
places in order:
-
+
1. The last argument register.
2. A slot on the stack above the frame. (This only
works if the function is not a varargs function).
@@ -9352,25 +10730,19 @@ arm_expand_prologue (void)
inherited from the caller. */
if (regs_ever_live[3] == 0)
- {
- insn = gen_rtx_REG (SImode, 3);
- insn = gen_rtx_SET (SImode, insn, ip_rtx);
- insn = emit_insn (insn);
- }
+ insn = emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx);
else if (args_to_push == 0)
{
rtx dwarf;
- insn = gen_rtx_PRE_DEC (SImode, stack_pointer_rtx);
- insn = gen_rtx_MEM (SImode, insn);
- insn = gen_rtx_SET (VOIDmode, insn, ip_rtx);
- insn = emit_insn (insn);
+ insn = gen_rtx_PRE_DEC (SImode, stack_pointer_rtx);
+ insn = emit_set_insn (gen_frame_mem (SImode, insn), ip_rtx);
fp_offset = 4;
/* Just tell the dwarf backend that we adjusted SP. */
dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
- gen_rtx_PLUS (SImode, stack_pointer_rtx,
- GEN_INT (-fp_offset)));
+ plus_constant (stack_pointer_rtx,
+ -fp_offset));
RTX_FRAME_RELATED_P (insn) = 1;
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
dwarf, REG_NOTES (insn));
@@ -9383,7 +10755,7 @@ arm_expand_prologue (void)
((0xf0 >> (args_to_push / 4)) & 0xf);
else
insn = emit_insn
- (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+ (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
GEN_INT (- args_to_push)));
RTX_FRAME_RELATED_P (insn) = 1;
@@ -9393,21 +10765,12 @@ arm_expand_prologue (void)
args_to_push = 0;
/* Now reuse r3 to preserve IP. */
- insn = gen_rtx_REG (SImode, 3);
- insn = gen_rtx_SET (SImode, insn, ip_rtx);
- (void) emit_insn (insn);
+ emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx);
}
}
- if (fp_offset)
- {
- insn = gen_rtx_PLUS (SImode, stack_pointer_rtx, GEN_INT (fp_offset));
- insn = gen_rtx_SET (SImode, ip_rtx, insn);
- }
- else
- insn = gen_movsi (ip_rtx, stack_pointer_rtx);
-
- insn = emit_insn (insn);
+ insn = emit_set_insn (ip_rtx,
+ plus_constant (stack_pointer_rtx, fp_offset));
RTX_FRAME_RELATED_P (insn) = 1;
}
@@ -9419,7 +10782,7 @@ arm_expand_prologue (void)
((0xf0 >> (args_to_push / 4)) & 0xf);
else
insn = emit_insn
- (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+ (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
GEN_INT (- args_to_push)));
RTX_FRAME_RELATED_P (insn) = 1;
}
@@ -9432,50 +10795,53 @@ arm_expand_prologue (void)
if ((func_type == ARM_FT_ISR || func_type == ARM_FT_FIQ)
&& (live_regs_mask & (1 << LR_REGNUM)) != 0
&& ! frame_pointer_needed)
- emit_insn (gen_rtx_SET (SImode,
- gen_rtx_REG (SImode, LR_REGNUM),
- gen_rtx_PLUS (SImode,
- gen_rtx_REG (SImode, LR_REGNUM),
- GEN_INT (-4))));
+ {
+ rtx lr = gen_rtx_REG (SImode, LR_REGNUM);
+
+ emit_set_insn (lr, plus_constant (lr, -4));
+ }
if (live_regs_mask)
{
insn = emit_multi_reg_push (live_regs_mask);
+ saved_regs += bit_count (live_regs_mask) * 4;
RTX_FRAME_RELATED_P (insn) = 1;
}
if (TARGET_IWMMXT)
- for (reg = FIRST_IWMMXT_REGNUM; reg <= LAST_IWMMXT_REGNUM; reg++)
+ for (reg = LAST_IWMMXT_REGNUM; reg >= FIRST_IWMMXT_REGNUM; reg--)
if (regs_ever_live[reg] && ! call_used_regs [reg])
{
insn = gen_rtx_PRE_DEC (V2SImode, stack_pointer_rtx);
- insn = gen_rtx_MEM (V2SImode, insn);
- insn = emit_insn (gen_rtx_SET (VOIDmode, insn,
- gen_rtx_REG (V2SImode, reg)));
+ insn = gen_frame_mem (V2SImode, insn);
+ insn = emit_set_insn (insn, gen_rtx_REG (V2SImode, reg));
RTX_FRAME_RELATED_P (insn) = 1;
+ saved_regs += 8;
}
if (! IS_VOLATILE (func_type))
{
+ int start_reg;
+
/* Save any floating point call-saved registers used by this
function. */
if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
{
- for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg--)
+ for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
if (regs_ever_live[reg] && !call_used_regs[reg])
{
insn = gen_rtx_PRE_DEC (XFmode, stack_pointer_rtx);
- insn = gen_rtx_MEM (XFmode, insn);
- insn = emit_insn (gen_rtx_SET (VOIDmode, insn,
- gen_rtx_REG (XFmode, reg)));
+ insn = gen_frame_mem (XFmode, insn);
+ insn = emit_set_insn (insn, gen_rtx_REG (XFmode, reg));
RTX_FRAME_RELATED_P (insn) = 1;
+ saved_regs += 12;
}
}
else
{
- int start_reg = LAST_ARM_FP_REGNUM;
+ start_reg = LAST_FPA_REGNUM;
- for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg--)
+ for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
{
if (regs_ever_live[reg] && !call_used_regs[reg])
{
@@ -9483,6 +10849,7 @@ arm_expand_prologue (void)
{
insn = emit_sfm (reg, 4);
RTX_FRAME_RELATED_P (insn) = 1;
+ saved_regs += 48;
start_reg = reg - 1;
}
}
@@ -9492,6 +10859,7 @@ arm_expand_prologue (void)
{
insn = emit_sfm (reg + 1, start_reg - reg);
RTX_FRAME_RELATED_P (insn) = 1;
+ saved_regs += (start_reg - reg) * 12;
}
start_reg = reg - 1;
}
@@ -9500,9 +10868,29 @@ arm_expand_prologue (void)
if (start_reg != reg)
{
insn = emit_sfm (reg + 1, start_reg - reg);
+ saved_regs += (start_reg - reg) * 12;
RTX_FRAME_RELATED_P (insn) = 1;
}
}
+ if (TARGET_HARD_FLOAT && TARGET_VFP)
+ {
+ start_reg = FIRST_VFP_REGNUM;
+
+ for (reg = FIRST_VFP_REGNUM; reg < LAST_VFP_REGNUM; reg += 2)
+ {
+ if ((!regs_ever_live[reg] || call_used_regs[reg])
+ && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1]))
+ {
+ if (start_reg != reg)
+ saved_regs += vfp_emit_fstmx (start_reg,
+ (reg - start_reg) / 2);
+ start_reg = reg + 2;
+ }
+ }
+ if (start_reg != reg)
+ saved_regs += vfp_emit_fstmx (start_reg,
+ (reg - start_reg) / 2);
+ }
}
if (frame_pointer_needed)
@@ -9511,7 +10899,7 @@ arm_expand_prologue (void)
insn = GEN_INT (-(4 + args_to_push + fp_offset));
insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, ip_rtx, insn));
RTX_FRAME_RELATED_P (insn) = 1;
-
+
if (IS_NESTED (func_type))
{
/* Recover the static chain register. */
@@ -9520,25 +10908,26 @@ arm_expand_prologue (void)
insn = gen_rtx_REG (SImode, 3);
else /* if (current_function_pretend_args_size == 0) */
{
- insn = gen_rtx_PLUS (SImode, hard_frame_pointer_rtx,
- GEN_INT (4));
- insn = gen_rtx_MEM (SImode, insn);
+ insn = plus_constant (hard_frame_pointer_rtx, 4);
+ insn = gen_frame_mem (SImode, insn);
}
- emit_insn (gen_rtx_SET (SImode, ip_rtx, insn));
+ emit_set_insn (ip_rtx, insn);
/* Add a USE to stop propagate_one_insn() from barfing. */
emit_insn (gen_prologue_use (ip_rtx));
}
}
- amount = GEN_INT (-(arm_get_frame_size ()
- + current_function_outgoing_args_size));
-
- if (amount != const0_rtx)
+ offsets = arm_get_frame_offsets ();
+ if (offsets->outgoing_args != offsets->saved_args + saved_regs)
{
/* This add can produce multiple insns for a large constant, so we
need to get tricky. */
rtx last = get_last_insn ();
+
+ amount = GEN_INT (offsets->saved_args + saved_regs
+ - offsets->outgoing_args);
+
insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
amount));
do
@@ -9556,10 +10945,17 @@ arm_expand_prologue (void)
hard_frame_pointer_rtx));
}
+
+ if (flag_pic && arm_pic_register != INVALID_REGNUM)
+ arm_load_pic_register (0UL);
+
/* If we are profiling, make sure no instructions are scheduled before
the call to mcount. Similarly if the user has requested no
- scheduling in the prolog. */
- if (current_function_profile || TARGET_NO_SCHED_PRO)
+ scheduling in the prolog. Similarly if we want non-call exceptions
+ using the EABI unwinder, to prevent faulting instructions from being
+ swapped with a stack adjustment. */
+ if (current_function_profile || !TARGET_SCHED_PROLOG
+ || (ARM_EABI_UNWIND_TABLES && flag_non_call_exceptions))
emit_insn (gen_blockage ());
/* If the link register is being kept alive, with the return address in it,
@@ -9596,7 +10992,7 @@ arm_print_operand (FILE *stream, rtx x, int code)
case '_':
fputs (user_label_prefix, stream);
return;
-
+
case '|':
fputs (REGISTER_PREFIX, stream);
return;
@@ -9604,8 +11000,17 @@ arm_print_operand (FILE *stream, rtx x, int code)
case '?':
if (arm_ccfsm_state == 3 || arm_ccfsm_state == 4)
{
- if (TARGET_THUMB || current_insn_predicate != NULL)
- abort ();
+ if (TARGET_THUMB)
+ {
+ output_operand_lossage ("predicated Thumb instruction");
+ break;
+ }
+ if (current_insn_predicate != NULL)
+ {
+ output_operand_lossage
+ ("predicated instruction in conditional sequence");
+ break;
+ }
fputs (arm_condition_codes[arm_current_cc], stream);
}
@@ -9614,7 +11019,10 @@ arm_print_operand (FILE *stream, rtx x, int code)
enum arm_cond_code code;
if (TARGET_THUMB)
- abort ();
+ {
+ output_operand_lossage ("predicated Thumb instruction");
+ break;
+ }
code = get_arm_condition_code (current_insn_predicate);
fputs (arm_condition_codes[code], stream);
@@ -9665,11 +11073,19 @@ arm_print_operand (FILE *stream, rtx x, int code)
case 'S':
{
HOST_WIDE_INT val;
- const char * shift = shift_op (x, &val);
+ const char *shift;
+
+ if (!shift_operator (x, SImode))
+ {
+ output_operand_lossage ("invalid shift operand");
+ break;
+ }
+
+ shift = shift_op (x, &val);
if (shift)
{
- fprintf (stream, ", %s ", shift_op (x, &val));
+ fprintf (stream, ", %s ", shift);
if (val == -1)
arm_print_operand (stream, XEXP (x, 1), 0);
else
@@ -9679,19 +11095,19 @@ arm_print_operand (FILE *stream, rtx x, int code)
return;
/* An explanation of the 'Q', 'R' and 'H' register operands:
-
+
In a pair of registers containing a DI or DF value the 'Q'
operand returns the register number of the register containing
the least significant part of the value. The 'R' operand returns
the register number of the register containing the most
significant part of the value.
-
+
The 'H' operand returns the higher of the two register numbers.
On a run where WORDS_BIG_ENDIAN is true the 'H' operand is the
same as the 'Q' operand, since the most significant part of the
value is held in the lower number register. The reverse is true
on systems where WORDS_BIG_ENDIAN is false.
-
+
The purpose of these operands is to distinguish between cases
where the endian-ness of the values is important (for example
when they are added together), and cases where the endian-ness
@@ -9706,25 +11122,37 @@ arm_print_operand (FILE *stream, rtx x, int code)
of the memory location is actually held in one of the registers
being overwritten by the load. */
case 'Q':
- if (REGNO (x) > LAST_ARM_REGNUM)
- abort ();
+ if (GET_CODE (x) != REG || REGNO (x) > LAST_ARM_REGNUM)
+ {
+ output_operand_lossage ("invalid operand for code '%c'", code);
+ return;
+ }
+
asm_fprintf (stream, "%r", REGNO (x) + (WORDS_BIG_ENDIAN ? 1 : 0));
return;
case 'R':
- if (REGNO (x) > LAST_ARM_REGNUM)
- abort ();
+ if (GET_CODE (x) != REG || REGNO (x) > LAST_ARM_REGNUM)
+ {
+ output_operand_lossage ("invalid operand for code '%c'", code);
+ return;
+ }
+
asm_fprintf (stream, "%r", REGNO (x) + (WORDS_BIG_ENDIAN ? 0 : 1));
return;
case 'H':
- if (REGNO (x) > LAST_ARM_REGNUM)
- abort ();
+ if (GET_CODE (x) != REG || REGNO (x) > LAST_ARM_REGNUM)
+ {
+ output_operand_lossage ("invalid operand for code '%c'", code);
+ return;
+ }
+
asm_fprintf (stream, "%r", REGNO (x) + 1);
return;
case 'm':
- asm_fprintf (stream, "%r",
+ asm_fprintf (stream, "%r",
GET_CODE (XEXP (x, 0)) == REG
? REGNO (XEXP (x, 0)) : REGNO (XEXP (XEXP (x, 0), 0)));
return;
@@ -9739,16 +11167,30 @@ arm_print_operand (FILE *stream, rtx x, int code)
/* CONST_TRUE_RTX means always -- that's the default. */
if (x == const_true_rtx)
return;
-
+
+ if (!COMPARISON_P (x))
+ {
+ output_operand_lossage ("invalid operand for code '%c'", code);
+ return;
+ }
+
fputs (arm_condition_codes[get_arm_condition_code (x)],
stream);
return;
case 'D':
- /* CONST_TRUE_RTX means not always -- ie never. We shouldn't ever
+ /* CONST_TRUE_RTX means not always -- i.e. never. We shouldn't ever
want to do that. */
if (x == const_true_rtx)
- abort ();
+ {
+ output_operand_lossage ("instruction never exectued");
+ return;
+ }
+ if (!COMPARISON_P (x))
+ {
+ output_operand_lossage ("invalid operand for code '%c'", code);
+ return;
+ }
fputs (arm_condition_codes[ARM_INVERSE_CONDITION_CODE
(get_arm_condition_code (x))],
@@ -9764,8 +11206,8 @@ arm_print_operand (FILE *stream, rtx x, int code)
case 'X': /* Cirrus register in D mode. */
case 'Y': /* Cirrus register in FX mode. */
case 'Z': /* Cirrus register in DX mode. */
- if (GET_CODE (x) != REG || REGNO_REG_CLASS (REGNO (x)) != CIRRUS_REGS)
- abort ();
+ gcc_assert (GET_CODE (x) == REG
+ && REGNO_REG_CLASS (REGNO (x)) == CIRRUS_REGS);
fprintf (stream, "mv%s%s",
code == 'W' ? "f"
@@ -9780,7 +11222,10 @@ arm_print_operand (FILE *stream, rtx x, int code)
int mode = GET_MODE (x);
if (GET_CODE (x) != REG || REGNO_REG_CLASS (REGNO (x)) != CIRRUS_REGS)
- abort ();
+ {
+ output_operand_lossage ("invalid operand for code '%c'", code);
+ return;
+ }
fprintf (stream, "mv%s%s",
mode == DFmode ? "d"
@@ -9796,7 +11241,11 @@ arm_print_operand (FILE *stream, rtx x, int code)
|| REGNO (x) < FIRST_IWMMXT_GR_REGNUM
|| REGNO (x) > LAST_IWMMXT_GR_REGNUM)
/* Bad value for wCG register number. */
- abort ();
+ {
+ output_operand_lossage ("invalid operand for code '%c'", code);
+ return;
+ }
+
else
fprintf (stream, "%d", REGNO (x) - FIRST_IWMMXT_GR_REGNUM);
return;
@@ -9807,7 +11256,11 @@ arm_print_operand (FILE *stream, rtx x, int code)
|| INTVAL (x) < 0
|| INTVAL (x) >= 16)
/* Bad value for wC register number. */
- abort ();
+ {
+ output_operand_lossage ("invalid operand for code '%c'", code);
+ return;
+ }
+
else
{
static const char * wc_reg_names [16] =
@@ -9817,30 +11270,68 @@ arm_print_operand (FILE *stream, rtx x, int code)
"wCGR0", "wCGR1", "wCGR2", "wCGR3",
"wC12", "wC13", "wC14", "wC15"
};
-
+
fprintf (stream, wc_reg_names [INTVAL (x)]);
}
return;
+ /* Print a VFP double precision register name. */
+ case 'P':
+ {
+ int mode = GET_MODE (x);
+ int num;
+
+ if (mode != DImode && mode != DFmode)
+ {
+ output_operand_lossage ("invalid operand for code '%c'", code);
+ return;
+ }
+
+ if (GET_CODE (x) != REG
+ || !IS_VFP_REGNUM (REGNO (x)))
+ {
+ output_operand_lossage ("invalid operand for code '%c'", code);
+ return;
+ }
+
+ num = REGNO(x) - FIRST_VFP_REGNUM;
+ if (num & 1)
+ {
+ output_operand_lossage ("invalid operand for code '%c'", code);
+ return;
+ }
+
+ fprintf (stream, "d%d", num >> 1);
+ }
+ return;
+
default:
if (x == 0)
- abort ();
+ {
+ output_operand_lossage ("missing operand");
+ return;
+ }
- if (GET_CODE (x) == REG)
- asm_fprintf (stream, "%r", REGNO (x));
- else if (GET_CODE (x) == MEM)
+ switch (GET_CODE (x))
{
+ case REG:
+ asm_fprintf (stream, "%r", REGNO (x));
+ break;
+
+ case MEM:
output_memory_reference_mode = GET_MODE (x);
output_address (XEXP (x, 0));
- }
- else if (GET_CODE (x) == CONST_DOUBLE)
- fprintf (stream, "#%s", fp_immediate_constant (x));
- else if (GET_CODE (x) == NEG)
- abort (); /* This should never happen now. */
- else
- {
+ break;
+
+ case CONST_DOUBLE:
+ fprintf (stream, "#%s", fp_immediate_constant (x));
+ break;
+
+ default:
+ gcc_assert (GET_CODE (x) != NEG);
fputc ('#', stream);
output_addr_const (stream, x);
+ break;
}
}
}
@@ -9874,12 +11365,11 @@ arm_assemble_integer (rtx x, unsigned int size, int aligned_p)
return true;
}
- if (VECTOR_MODE_SUPPORTED_P (GET_MODE (x)))
+ if (arm_vector_mode_supported_p (GET_MODE (x)))
{
int i, units;
- if (GET_CODE (x) != CONST_VECTOR)
- abort ();
+ gcc_assert (GET_CODE (x) == CONST_VECTOR);
units = CONST_VECTOR_NUNITS (x);
@@ -9889,7 +11379,7 @@ arm_assemble_integer (rtx x, unsigned int size, int aligned_p)
case V4HImode: size = 2; break;
case V8QImode: size = 1; break;
default:
- abort ();
+ gcc_unreachable ();
}
for (i = 0; i < units; i++)
@@ -9906,6 +11396,26 @@ arm_assemble_integer (rtx x, unsigned int size, int aligned_p)
return default_assemble_integer (x, size, aligned_p);
}
+
+
+/* Add a function to the list of static constructors. */
+
+static void
+arm_elf_asm_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
+{
+ if (!TARGET_AAPCS_BASED)
+ {
+ default_named_section_asm_out_constructor (symbol, priority);
+ return;
+ }
+
+ /* Put these in the .init_array section, using a special relocation. */
+ switch_to_section (ctors_section);
+ assemble_align (POINTER_SIZE);
+ fputs ("\t.word\t", asm_out_file);
+ output_addr_const (asm_out_file, symbol);
+ fputs ("(target1)\n", asm_out_file);
+}
#endif
/* A finite state machine takes care of noticing whether or not instructions
@@ -9967,8 +11477,7 @@ get_arm_condition_code (rtx comparison)
case CC_DLTUmode: code = ARM_CC;
dominance:
- if (comp_code != EQ && comp_code != NE)
- abort ();
+ gcc_assert (comp_code == EQ || comp_code == NE);
if (comp_code == EQ)
return ARM_INVERSE_CONDITION_CODE (code);
@@ -9981,7 +11490,7 @@ get_arm_condition_code (rtx comparison)
case EQ: return ARM_EQ;
case GE: return ARM_PL;
case LT: return ARM_MI;
- default: abort ();
+ default: gcc_unreachable ();
}
case CC_Zmode:
@@ -9989,7 +11498,7 @@ get_arm_condition_code (rtx comparison)
{
case NE: return ARM_NE;
case EQ: return ARM_EQ;
- default: abort ();
+ default: gcc_unreachable ();
}
case CC_Nmode:
@@ -9997,7 +11506,7 @@ get_arm_condition_code (rtx comparison)
{
case NE: return ARM_MI;
case EQ: return ARM_PL;
- default: abort ();
+ default: gcc_unreachable ();
}
case CCFPEmode:
@@ -10022,7 +11531,7 @@ get_arm_condition_code (rtx comparison)
/* UNEQ and LTGT do not have a representation. */
case UNEQ: /* Fall through. */
case LTGT: /* Fall through. */
- default: abort ();
+ default: gcc_unreachable ();
}
case CC_SWPmode:
@@ -10038,7 +11547,7 @@ get_arm_condition_code (rtx comparison)
case GTU: return ARM_CC;
case LEU: return ARM_CS;
case LTU: return ARM_HI;
- default: abort ();
+ default: gcc_unreachable ();
}
case CC_Cmode:
@@ -10046,9 +11555,9 @@ get_arm_condition_code (rtx comparison)
{
case LTU: return ARM_CS;
case GEU: return ARM_CC;
- default: abort ();
+ default: gcc_unreachable ();
}
-
+
case CCmode:
switch (comp_code)
{
@@ -10062,13 +11571,11 @@ get_arm_condition_code (rtx comparison)
case GTU: return ARM_HI;
case LEU: return ARM_LS;
case LTU: return ARM_CC;
- default: abort ();
+ default: gcc_unreachable ();
}
- default: abort ();
+ default: gcc_unreachable ();
}
-
- abort ();
}
void
@@ -10086,10 +11593,10 @@ arm_final_prescan_insn (rtx insn)
means that we have to grub around within the jump expression to find
out what the conditions are when the jump isn't taken. */
int jump_clobbers = 0;
-
+
/* If we start with a return insn, we only succeed if we find another one. */
int seeking_return = 0;
-
+
/* START_INSN will hold the insn from where we start looking. This is the
first insn after the following code_label if REVERSE is true. */
rtx start_insn = insn;
@@ -10146,12 +11653,11 @@ arm_final_prescan_insn (rtx insn)
return;
}
- if (arm_ccfsm_state != 0 && !reverse)
- abort ();
+ gcc_assert (!arm_ccfsm_state || reverse);
if (GET_CODE (insn) != JUMP_INSN)
return;
- /* This jump might be paralleled with a clobber of the condition codes
+ /* This jump might be paralleled with a clobber of the condition codes
the jump should always come first */
if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
body = XVECEXP (body, 0, 0);
@@ -10166,14 +11672,14 @@ arm_final_prescan_insn (rtx insn)
int then_not_else = TRUE;
rtx this_insn = start_insn, label = 0;
- /* If the jump cannot be done with one instruction, we cannot
+ /* If the jump cannot be done with one instruction, we cannot
conditionally execute the instruction in the inverse case. */
if (get_attr_conds (insn) == CONDS_JUMP_CLOB)
{
jump_clobbers = 1;
return;
}
-
+
/* Register the insn jumped to. */
if (reverse)
{
@@ -10195,7 +11701,7 @@ arm_final_prescan_insn (rtx insn)
then_not_else = FALSE;
}
else
- abort ();
+ gcc_unreachable ();
/* See how many insns this branch skips, and what kind of insns. If all
insns are okay, and the label or unconditional branch to the same
@@ -10231,8 +11737,8 @@ arm_final_prescan_insn (rtx insn)
case BARRIER:
/* Succeed if the following insn is the target label.
- Otherwise fail.
- If return insns are used then the last insn in a function
+ Otherwise fail.
+ If return insns are used then the last insn in a function
will be a barrier. */
this_insn = next_nonnote_insn (this_insn);
if (this_insn && this_insn == label)
@@ -10251,32 +11757,37 @@ arm_final_prescan_insn (rtx insn)
break;
case CALL_INSN:
- /* If using 32-bit addresses the cc is not preserved over
- calls. */
- if (TARGET_APCS_32)
+ /* The AAPCS says that conditional calls should not be
+ used since they make interworking inefficient (the
+ linker can't transform BL<cond> into BLX). That's
+ only a problem if the machine has BLX. */
+ if (arm_arch5)
{
- /* Succeed if the following insn is the target label,
- or if the following two insns are a barrier and
- the target label. */
- this_insn = next_nonnote_insn (this_insn);
- if (this_insn && GET_CODE (this_insn) == BARRIER)
- this_insn = next_nonnote_insn (this_insn);
+ fail = TRUE;
+ break;
+ }
+
+ /* Succeed if the following insn is the target label, or
+ if the following two insns are a barrier and the
+ target label. */
+ this_insn = next_nonnote_insn (this_insn);
+ if (this_insn && GET_CODE (this_insn) == BARRIER)
+ this_insn = next_nonnote_insn (this_insn);
- if (this_insn && this_insn == label
- && insns_skipped < max_insns_skipped)
+ if (this_insn && this_insn == label
+ && insns_skipped < max_insns_skipped)
+ {
+ if (jump_clobbers)
{
- if (jump_clobbers)
- {
- arm_ccfsm_state = 2;
- this_insn = next_nonnote_insn (this_insn);
- }
- else
- arm_ccfsm_state = 1;
- succeed = TRUE;
+ arm_ccfsm_state = 2;
+ this_insn = next_nonnote_insn (this_insn);
}
else
- fail = TRUE;
+ arm_ccfsm_state = 1;
+ succeed = TRUE;
}
+ else
+ fail = TRUE;
break;
case JUMP_INSN:
@@ -10299,7 +11810,7 @@ arm_final_prescan_insn (rtx insn)
else if (GET_CODE (SET_SRC (scanbody)) == IF_THEN_ELSE)
fail = TRUE;
}
- /* Fail if a conditional return is undesirable (eg on a
+ /* Fail if a conditional return is undesirable (e.g. on a
StrongARM), but still allow this if optimizing for size. */
else if (GET_CODE (scanbody) == RETURN
&& !use_return_insn (TRUE, NULL)
@@ -10323,7 +11834,7 @@ arm_final_prescan_insn (rtx insn)
}
}
else
- fail = TRUE; /* Unrecognized jump (eg epilogue). */
+ fail = TRUE; /* Unrecognized jump (e.g. epilogue). */
break;
@@ -10357,14 +11868,16 @@ arm_final_prescan_insn (rtx insn)
{
if ((!seeking_return) && (arm_ccfsm_state == 1 || reverse))
arm_target_label = CODE_LABEL_NUMBER (label);
- else if (seeking_return || arm_ccfsm_state == 2)
+ else
{
+ gcc_assert (seeking_return || arm_ccfsm_state == 2);
+
while (this_insn && GET_CODE (PATTERN (this_insn)) == USE)
{
this_insn = next_nonnote_insn (this_insn);
- if (this_insn && (GET_CODE (this_insn) == BARRIER
- || GET_CODE (this_insn) == CODE_LABEL))
- abort ();
+ gcc_assert (!this_insn
+ || (GET_CODE (this_insn) != BARRIER
+ && GET_CODE (this_insn) != CODE_LABEL));
}
if (!this_insn)
{
@@ -10376,13 +11889,10 @@ arm_final_prescan_insn (rtx insn)
}
arm_target_insn = this_insn;
}
- else
- abort ();
if (jump_clobbers)
{
- if (reverse)
- abort ();
- arm_current_cc =
+ gcc_assert (!reverse);
+ arm_current_cc =
get_arm_condition_code (XEXP (XEXP (XEXP (SET_SRC (body),
0), 0), 1));
if (GET_CODE (XEXP (XEXP (SET_SRC (body), 0), 0)) == AND)
@@ -10402,7 +11912,7 @@ arm_final_prescan_insn (rtx insn)
if (reverse || then_not_else)
arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
}
-
+
/* Restore recog_data (getting the attributes of other insns can
destroy this array, but final.c assumes that it remains intact
across this call; since the insn has been recognized already we
@@ -10412,13 +11922,15 @@ arm_final_prescan_insn (rtx insn)
}
/* Returns true if REGNO is a valid register
- for holding a quantity of tyoe MODE. */
+ for holding a quantity of type MODE. */
int
arm_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
{
if (GET_MODE_CLASS (mode) == MODE_CC)
- return regno == CC_REGNUM;
-
+ return (regno == CC_REGNUM
+ || (TARGET_HARD_FLOAT && TARGET_VFP
+ && regno == VFPCC_REGNUM));
+
if (TARGET_THUMB)
/* For the Thumb we only allow values bigger than SImode in
registers 0 - 6, so that there is always a second low
@@ -10427,7 +11939,8 @@ arm_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
start of an even numbered register pair. */
return (ARM_NUM_REGS (mode) < 2) || (regno < LAST_LO_REGNUM);
- if (IS_CIRRUS_REGNUM (regno))
+ if (TARGET_HARD_FLOAT && TARGET_MAVERICK
+ && IS_CIRRUS_REGNUM (regno))
/* We have outlawed SI values in Cirrus registers because they
reside in the lower 32 bits, but SF values reside in the
upper 32 bits. This causes gcc all sorts of grief. We can't
@@ -10435,26 +11948,44 @@ arm_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
get sign extended to 64bits-- aldyh. */
return (GET_MODE_CLASS (mode) == MODE_FLOAT) || (mode == DImode);
- if (IS_IWMMXT_GR_REGNUM (regno))
- return mode == SImode;
+ if (TARGET_HARD_FLOAT && TARGET_VFP
+ && IS_VFP_REGNUM (regno))
+ {
+ if (mode == SFmode || mode == SImode)
+ return TRUE;
- if (IS_IWMMXT_REGNUM (regno))
- return VALID_IWMMXT_REG_MODE (mode);
+ /* DFmode values are only valid in even register pairs. */
+ if (mode == DFmode)
+ return ((regno - FIRST_VFP_REGNUM) & 1) == 0;
+ return FALSE;
+ }
+ if (TARGET_REALLY_IWMMXT)
+ {
+ if (IS_IWMMXT_GR_REGNUM (regno))
+ return mode == SImode;
+
+ if (IS_IWMMXT_REGNUM (regno))
+ return VALID_IWMMXT_REG_MODE (mode);
+ }
+
+ /* We allow any value to be stored in the general registers.
+ Restrict doubleword quantities to even register pairs so that we can
+ use ldrd. */
if (regno <= LAST_ARM_REGNUM)
- /* We allow any value to be stored in the general registers. */
- return 1;
+ return !(TARGET_LDRD && GET_MODE_SIZE (mode) > 4 && (regno & 1) != 0);
- if ( regno == FRAME_POINTER_REGNUM
+ if (regno == FRAME_POINTER_REGNUM
|| regno == ARG_POINTER_REGNUM)
/* We only allow integers in the fake hard registers. */
return GET_MODE_CLASS (mode) == MODE_INT;
/* The only registers left are the FPA registers
which we only allow to hold FP values. */
- return GET_MODE_CLASS (mode) == MODE_FLOAT
- && regno >= FIRST_ARM_FP_REGNUM
- && regno <= LAST_ARM_FP_REGNUM;
+ return (TARGET_HARD_FLOAT && TARGET_FPA
+ && GET_MODE_CLASS (mode) == MODE_FLOAT
+ && regno >= FIRST_FPA_REGNUM
+ && regno <= LAST_FPA_REGNUM);
}
int
@@ -10475,13 +12006,16 @@ arm_regno_class (int regno)
|| regno == FRAME_POINTER_REGNUM
|| regno == ARG_POINTER_REGNUM)
return GENERAL_REGS;
-
- if (regno == CC_REGNUM)
+
+ if (regno == CC_REGNUM || regno == VFPCC_REGNUM)
return NO_REGS;
if (IS_CIRRUS_REGNUM (regno))
return CIRRUS_REGS;
+ if (IS_VFP_REGNUM (regno))
+ return VFP_REGS;
+
if (IS_IWMMXT_REGNUM (regno))
return IWMMXT_REGS;
@@ -10510,13 +12044,13 @@ arm_debugger_arg_offset (int value, rtx addr)
an offset of 0 is correct. */
if (REGNO (addr) == (unsigned) HARD_FRAME_POINTER_REGNUM)
return 0;
-
+
/* If we are using the stack pointer to point at the
argument, then an offset of 0 is correct. */
if ((TARGET_THUMB || !frame_pointer_needed)
&& REGNO (addr) == SP_REGNUM)
return 0;
-
+
/* Oh dear. The argument is pointed to by a register rather
than being held in a register, or being stored at a known
offset from the frame pointer. Since GDB only understands
@@ -10526,12 +12060,12 @@ arm_debugger_arg_offset (int value, rtx addr)
looking to see where this register gets its value. If the
register is initialized from the frame pointer plus an offset
then we are in luck and we can continue, otherwise we give up.
-
+
This code is exercised by producing debugging information
for a function with arguments like this:
-
+
double func (double a, double b, int c, double d) {return d;}
-
+
Without this code the stab for parameter 'd' will be set to
an offset of 0 from the frame pointer, rather than 8. */
@@ -10546,10 +12080,10 @@ arm_debugger_arg_offset (int value, rtx addr)
a constant integer
then... */
-
+
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
- if ( GET_CODE (insn) == INSN
+ if ( GET_CODE (insn) == INSN
&& GET_CODE (PATTERN (insn)) == SET
&& REGNO (XEXP (PATTERN (insn), 0)) == REGNO (addr)
&& GET_CODE (XEXP (PATTERN (insn), 1)) == PLUS
@@ -10559,15 +12093,15 @@ arm_debugger_arg_offset (int value, rtx addr)
)
{
value = INTVAL (XEXP (XEXP (PATTERN (insn), 1), 1));
-
+
break;
}
}
-
+
if (value == 0)
{
debug_rtx (addr);
- warning ("unable to compute real location of stacked parameter");
+ warning (0, "unable to compute real location of stacked parameter");
value = 8; /* XXX magic hack */
}
@@ -10578,7 +12112,8 @@ arm_debugger_arg_offset (int value, rtx addr)
do \
{ \
if ((MASK) & insn_flags) \
- builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, NULL, NULL_TREE); \
+ lang_hooks.builtin_function ((NAME), (TYPE), (CODE), \
+ BUILT_IN_MD, NULL, NULL_TREE); \
} \
while (0)
@@ -10617,8 +12152,8 @@ static const struct builtin_description bdesc_2arg[] =
IWMMXT_BUILTIN (ussubv4hi3, "wsubhus", WSUBUSH)
IWMMXT_BUILTIN (ussubv2si3, "wsubwus", WSUBUSW)
IWMMXT_BUILTIN (mulv4hi3, "wmulul", WMULUL)
- IWMMXT_BUILTIN (smulv4hi3_highpart, "wmulsh", WMULSH)
- IWMMXT_BUILTIN (umulv4hi3_highpart, "wmuluh", WMULUH)
+ IWMMXT_BUILTIN (smulv4hi3_highpart, "wmulsm", WMULSM)
+ IWMMXT_BUILTIN (umulv4hi3_highpart, "wmulum", WMULUM)
IWMMXT_BUILTIN (eqv8qi3, "wcmpeqb", WCMPEQB)
IWMMXT_BUILTIN (eqv4hi3, "wcmpeqh", WCMPEQH)
IWMMXT_BUILTIN (eqv2si3, "wcmpeqw", WCMPEQW)
@@ -10659,7 +12194,7 @@ static const struct builtin_description bdesc_2arg[] =
#define IWMMXT_BUILTIN2(code, builtin) \
{ FL_IWMMXT, CODE_FOR_##code, NULL, ARM_BUILTIN_##builtin, 0, 0 },
-
+
IWMMXT_BUILTIN2 (iwmmxt_wpackhss, WPACKHSS)
IWMMXT_BUILTIN2 (iwmmxt_wpackwss, WPACKWSS)
IWMMXT_BUILTIN2 (iwmmxt_wpackdss, WPACKDSS)
@@ -10677,13 +12212,13 @@ static const struct builtin_description bdesc_2arg[] =
IWMMXT_BUILTIN2 (lshrv2si3_di, WSRLW)
IWMMXT_BUILTIN2 (lshrv2si3, WSRLWI)
IWMMXT_BUILTIN2 (lshrdi3_di, WSRLD)
- IWMMXT_BUILTIN2 (lshrdi3, WSRLDI)
+ IWMMXT_BUILTIN2 (lshrdi3_iwmmxt, WSRLDI)
IWMMXT_BUILTIN2 (ashrv4hi3_di, WSRAH)
IWMMXT_BUILTIN2 (ashrv4hi3, WSRAHI)
IWMMXT_BUILTIN2 (ashrv2si3_di, WSRAW)
IWMMXT_BUILTIN2 (ashrv2si3, WSRAWI)
IWMMXT_BUILTIN2 (ashrdi3_di, WSRAD)
- IWMMXT_BUILTIN2 (ashrdi3, WSRADI)
+ IWMMXT_BUILTIN2 (ashrdi3_iwmmxt, WSRADI)
IWMMXT_BUILTIN2 (rorv4hi3_di, WRORH)
IWMMXT_BUILTIN2 (rorv4hi3, WRORHI)
IWMMXT_BUILTIN2 (rorv2si3_di, WRORW)
@@ -10726,6 +12261,10 @@ arm_init_iwmmxt_builtins (void)
size_t i;
tree endlink = void_list_node;
+ tree V2SI_type_node = build_vector_type_for_mode (intSI_type_node, V2SImode);
+ tree V4HI_type_node = build_vector_type_for_mode (intHI_type_node, V4HImode);
+ tree V8QI_type_node = build_vector_type_for_mode (intQI_type_node, V8QImode);
+
tree int_ftype_int
= build_function_type (integer_type_node,
tree_cons (NULL_TREE, integer_type_node, endlink));
@@ -10940,7 +12479,7 @@ arm_init_iwmmxt_builtins (void)
break;
default:
- abort ();
+ gcc_unreachable ();
}
def_mbuiltin (d->mask, d->name, type, d->code);
@@ -11039,8 +12578,23 @@ arm_init_iwmmxt_builtins (void)
}
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);
+
+ ftype = build_function_type (ptr_type_node, void_list_node);
+ lang_hooks.builtin_function ("__builtin_thread_pointer", ftype,
+ ARM_BUILTIN_THREAD_POINTER, BUILT_IN_MD,
+ NULL, const_nothrow);
+}
+
+static void
arm_init_builtins (void)
{
+ arm_init_tls_builtins ();
+
if (TARGET_REALLY_IWMMXT)
arm_init_iwmmxt_builtins ();
}
@@ -11070,8 +12624,8 @@ arm_expand_binop_builtin (enum insn_code icode,
rtx pat;
tree arg0 = TREE_VALUE (arglist);
tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
- rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
- rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+ rtx op0 = expand_normal (arg0);
+ rtx op1 = expand_normal (arg1);
enum machine_mode tmode = insn_data[icode].operand[0].mode;
enum machine_mode mode0 = insn_data[icode].operand[1].mode;
enum machine_mode mode1 = insn_data[icode].operand[2].mode;
@@ -11086,10 +12640,7 @@ arm_expand_binop_builtin (enum insn_code icode,
|| ! (*insn_data[icode].operand[0].predicate) (target, tmode))
target = gen_reg_rtx (tmode);
- /* In case the insn wants input operands in modes different from
- the result, abort. */
- if (GET_MODE (op0) != mode0 || GET_MODE (op1) != mode1)
- abort ();
+ gcc_assert (GET_MODE (op0) == mode0 && GET_MODE (op1) == mode1);
if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
op0 = copy_to_mode_reg (mode0, op0);
@@ -11111,7 +12662,7 @@ arm_expand_unop_builtin (enum insn_code icode,
{
rtx pat;
tree arg0 = TREE_VALUE (arglist);
- rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+ rtx op0 = expand_normal (arg0);
enum machine_mode tmode = insn_data[icode].operand[0].mode;
enum machine_mode mode0 = insn_data[icode].operand[1].mode;
@@ -11184,8 +12735,8 @@ arm_expand_builtin (tree exp,
arg0 = TREE_VALUE (arglist);
arg1 = TREE_VALUE (TREE_CHAIN (arglist));
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+ op0 = expand_normal (arg0);
+ op1 = expand_normal (arg1);
tmode = insn_data[icode].operand[0].mode;
mode0 = insn_data[icode].operand[1].mode;
mode1 = insn_data[icode].operand[2].mode;
@@ -11217,9 +12768,9 @@ arm_expand_builtin (tree exp,
arg0 = TREE_VALUE (arglist);
arg1 = TREE_VALUE (TREE_CHAIN (arglist));
arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
- op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
+ op0 = expand_normal (arg0);
+ op1 = expand_normal (arg1);
+ op2 = expand_normal (arg2);
tmode = insn_data[icode].operand[0].mode;
mode0 = insn_data[icode].operand[1].mode;
mode1 = insn_data[icode].operand[2].mode;
@@ -11248,14 +12799,14 @@ arm_expand_builtin (tree exp,
case ARM_BUILTIN_SETWCX:
arg0 = TREE_VALUE (arglist);
arg1 = TREE_VALUE (TREE_CHAIN (arglist));
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
- emit_insn (gen_iwmmxt_tmcr (op0, op1));
+ op0 = force_reg (SImode, expand_normal (arg0));
+ op1 = expand_normal (arg1);
+ emit_insn (gen_iwmmxt_tmcr (op1, op0));
return 0;
case ARM_BUILTIN_GETWCX:
arg0 = TREE_VALUE (arglist);
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+ op0 = expand_normal (arg0);
target = gen_reg_rtx (SImode);
emit_insn (gen_iwmmxt_tmrc (target, op0));
return target;
@@ -11264,8 +12815,8 @@ arm_expand_builtin (tree exp,
icode = CODE_FOR_iwmmxt_wshufh;
arg0 = TREE_VALUE (arglist);
arg1 = TREE_VALUE (TREE_CHAIN (arglist));
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+ op0 = expand_normal (arg0);
+ op1 = expand_normal (arg1);
tmode = insn_data[icode].operand[0].mode;
mode1 = insn_data[icode].operand[1].mode;
mode2 = insn_data[icode].operand[2].mode;
@@ -11319,9 +12870,9 @@ arm_expand_builtin (tree exp,
arg0 = TREE_VALUE (arglist);
arg1 = TREE_VALUE (TREE_CHAIN (arglist));
arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
- op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
+ op0 = expand_normal (arg0);
+ op1 = expand_normal (arg1);
+ op2 = expand_normal (arg2);
tmode = insn_data[icode].operand[0].mode;
mode0 = insn_data[icode].operand[1].mode;
mode1 = insn_data[icode].operand[2].mode;
@@ -11342,12 +12893,15 @@ arm_expand_builtin (tree exp,
return 0;
emit_insn (pat);
return target;
-
+
case ARM_BUILTIN_WZERO:
target = gen_reg_rtx (DImode);
emit_insn (gen_iwmmxt_clrdi (target));
return target;
+ case ARM_BUILTIN_THREAD_POINTER:
+ return arm_load_tp (target);
+
default:
break;
}
@@ -11364,42 +12918,11 @@ arm_expand_builtin (tree exp,
return NULL_RTX;
}
-/* Recursively search through all of the blocks in a function
- checking to see if any of the variables created in that
- function match the RTX called 'orig'. If they do then
- replace them with the RTX called 'new'. */
-static void
-replace_symbols_in_block (tree block, rtx orig, rtx new)
-{
- for (; block; block = BLOCK_CHAIN (block))
- {
- tree sym;
-
- if (!TREE_USED (block))
- continue;
-
- for (sym = BLOCK_VARS (block); sym; sym = TREE_CHAIN (sym))
- {
- if ( (DECL_NAME (sym) == 0 && TREE_CODE (sym) != TYPE_DECL)
- || DECL_IGNORED_P (sym)
- || TREE_CODE (sym) != VAR_DECL
- || DECL_EXTERNAL (sym)
- || !rtx_equal_p (DECL_RTL (sym), orig)
- )
- continue;
-
- SET_DECL_RTL (sym, new);
- }
-
- replace_symbols_in_block (BLOCK_SUBBLOCKS (block), orig, new);
- }
-}
-
/* Return the number (counting from 0) of
the least significant set bit in MASK. */
inline static int
-number_of_first_bit_set (int mask)
+number_of_first_bit_set (unsigned mask)
{
int bit;
@@ -11411,11 +12934,121 @@ number_of_first_bit_set (int mask)
return bit;
}
+/* Emit code to push or pop registers to or from the stack. F is the
+ assembly file. MASK is the registers to push or pop. PUSH is
+ nonzero if we should push, and zero if we should pop. For debugging
+ output, if pushing, adjust CFA_OFFSET by the amount of space added
+ to the stack. REAL_REGS should have the same number of bits set as
+ MASK, and will be used instead (in the same order) to describe which
+ registers were saved - this is used to mark the save slots when we
+ push high registers after moving them to low registers. */
+static void
+thumb_pushpop (FILE *f, unsigned long mask, int push, int *cfa_offset,
+ unsigned long real_regs)
+{
+ int regno;
+ int lo_mask = mask & 0xFF;
+ int pushed_words = 0;
+
+ gcc_assert (mask);
+
+ if (lo_mask == 0 && !push && (mask & (1 << PC_REGNUM)))
+ {
+ /* Special case. Do not generate a POP PC statement here, do it in
+ thumb_exit() */
+ thumb_exit (f, -1);
+ return;
+ }
+
+ if (ARM_EABI_UNWIND_TABLES && push)
+ {
+ fprintf (f, "\t.save\t{");
+ for (regno = 0; regno < 15; regno++)
+ {
+ if (real_regs & (1 << regno))
+ {
+ if (real_regs & ((1 << regno) -1))
+ fprintf (f, ", ");
+ asm_fprintf (f, "%r", regno);
+ }
+ }
+ fprintf (f, "}\n");
+ }
+
+ fprintf (f, "\t%s\t{", push ? "push" : "pop");
+
+ /* Look at the low registers first. */
+ for (regno = 0; regno <= LAST_LO_REGNUM; regno++, lo_mask >>= 1)
+ {
+ if (lo_mask & 1)
+ {
+ asm_fprintf (f, "%r", regno);
+
+ if ((lo_mask & ~1) != 0)
+ fprintf (f, ", ");
+
+ pushed_words++;
+ }
+ }
+
+ if (push && (mask & (1 << LR_REGNUM)))
+ {
+ /* Catch pushing the LR. */
+ if (mask & 0xFF)
+ fprintf (f, ", ");
+
+ asm_fprintf (f, "%r", LR_REGNUM);
+
+ pushed_words++;
+ }
+ else if (!push && (mask & (1 << PC_REGNUM)))
+ {
+ /* Catch popping the PC. */
+ if (TARGET_INTERWORK || TARGET_BACKTRACE
+ || current_function_calls_eh_return)
+ {
+ /* The PC is never poped directly, instead
+ it is popped into r3 and then BX is used. */
+ fprintf (f, "}\n");
+
+ thumb_exit (f, -1);
+
+ return;
+ }
+ else
+ {
+ if (mask & 0xFF)
+ fprintf (f, ", ");
+
+ asm_fprintf (f, "%r", PC_REGNUM);
+ }
+ }
+
+ fprintf (f, "}\n");
+
+ if (push && pushed_words && dwarf2out_do_frame ())
+ {
+ char *l = dwarf2out_cfi_label ();
+ int pushed_mask = real_regs;
+
+ *cfa_offset += pushed_words * 4;
+ dwarf2out_def_cfa (l, SP_REGNUM, *cfa_offset);
+
+ pushed_words = 0;
+ pushed_mask = real_regs;
+ for (regno = 0; regno <= 14; regno++, pushed_mask >>= 1)
+ {
+ if (pushed_mask & 1)
+ dwarf2out_reg_save (l, regno, 4 * pushed_words++ - *cfa_offset);
+ }
+ }
+}
+
/* Generate code to return from a thumb function.
If 'reg_containing_return_addr' is -1, then the return address is
actually on the stack, at the stack pointer. */
static void
-thumb_exit (FILE *f, int reg_containing_return_addr, rtx eh_ofs)
+thumb_exit (FILE *f, int reg_containing_return_addr)
{
unsigned regs_available_for_popping;
unsigned regs_to_pop;
@@ -11430,15 +13063,8 @@ thumb_exit (FILE *f, int reg_containing_return_addr, rtx eh_ofs)
regs_to_pop = 0;
pops_needed = 0;
- /* There is an assumption here, that if eh_ofs is not NULL, the
- normal return address will have been pushed. */
- if (reg_containing_return_addr == -1 || eh_ofs)
+ if (reg_containing_return_addr == -1)
{
- /* When we are generating a return for __builtin_eh_return,
- reg_containing_return_addr must specify the return regno. */
- if (eh_ofs && reg_containing_return_addr == -1)
- abort ();
-
regs_to_pop |= 1 << LR_REGNUM;
++pops_needed;
}
@@ -11454,8 +13080,8 @@ thumb_exit (FILE *f, int reg_containing_return_addr, rtx eh_ofs)
return. */
if (pops_needed == 0)
{
- if (eh_ofs)
- asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, REGNO (eh_ofs));
+ if (current_function_calls_eh_return)
+ asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
return;
@@ -11465,17 +13091,10 @@ thumb_exit (FILE *f, int reg_containing_return_addr, rtx eh_ofs)
just pop the return address straight into the PC. */
else if (!TARGET_INTERWORK
&& !TARGET_BACKTRACE
- && !is_called_in_ARM_mode (current_function_decl))
+ && !is_called_in_ARM_mode (current_function_decl)
+ && !current_function_calls_eh_return)
{
- if (eh_ofs)
- {
- asm_fprintf (f, "\tadd\t%r, #4\n", SP_REGNUM);
- asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, REGNO (eh_ofs));
- asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
- }
- else
- asm_fprintf (f, "\tpop\t{%r}\n", PC_REGNUM);
-
+ asm_fprintf (f, "\tpop\t{%r}\n", PC_REGNUM);
return;
}
@@ -11484,11 +13103,10 @@ thumb_exit (FILE *f, int reg_containing_return_addr, rtx eh_ofs)
/* If returning via __builtin_eh_return, the bottom three registers
all contain information needed for the return. */
- if (eh_ofs)
+ if (current_function_calls_eh_return)
size = 12;
else
{
-#ifdef RTX_CODE
/* If we can deduce the registers used from the function's
return value. This is more reliable that examining
regs_ever_live[] because that will be set if the register is
@@ -11498,7 +13116,6 @@ thumb_exit (FILE *f, int reg_containing_return_addr, rtx eh_ofs)
if (current_function_return_rtx != 0)
mode = GET_MODE (current_function_return_rtx);
else
-#endif
mode = DECL_MODE (DECL_RESULT (current_function_decl));
size = GET_MODE_SIZE (mode);
@@ -11538,7 +13155,7 @@ thumb_exit (FILE *f, int reg_containing_return_addr, rtx eh_ofs)
/* If we have any popping registers left over, remove them. */
if (available > 0)
regs_available_for_popping &= ~available;
-
+
/* Otherwise if we need another popping register we can use
the fourth argument register. */
else if (pops_needed)
@@ -11556,15 +13173,15 @@ thumb_exit (FILE *f, int reg_containing_return_addr, rtx eh_ofs)
/* Register a4 is being used to hold part of the return value,
but we have dire need of a free, low register. */
restore_a4 = TRUE;
-
+
asm_fprintf (f, "\tmov\t%r, %r\n",IP_REGNUM, LAST_ARG_REGNUM);
}
-
+
if (reg_containing_return_addr != LAST_ARG_REGNUM)
{
/* The fourth argument register is available. */
regs_available_for_popping |= 1 << LAST_ARG_REGNUM;
-
+
--pops_needed;
}
}
@@ -11578,7 +13195,7 @@ thumb_exit (FILE *f, int reg_containing_return_addr, rtx eh_ofs)
{
/* The return address was popped into the lowest numbered register. */
regs_to_pop &= ~(1 << LR_REGNUM);
-
+
reg_containing_return_addr =
number_of_first_bit_set (regs_available_for_popping);
@@ -11591,7 +13208,7 @@ thumb_exit (FILE *f, int reg_containing_return_addr, rtx eh_ofs)
if (regs_available_for_popping)
{
int frame_pointer;
-
+
/* Work out which register currently contains the frame pointer. */
frame_pointer = number_of_first_bit_set (regs_available_for_popping);
@@ -11602,18 +13219,18 @@ thumb_exit (FILE *f, int reg_containing_return_addr, rtx eh_ofs)
/* (Temporarily) remove it from the mask of popped registers. */
regs_available_for_popping &= ~(1 << frame_pointer);
regs_to_pop &= ~(1 << ARM_HARD_FRAME_POINTER_REGNUM);
-
+
if (regs_available_for_popping)
{
int stack_pointer;
-
+
/* We popped the stack pointer as well,
find the register that contains it. */
stack_pointer = number_of_first_bit_set (regs_available_for_popping);
/* Move it into the stack register. */
asm_fprintf (f, "\tmov\t%r, %r\n", SP_REGNUM, stack_pointer);
-
+
/* At this point we have popped all necessary registers, so
do not worry about restoring regs_available_for_popping
to its correct value:
@@ -11630,7 +13247,7 @@ thumb_exit (FILE *f, int reg_containing_return_addr, rtx eh_ofs)
regs_available_for_popping |= (1 << frame_pointer);
}
}
-
+
/* If we still have registers left on the stack, but we no longer have
any registers into which we can pop them, then we must move the return
address into the link register and make available the register that
@@ -11638,10 +13255,10 @@ thumb_exit (FILE *f, int reg_containing_return_addr, rtx eh_ofs)
if (regs_available_for_popping == 0 && pops_needed > 0)
{
regs_available_for_popping |= 1 << reg_containing_return_addr;
-
+
asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM,
reg_containing_return_addr);
-
+
reg_containing_return_addr = LR_REGNUM;
}
@@ -11651,7 +13268,7 @@ thumb_exit (FILE *f, int reg_containing_return_addr, rtx eh_ofs)
{
int popped_into;
int move_to;
-
+
thumb_pushpop (f, regs_available_for_popping, FALSE, NULL,
regs_available_for_popping);
@@ -11666,13 +13283,13 @@ thumb_exit (FILE *f, int reg_containing_return_addr, rtx eh_ofs)
--pops_needed;
}
-
+
/* If we still have not popped everything then we must have only
had one register available to us and we are now popping the SP. */
if (pops_needed > 0)
{
int popped_into;
-
+
thumb_pushpop (f, regs_available_for_popping, FALSE, NULL,
regs_available_for_popping);
@@ -11693,107 +13310,17 @@ thumb_exit (FILE *f, int reg_containing_return_addr, rtx eh_ofs)
asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM, LAST_ARG_REGNUM);
reg_containing_return_addr = LR_REGNUM;
}
-
+
asm_fprintf (f, "\tmov\t%r, %r\n", LAST_ARG_REGNUM, IP_REGNUM);
}
- if (eh_ofs)
- asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, REGNO (eh_ofs));
+ if (current_function_calls_eh_return)
+ asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
/* Return to caller. */
asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
}
-/* Emit code to push or pop registers to or from the stack. F is the
- assembly file. MASK is the registers to push or pop. PUSH is
- non-zero if we should push, and zero if we should pop. For debugging
- output, if pushing, adjust CFA_OFFSET by the amount of space added
- to the stack. REAL_REGS should have the same number of bits set as
- MASK, and will be used instead (in the same order) to describe which
- registers were saved - this is used to mark the save slots when we
- push high registers after moving them to low registers. */
-static void
-thumb_pushpop (FILE *f, int mask, int push, int *cfa_offset, int real_regs)
-{
- int regno;
- int lo_mask = mask & 0xFF;
- int pushed_words = 0;
-
- if (lo_mask == 0 && !push && (mask & (1 << 15)))
- {
- /* Special case. Do not generate a POP PC statement here, do it in
- thumb_exit() */
- thumb_exit (f, -1, NULL_RTX);
- return;
- }
-
- fprintf (f, "\t%s\t{", push ? "push" : "pop");
-
- /* Look at the low registers first. */
- for (regno = 0; regno <= LAST_LO_REGNUM; regno++, lo_mask >>= 1)
- {
- if (lo_mask & 1)
- {
- asm_fprintf (f, "%r", regno);
-
- if ((lo_mask & ~1) != 0)
- fprintf (f, ", ");
-
- pushed_words++;
- }
- }
-
- if (push && (mask & (1 << LR_REGNUM)))
- {
- /* Catch pushing the LR. */
- if (mask & 0xFF)
- fprintf (f, ", ");
-
- asm_fprintf (f, "%r", LR_REGNUM);
-
- pushed_words++;
- }
- else if (!push && (mask & (1 << PC_REGNUM)))
- {
- /* Catch popping the PC. */
- if (TARGET_INTERWORK || TARGET_BACKTRACE)
- {
- /* The PC is never poped directly, instead
- it is popped into r3 and then BX is used. */
- fprintf (f, "}\n");
-
- thumb_exit (f, -1, NULL_RTX);
-
- return;
- }
- else
- {
- if (mask & 0xFF)
- fprintf (f, ", ");
-
- asm_fprintf (f, "%r", PC_REGNUM);
- }
- }
-
- fprintf (f, "}\n");
-
- if (push && pushed_words && dwarf2out_do_frame ())
- {
- char *l = dwarf2out_cfi_label ();
- int pushed_mask = real_regs;
-
- *cfa_offset += pushed_words * 4;
- dwarf2out_def_cfa (l, SP_REGNUM, *cfa_offset);
-
- pushed_words = 0;
- pushed_mask = real_regs;
- for (regno = 0; regno <= 14; regno++, pushed_mask >>= 1)
- {
- if (pushed_mask & 1)
- dwarf2out_reg_save (l, regno, 4 * pushed_words++ - *cfa_offset);
- }
- }
-}
void
thumb_final_prescan_insn (rtx insn)
@@ -11811,7 +13338,7 @@ thumb_shiftable_const (unsigned HOST_WIDE_INT val)
if (val == 0) /* XXX */
return 0;
-
+
for (i = 0; i < 25; i++)
if ((val & (mask << i)) == val)
return 1;
@@ -11821,14 +13348,14 @@ thumb_shiftable_const (unsigned HOST_WIDE_INT val)
/* Returns nonzero if the current function contains,
or might contain a far jump. */
-int
-thumb_far_jump_used_p (int in_prologue)
+static int
+thumb_far_jump_used_p (void)
{
rtx insn;
/* This test is only important for leaf functions. */
/* assert (!leaf_function_p ()); */
-
+
/* If we have already decided that far jumps may be used,
do not bother checking again, and always return true even if
it turns out that they are not being used. Once we have made
@@ -11840,7 +13367,7 @@ thumb_far_jump_used_p (int in_prologue)
/* If this function is not being called from the prologue/epilogue
generation code then it must be being called from the
INITIAL_ELIMINATION_OFFSET macro. */
- if (!in_prologue)
+ if (!(ARM_DOUBLEWORD_ALIGN || reload_completed))
{
/* In this case we know that we are being asked about the elimination
of the arg pointer register. If that register is not being used,
@@ -11859,7 +13386,10 @@ thumb_far_jump_used_p (int in_prologue)
A false negative will not result in bad code being generated, but it
will result in a needless push and pop of the link register. We
- hope that this does not occur too often. */
+ hope that this does not occur too often.
+
+ If we need doubleword stack alignment this could affect the other
+ elimination offsets so we can't risk getting it wrong. */
if (regs_ever_live [ARG_POINTER_REGNUM])
cfun->machine->arg_pointer_live = 1;
else if (!cfun->machine->arg_pointer_live)
@@ -11883,7 +13413,7 @@ thumb_far_jump_used_p (int in_prologue)
return 1;
}
}
-
+
return 0;
}
@@ -11891,14 +13421,13 @@ thumb_far_jump_used_p (int in_prologue)
int
is_called_in_ARM_mode (tree func)
{
- if (TREE_CODE (func) != FUNCTION_DECL)
- abort ();
+ gcc_assert (TREE_CODE (func) == FUNCTION_DECL);
- /* Ignore the problem about functions whoes address is taken. */
+ /* Ignore the problem about functions whose address is taken. */
if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func))
return TRUE;
-#ifdef ARM_PE
+#ifdef ARM_PE
return lookup_attribute ("interfacearm", DECL_ATTRIBUTES (func)) != NULL_TREE;
#else
return FALSE;
@@ -11910,11 +13439,10 @@ const char *
thumb_unexpanded_epilogue (void)
{
int regno;
- int live_regs_mask = 0;
+ unsigned long live_regs_mask = 0;
int high_regs_pushed = 0;
- int leaf_function = leaf_function_p ();
int had_to_push_lr;
- rtx eh_ofs = cfun->machine->eh_epilogue_sp_ofs;
+ int size;
if (return_used_this_function)
return "";
@@ -11922,16 +13450,17 @@ thumb_unexpanded_epilogue (void)
if (IS_NAKED (arm_current_func_type ()))
return "";
- for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
- if (THUMB_REG_PUSHED_P (regno))
- live_regs_mask |= 1 << regno;
+ live_regs_mask = thumb_compute_save_reg_mask ();
+ high_regs_pushed = bit_count (live_regs_mask & 0x0f00);
- for (regno = 8; regno < 13; regno++)
- if (THUMB_REG_PUSHED_P (regno))
- high_regs_pushed++;
+ /* If we can deduce the registers used from the function's return value.
+ This is more reliable that examining regs_ever_live[] because that
+ will be set if the register is ever used in the function, not just if
+ the register is used to hold a return value. */
+ size = arm_size_return_regs ();
/* The prolog may have pushed some high registers to use as
- work registers. eg the testsuite file:
+ work registers. e.g. the testsuite file:
gcc/testsuite/gcc/gcc.c-torture/execute/complex-2.c
compiles to produce:
push {r4, r5, r6, r7, lr}
@@ -11939,41 +13468,27 @@ thumb_unexpanded_epilogue (void)
mov r6, r8
push {r6, r7}
as part of the prolog. We have to undo that pushing here. */
-
+
if (high_regs_pushed)
{
- int mask = live_regs_mask;
+ unsigned long mask = live_regs_mask & 0xff;
int next_hi_reg;
- int size;
- int mode;
-
-#ifdef RTX_CODE
- /* If we can deduce the registers used from the function's return value.
- This is more reliable that examining regs_ever_live[] because that
- will be set if the register is ever used in the function, not just if
- the register is used to hold a return value. */
-
- if (current_function_return_rtx != 0)
- mode = GET_MODE (current_function_return_rtx);
- else
-#endif
- mode = DECL_MODE (DECL_RESULT (current_function_decl));
- size = GET_MODE_SIZE (mode);
-
- /* Unless we are returning a type of size > 12 register r3 is
- available. */
- if (size < 13)
+ /* The available low registers depend on the size of the value we are
+ returning. */
+ if (size <= 12)
mask |= 1 << 3;
+ if (size <= 8)
+ mask |= 1 << 2;
if (mask == 0)
/* Oh dear! We have no low registers into which we can pop
high registers! */
internal_error
("no low registers available for popping high registers");
-
+
for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++)
- if (THUMB_REG_PUSHED_P (next_hi_reg))
+ if (live_regs_mask & (1 << next_hi_reg))
break;
while (high_regs_pushed)
@@ -12000,33 +13515,23 @@ thumb_unexpanded_epilogue (void)
{
asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", next_hi_reg,
regno);
-
+
for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++)
- if (THUMB_REG_PUSHED_P (next_hi_reg))
+ if (live_regs_mask & (1 << next_hi_reg))
break;
}
}
}
+ live_regs_mask &= ~0x0f00;
}
- had_to_push_lr = (live_regs_mask || !leaf_function
- || thumb_far_jump_used_p (1));
-
- if (TARGET_BACKTRACE
- && ((live_regs_mask & 0xFF) == 0)
- && regs_ever_live [LAST_ARG_REGNUM] != 0)
- {
- /* The stack backtrace structure creation code had to
- push R7 in order to get a work register, so we pop
- it now. */
- live_regs_mask |= (1 << LAST_LO_REGNUM);
- }
-
+ had_to_push_lr = (live_regs_mask & (1 << LR_REGNUM)) != 0;
+ live_regs_mask &= 0xff;
+
if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE)
{
- if (had_to_push_lr
- && !is_called_in_ARM_mode (current_function_decl)
- && !eh_ofs)
+ /* Pop the return address into the PC. */
+ if (had_to_push_lr)
live_regs_mask |= 1 << PC_REGNUM;
/* Either no argument registers were pushed or a backtrace
@@ -12035,43 +13540,54 @@ thumb_unexpanded_epilogue (void)
if (live_regs_mask)
thumb_pushpop (asm_out_file, live_regs_mask, FALSE, NULL,
live_regs_mask);
-
- if (eh_ofs)
- thumb_exit (asm_out_file, 2, eh_ofs);
+
/* We have either just popped the return address into the
- PC or it is was kept in LR for the entire function or
- it is still on the stack because we do not want to
- return by doing a pop {pc}. */
- else if ((live_regs_mask & (1 << PC_REGNUM)) == 0)
- thumb_exit (asm_out_file,
- (had_to_push_lr
- && is_called_in_ARM_mode (current_function_decl)) ?
- -1 : LR_REGNUM, NULL_RTX);
+ PC or it is was kept in LR for the entire function. */
+ if (!had_to_push_lr)
+ thumb_exit (asm_out_file, LR_REGNUM);
}
else
{
/* Pop everything but the return address. */
- live_regs_mask &= ~(1 << PC_REGNUM);
-
if (live_regs_mask)
thumb_pushpop (asm_out_file, live_regs_mask, FALSE, NULL,
live_regs_mask);
if (had_to_push_lr)
- /* Get the return address into a temporary register. */
- thumb_pushpop (asm_out_file, 1 << LAST_ARG_REGNUM, 0, NULL,
- 1 << LAST_ARG_REGNUM);
-
+ {
+ if (size > 12)
+ {
+ /* We have no free low regs, so save one. */
+ asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", IP_REGNUM,
+ LAST_ARG_REGNUM);
+ }
+
+ /* Get the return address into a temporary register. */
+ thumb_pushpop (asm_out_file, 1 << LAST_ARG_REGNUM, 0, NULL,
+ 1 << LAST_ARG_REGNUM);
+
+ if (size > 12)
+ {
+ /* Move the return address to lr. */
+ asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", LR_REGNUM,
+ LAST_ARG_REGNUM);
+ /* Restore the low register. */
+ asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", LAST_ARG_REGNUM,
+ IP_REGNUM);
+ regno = LR_REGNUM;
+ }
+ else
+ regno = LAST_ARG_REGNUM;
+ }
+ else
+ regno = LR_REGNUM;
+
/* Remove the argument registers that were pushed onto the stack. */
asm_fprintf (asm_out_file, "\tadd\t%r, %r, #%d\n",
SP_REGNUM, SP_REGNUM,
current_function_pretend_args_size);
-
- if (eh_ofs)
- thumb_exit (asm_out_file, 2, eh_ofs);
- else
- thumb_exit (asm_out_file,
- had_to_push_lr ? LAST_ARG_REGNUM : LR_REGNUM, NULL_RTX);
+
+ thumb_exit (asm_out_file, regno);
}
return "";
@@ -12084,7 +13600,7 @@ arm_init_machine_status (void)
struct machine_function *machine;
machine = (machine_function *) ggc_alloc_cleared (sizeof (machine_function));
-#if ARM_FT_UNKNOWN != 0
+#if ARM_FT_UNKNOWN != 0
machine->func_type = ARM_FT_UNKNOWN;
#endif
return machine;
@@ -12098,14 +13614,7 @@ arm_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
if (count != 0)
return NULL_RTX;
- if (TARGET_APCS_32)
- return get_hard_reg_initial_val (Pmode, LR_REGNUM);
- else
- {
- rtx lr = gen_rtx_AND (Pmode, gen_rtx_REG (Pmode, LR_REGNUM),
- GEN_INT (RETURN_ADDR_MASK26));
- return get_func_hard_reg_initial_val (cfun, lr);
- }
+ return get_hard_reg_initial_val (Pmode, LR_REGNUM);
}
/* Do anything needed before RTL is emitted for each function. */
@@ -12114,106 +13623,86 @@ arm_init_expanders (void)
{
/* Arrange to initialize and mark the machine per-function status. */
init_machine_status = arm_init_machine_status;
-}
-
-HOST_WIDE_INT
-thumb_get_frame_size (void)
-{
- int regno;
- int base_size = ROUND_UP_WORD (get_frame_size ());
- int count_regs = 0;
- int entry_size = 0;
- int leaf;
-
- if (! TARGET_THUMB)
- abort ();
+ /* This is to stop the combine pass optimizing away the alignment
+ adjustment of va_arg. */
+ /* ??? It is claimed that this should not be necessary. */
+ if (cfun)
+ mark_reg_pointer (arg_pointer_rtx, PARM_BOUNDARY);
+}
- if (! TARGET_ATPCS)
- return base_size;
- /* We need to know if we are a leaf function. Unfortunately, it
- is possible to be called after start_sequence has been called,
- which causes get_insns to return the insns for the sequence,
- not the function, which will cause leaf_function_p to return
- the incorrect result.
-
- To work around this, we cache the computed frame size. This
- works because we will only be calling RTL expanders that need
- to know about leaf functions once reload has completed, and the
- frame size cannot be changed after that time, so we can safely
- use the cached value. */
+/* Like arm_compute_initial_elimination offset. Simpler because there
+ isn't an ABI specified frame pointer for Thumb. Instead, we set it
+ to point at the base of the local variables after static stack
+ space for a function has been allocated. */
- if (reload_completed)
- return cfun->machine->frame_size;
+HOST_WIDE_INT
+thumb_compute_initial_elimination_offset (unsigned int from, unsigned int to)
+{
+ arm_stack_offsets *offsets;
- leaf = leaf_function_p ();
+ offsets = arm_get_frame_offsets ();
- /* A leaf function does not need any stack alignment if it has nothing
- on the stack. */
- if (leaf && base_size == 0)
+ switch (from)
{
- cfun->machine->frame_size = 0;
- return 0;
- }
-
- /* We know that SP will be word aligned on entry, and we must
- preserve that condition at any subroutine call. But those are
- the only constraints. */
-
- /* Space for variadic functions. */
- if (current_function_pretend_args_size)
- entry_size += current_function_pretend_args_size;
+ case ARG_POINTER_REGNUM:
+ switch (to)
+ {
+ case STACK_POINTER_REGNUM:
+ return offsets->outgoing_args - offsets->saved_args;
- /* Space for pushed lo registers. */
- for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
- if (THUMB_REG_PUSHED_P (regno))
- count_regs++;
+ case FRAME_POINTER_REGNUM:
+ return offsets->soft_frame - offsets->saved_args;
- /* Space for backtrace structure. */
- if (TARGET_BACKTRACE)
- {
- if (count_regs == 0 && regs_ever_live[LAST_ARG_REGNUM] != 0)
- entry_size += 20;
- else
- entry_size += 16;
- }
+ case ARM_HARD_FRAME_POINTER_REGNUM:
+ return offsets->saved_regs - offsets->saved_args;
- if (count_regs || !leaf || thumb_far_jump_used_p (1))
- count_regs++; /* LR */
+ case THUMB_HARD_FRAME_POINTER_REGNUM:
+ return offsets->locals_base - offsets->saved_args;
- entry_size += count_regs * 4;
- count_regs = 0;
+ default:
+ gcc_unreachable ();
+ }
+ break;
- /* Space for pushed hi regs. */
- for (regno = 8; regno < 13; regno++)
- if (THUMB_REG_PUSHED_P (regno))
- count_regs++;
+ case FRAME_POINTER_REGNUM:
+ switch (to)
+ {
+ case STACK_POINTER_REGNUM:
+ return offsets->outgoing_args - offsets->soft_frame;
- entry_size += count_regs * 4;
+ case ARM_HARD_FRAME_POINTER_REGNUM:
+ return offsets->saved_regs - offsets->soft_frame;
- if ((entry_size + base_size + current_function_outgoing_args_size) & 7)
- base_size += 4;
- if ((entry_size + base_size + current_function_outgoing_args_size) & 7)
- abort ();
+ case THUMB_HARD_FRAME_POINTER_REGNUM:
+ return offsets->locals_base - offsets->soft_frame;
- cfun->machine->frame_size = base_size;
+ default:
+ gcc_unreachable ();
+ }
+ break;
- return base_size;
+ default:
+ gcc_unreachable ();
+ }
}
+
/* Generate the rest of a function's prologue. */
void
thumb_expand_prologue (void)
{
rtx insn, dwarf;
- HOST_WIDE_INT amount = (thumb_get_frame_size ()
- + current_function_outgoing_args_size);
+ HOST_WIDE_INT amount;
+ arm_stack_offsets *offsets;
unsigned long func_type;
+ int regno;
+ unsigned long live_regs_mask;
func_type = arm_current_func_type ();
-
+
/* Naked functions don't have prologues. */
if (IS_NAKED (func_type))
return;
@@ -12224,16 +13713,20 @@ thumb_expand_prologue (void)
return;
}
- if (frame_pointer_needed)
- {
- insn = emit_insn (gen_movsi (hard_frame_pointer_rtx, stack_pointer_rtx));
- RTX_FRAME_RELATED_P (insn) = 1;
- }
+ live_regs_mask = thumb_compute_save_reg_mask ();
+ /* Load the pic register before setting the frame pointer,
+ so we can use r7 as a temporary work register. */
+ if (flag_pic && arm_pic_register != INVALID_REGNUM)
+ arm_load_pic_register (live_regs_mask);
+
+ if (!frame_pointer_needed && CALLER_INTERWORKING_SLOT_SIZE > 0)
+ emit_move_insn (gen_rtx_REG (Pmode, ARM_HARD_FRAME_POINTER_REGNUM),
+ stack_pointer_rtx);
+ offsets = arm_get_frame_offsets ();
+ amount = offsets->outgoing_args - offsets->saved_regs;
if (amount)
{
- amount = ROUND_UP_WORD (amount);
-
if (amount < 512)
{
insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
@@ -12242,7 +13735,6 @@ thumb_expand_prologue (void)
}
else
{
- int regno;
rtx reg;
/* The stack decrement is too big for an immediate value in a single
@@ -12260,17 +13752,17 @@ thumb_expand_prologue (void)
been pushed at the start of the prologue and so we can corrupt
it now. */
for (regno = LAST_ARG_REGNUM + 1; regno <= LAST_LO_REGNUM; regno++)
- if (THUMB_REG_PUSHED_P (regno)
+ if (live_regs_mask & (1 << regno)
&& !(frame_pointer_needed
&& (regno == THUMB_HARD_FRAME_POINTER_REGNUM)))
break;
if (regno > LAST_LO_REGNUM) /* Very unlikely. */
{
- rtx spare = gen_rtx (REG, SImode, IP_REGNUM);
+ rtx spare = gen_rtx_REG (SImode, IP_REGNUM);
/* Choose an arbitrary, non-argument low register. */
- reg = gen_rtx (REG, SImode, LAST_LO_REGNUM);
+ reg = gen_rtx_REG (SImode, LAST_LO_REGNUM);
/* Save it by copying it into a high, scratch register. */
emit_insn (gen_movsi (spare, reg));
@@ -12282,9 +13774,9 @@ thumb_expand_prologue (void)
insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx, reg));
RTX_FRAME_RELATED_P (insn) = 1;
- dwarf = gen_rtx_SET (SImode, stack_pointer_rtx,
+ dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
plus_constant (stack_pointer_rtx,
- GEN_INT (- amount)));
+ -amount));
RTX_FRAME_RELATED_P (dwarf) = 1;
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
@@ -12292,7 +13784,7 @@ thumb_expand_prologue (void)
/* Restore the low register's original value. */
emit_insn (gen_movsi (reg, spare));
-
+
/* Emit a USE of the restored scratch register, so that flow
analysis will not consider the restore redundant. The
register won't be used again in this function and isn't
@@ -12301,16 +13793,16 @@ thumb_expand_prologue (void)
}
else
{
- reg = gen_rtx (REG, SImode, regno);
+ reg = gen_rtx_REG (SImode, regno);
emit_insn (gen_movsi (reg, GEN_INT (- amount)));
insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx, reg));
RTX_FRAME_RELATED_P (insn) = 1;
- dwarf = gen_rtx_SET (SImode, stack_pointer_rtx,
+ dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
plus_constant (stack_pointer_rtx,
- GEN_INT (- amount)));
+ -amount));
RTX_FRAME_RELATED_P (dwarf) = 1;
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
@@ -12318,46 +13810,90 @@ thumb_expand_prologue (void)
}
}
}
-
- if (current_function_profile || TARGET_NO_SCHED_PRO)
+
+ if (frame_pointer_needed)
+ {
+ amount = offsets->outgoing_args - offsets->locals_base;
+
+ if (amount < 1024)
+ insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
+ stack_pointer_rtx, GEN_INT (amount)));
+ 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));
+ dwarf = gen_rtx_SET (VOIDmode, hard_frame_pointer_rtx,
+ plus_constant (stack_pointer_rtx, amount));
+ RTX_FRAME_RELATED_P (dwarf) = 1;
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
+ REG_NOTES (insn));
+ }
+
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ /* If we are profiling, make sure no instructions are scheduled before
+ the call to mcount. Similarly if the user has requested no
+ scheduling in the prolog. Similarly if we want non-call exceptions
+ using the EABI unwinder, to prevent faulting instructions from being
+ swapped with a stack adjustment. */
+ if (current_function_profile || !TARGET_SCHED_PROLOG
+ || (ARM_EABI_UNWIND_TABLES && flag_non_call_exceptions))
emit_insn (gen_blockage ());
+
+ cfun->machine->lr_save_eliminated = !thumb_force_lr_save ();
+ if (live_regs_mask & 0xff)
+ cfun->machine->lr_save_eliminated = 0;
+
+ /* If the link register is being kept alive, with the return address in it,
+ then make sure that it does not get reused by the ce2 pass. */
+ if (cfun->machine->lr_save_eliminated)
+ emit_insn (gen_prologue_use (gen_rtx_REG (SImode, LR_REGNUM)));
}
+
void
thumb_expand_epilogue (void)
{
- HOST_WIDE_INT amount = (thumb_get_frame_size ()
- + current_function_outgoing_args_size);
+ HOST_WIDE_INT amount;
+ arm_stack_offsets *offsets;
int regno;
/* Naked functions don't have prologues. */
if (IS_NAKED (arm_current_func_type ()))
return;
+ offsets = arm_get_frame_offsets ();
+ amount = offsets->outgoing_args - offsets->saved_regs;
+
if (frame_pointer_needed)
- emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
- else if (amount)
{
- amount = ROUND_UP_WORD (amount);
-
+ emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
+ amount = offsets->locals_base - offsets->saved_regs;
+ }
+
+ if (amount)
+ {
if (amount < 512)
emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
GEN_INT (amount)));
else
{
/* r3 is always free in the epilogue. */
- rtx reg = gen_rtx (REG, SImode, LAST_ARG_REGNUM);
+ rtx reg = gen_rtx_REG (SImode, LAST_ARG_REGNUM);
emit_insn (gen_movsi (reg, GEN_INT (amount)));
emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg));
}
}
-
+
/* Emit a USE (stack_pointer_rtx), so that
the stack adjustment will not be deleted. */
emit_insn (gen_prologue_use (stack_pointer_rtx));
- if (current_function_profile || TARGET_NO_SCHED_PRO)
+ if (current_function_profile || !TARGET_SCHED_PROLOG)
emit_insn (gen_blockage ());
/* Emit a clobber for each insn that will be restored in the epilogue,
@@ -12373,8 +13909,9 @@ thumb_expand_epilogue (void)
static void
thumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
{
- int live_regs_mask = 0;
- int high_regs_pushed = 0;
+ unsigned long live_regs_mask = 0;
+ unsigned long l_mask;
+ unsigned high_regs_pushed = 0;
int cfa_offset = 0;
int regno;
@@ -12385,12 +13922,11 @@ thumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
{
const char * name;
- if (GET_CODE (DECL_RTL (current_function_decl)) != MEM)
- abort ();
- if (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0)) != SYMBOL_REF)
- abort ();
+ gcc_assert (GET_CODE (DECL_RTL (current_function_decl)) == MEM);
+ gcc_assert (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0))
+ == SYMBOL_REF);
name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
-
+
/* Generate code sequence to switch us into Thumb mode. */
/* The .code 32 directive has already been emitted by
ASM_DECLARE_FUNCTION_NAME. */
@@ -12403,29 +13939,34 @@ thumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
is called from a Thumb encoded function elsewhere in the
same file. Hence the definition of STUB_NAME here must
agree with the definition in gas/config/tc-arm.c. */
-
+
#define STUB_NAME ".real_start_of"
-
+
fprintf (f, "\t.code\t16\n");
#ifdef ARM_PE
if (arm_dllexport_name_p (name))
name = arm_strip_name_encoding (name);
-#endif
+#endif
asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name);
fprintf (f, "\t.thumb_func\n");
asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name);
}
-
+
if (current_function_pretend_args_size)
{
+ /* Output unwind directive for the stack adjustment. */
+ if (ARM_EABI_UNWIND_TABLES)
+ fprintf (f, "\t.pad #%d\n",
+ current_function_pretend_args_size);
+
if (cfun->machine->uses_anonymous_args)
{
int num_pushes;
-
+
fprintf (f, "\tpush\t{");
num_pushes = ARM_NUM_INTS (current_function_pretend_args_size);
-
+
for (regno = LAST_ARG_REGNUM + 1 - num_pushes;
regno <= LAST_ARG_REGNUM;
regno++)
@@ -12435,7 +13976,7 @@ thumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
fprintf (f, "}\n");
}
else
- asm_fprintf (f, "\tsub\t%r, %r, #%d\n",
+ asm_fprintf (f, "\tsub\t%r, %r, #%d\n",
SP_REGNUM, SP_REGNUM,
current_function_pretend_args_size);
@@ -12445,31 +13986,31 @@ thumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
if (dwarf2out_do_frame ())
{
char *l = dwarf2out_cfi_label ();
+
cfa_offset = cfa_offset + current_function_pretend_args_size;
dwarf2out_def_cfa (l, SP_REGNUM, cfa_offset);
}
}
- for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
- if (THUMB_REG_PUSHED_P (regno))
- live_regs_mask |= 1 << regno;
-
- if (live_regs_mask || !leaf_function_p () || thumb_far_jump_used_p (1))
- live_regs_mask |= 1 << LR_REGNUM;
+ /* Get the registers we are going to push. */
+ live_regs_mask = thumb_compute_save_reg_mask ();
+ /* Extract a mask of the ones we can give to the Thumb's push instruction. */
+ l_mask = live_regs_mask & 0x40ff;
+ /* Then count how many other high registers will need to be pushed. */
+ high_regs_pushed = bit_count (live_regs_mask & 0x0f00);
if (TARGET_BACKTRACE)
{
- int offset;
- int work_register = 0;
- int wr;
-
+ unsigned offset;
+ unsigned work_register;
+
/* We have been asked to create a stack backtrace structure.
The code looks like this:
-
+
0 .align 2
0 func:
0 sub SP, #16 Reserve space for 4 registers.
- 2 push {R7} Get a work register.
+ 2 push {R7} Push low registers.
4 add R7, SP, #20 Get the stack pointer before the push.
6 str R7, [SP, #8] Store the stack pointer (before reserving the space).
8 mov R7, PC Get hold of the start of this code plus 12.
@@ -12481,25 +14022,11 @@ thumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
20 add R7, SP, #16 Point at the start of the backtrace structure.
22 mov FP, R7 Put this value into the frame pointer. */
- if ((live_regs_mask & 0xFF) == 0)
- {
- /* See if the a4 register is free. */
+ work_register = thumb_find_work_register (live_regs_mask);
- if (regs_ever_live [LAST_ARG_REGNUM] == 0)
- work_register = LAST_ARG_REGNUM;
- else /* We must push a register of our own. */
- live_regs_mask |= (1 << LAST_LO_REGNUM);
- }
+ if (ARM_EABI_UNWIND_TABLES)
+ asm_fprintf (f, "\t.pad #16\n");
- if (work_register == 0)
- {
- /* Select a register from the list that will be pushed to
- use as our work register. */
- for (work_register = (LAST_LO_REGNUM + 1); work_register--;)
- if ((1 << work_register) & live_regs_mask)
- break;
- }
-
asm_fprintf
(f, "\tsub\t%r, %r, #16\t%@ Create stack backtrace structure\n",
SP_REGNUM, SP_REGNUM);
@@ -12507,26 +14034,28 @@ thumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
if (dwarf2out_do_frame ())
{
char *l = dwarf2out_cfi_label ();
+
cfa_offset = cfa_offset + 16;
dwarf2out_def_cfa (l, SP_REGNUM, cfa_offset);
}
- if (live_regs_mask)
- thumb_pushpop (f, live_regs_mask, 1, &cfa_offset, live_regs_mask);
-
- for (offset = 0, wr = 1 << 15; wr != 0; wr >>= 1)
- if (wr & live_regs_mask)
- offset += 4;
-
+ if (l_mask)
+ {
+ thumb_pushpop (f, l_mask, 1, &cfa_offset, l_mask);
+ offset = bit_count (l_mask) * UNITS_PER_WORD;
+ }
+ else
+ offset = 0;
+
asm_fprintf (f, "\tadd\t%r, %r, #%d\n", work_register, SP_REGNUM,
offset + 16 + current_function_pretend_args_size);
-
+
asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
offset + 4);
/* Make sure that the instruction fetching the PC is in the right place
to calculate "start of backtrace creation code + 12". */
- if (live_regs_mask)
+ if (l_mask)
{
asm_fprintf (f, "\tmov\t%r, %r\n", work_register, PC_REGNUM);
asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
@@ -12546,7 +14075,7 @@ thumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
offset + 12);
}
-
+
asm_fprintf (f, "\tmov\t%r, %r\n", work_register, LR_REGNUM);
asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
offset + 8);
@@ -12555,67 +14084,68 @@ thumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
asm_fprintf (f, "\tmov\t%r, %r\t\t%@ Backtrace structure created\n",
ARM_HARD_FRAME_POINTER_REGNUM, work_register);
}
- else if (live_regs_mask)
- thumb_pushpop (f, live_regs_mask, 1, &cfa_offset, live_regs_mask);
-
- for (regno = 8; regno < 13; regno++)
- if (THUMB_REG_PUSHED_P (regno))
- high_regs_pushed++;
+ /* Optimization: If we are not pushing any low registers but we are going
+ to push some high registers then delay our first push. This will just
+ be a push of LR and we can combine it with the push of the first high
+ register. */
+ else if ((l_mask & 0xff) != 0
+ || (high_regs_pushed == 0 && l_mask))
+ thumb_pushpop (f, l_mask, 1, &cfa_offset, l_mask);
if (high_regs_pushed)
{
- int pushable_regs = 0;
- int mask = live_regs_mask & 0xff;
- int next_hi_reg;
+ unsigned pushable_regs;
+ unsigned next_hi_reg;
for (next_hi_reg = 12; next_hi_reg > LAST_LO_REGNUM; next_hi_reg--)
- if (THUMB_REG_PUSHED_P (next_hi_reg))
+ if (live_regs_mask & (1 << next_hi_reg))
break;
- pushable_regs = mask;
+ pushable_regs = l_mask & 0xff;
if (pushable_regs == 0)
- {
- /* Desperation time -- this probably will never happen. */
- if (THUMB_REG_PUSHED_P (LAST_ARG_REGNUM))
- asm_fprintf (f, "\tmov\t%r, %r\n", IP_REGNUM, LAST_ARG_REGNUM);
- mask = 1 << LAST_ARG_REGNUM;
- }
+ pushable_regs = 1 << thumb_find_work_register (live_regs_mask);
while (high_regs_pushed > 0)
{
- int real_regs_mask = 0;
+ unsigned long real_regs_mask = 0;
- for (regno = LAST_LO_REGNUM; regno >= 0; regno--)
+ for (regno = LAST_LO_REGNUM; regno >= 0; regno --)
{
- if (mask & (1 << regno))
+ if (pushable_regs & (1 << regno))
{
asm_fprintf (f, "\tmov\t%r, %r\n", regno, next_hi_reg);
-
- high_regs_pushed--;
+
+ high_regs_pushed --;
real_regs_mask |= (1 << next_hi_reg);
-
+
if (high_regs_pushed)
{
- for (next_hi_reg--; next_hi_reg > LAST_LO_REGNUM;
- next_hi_reg--)
- if (THUMB_REG_PUSHED_P (next_hi_reg))
+ for (next_hi_reg --; next_hi_reg > LAST_LO_REGNUM;
+ next_hi_reg --)
+ if (live_regs_mask & (1 << next_hi_reg))
break;
}
else
{
- mask &= ~((1 << regno) - 1);
+ pushable_regs &= ~((1 << regno) - 1);
break;
}
}
}
- thumb_pushpop (f, mask, 1, &cfa_offset, real_regs_mask);
+ /* If we had to find a work register and we have not yet
+ saved the LR then add it to the list of regs to push. */
+ if (l_mask == (1 << LR_REGNUM))
+ {
+ thumb_pushpop (f, pushable_regs | (1 << LR_REGNUM),
+ 1, &cfa_offset,
+ real_regs_mask | (1 << LR_REGNUM));
+ l_mask = 0;
+ }
+ else
+ thumb_pushpop (f, pushable_regs, 1, &cfa_offset, real_regs_mask);
}
-
- if (pushable_regs == 0
- && (THUMB_REG_PUSHED_P (LAST_ARG_REGNUM)))
- asm_fprintf (f, "\tmov\t%r, %r\n", LAST_ARG_REGNUM, IP_REGNUM);
}
}
@@ -12630,22 +14160,18 @@ thumb_load_double_from_address (rtx *operands)
rtx offset;
rtx arg1;
rtx arg2;
-
- if (GET_CODE (operands[0]) != REG)
- abort ();
-
- if (GET_CODE (operands[1]) != MEM)
- abort ();
+
+ gcc_assert (GET_CODE (operands[0]) == REG);
+ gcc_assert (GET_CODE (operands[1]) == MEM);
/* Get the memory address. */
addr = XEXP (operands[1], 0);
-
+
/* Work out how the memory address is computed. */
switch (GET_CODE (addr))
{
case REG:
- operands[2] = gen_rtx (MEM, SImode,
- plus_constant (XEXP (operands[1], 0), 4));
+ operands[2] = adjust_address (operands[1], SImode, 4);
if (REGNO (operands[0]) == REGNO (addr))
{
@@ -12658,27 +14184,25 @@ thumb_load_double_from_address (rtx *operands)
output_asm_insn ("ldr\t%H0, %2", operands);
}
break;
-
+
case CONST:
/* Compute <address> + 4 for the high order load. */
- operands[2] = gen_rtx (MEM, SImode,
- plus_constant (XEXP (operands[1], 0), 4));
-
+ operands[2] = adjust_address (operands[1], SImode, 4);
+
output_asm_insn ("ldr\t%0, %1", operands);
output_asm_insn ("ldr\t%H0, %2", operands);
break;
-
+
case PLUS:
arg1 = XEXP (addr, 0);
arg2 = XEXP (addr, 1);
-
+
if (CONSTANT_P (arg1))
base = arg2, offset = arg1;
else
base = arg1, offset = arg2;
-
- if (GET_CODE (base) != REG)
- abort ();
+
+ gcc_assert (GET_CODE (base) == REG);
/* Catch the case of <address> = <reg> + <reg> */
if (GET_CODE (offset) == REG)
@@ -12686,17 +14210,17 @@ thumb_load_double_from_address (rtx *operands)
int reg_offset = REGNO (offset);
int reg_base = REGNO (base);
int reg_dest = REGNO (operands[0]);
-
+
/* Add the base and offset registers together into the
higher destination register. */
asm_fprintf (asm_out_file, "\tadd\t%r, %r, %r",
reg_dest + 1, reg_base, reg_offset);
-
+
/* Load the lower destination register from the address in
the higher destination register. */
asm_fprintf (asm_out_file, "\tldr\t%r, [%r, #0]",
reg_dest, reg_dest + 1);
-
+
/* Load the higher destination register from its own address
plus 4. */
asm_fprintf (asm_out_file, "\tldr\t%r, [%r, #4]",
@@ -12705,9 +14229,8 @@ thumb_load_double_from_address (rtx *operands)
else
{
/* Compute <address> + 4 for the high order load. */
- operands[2] = gen_rtx (MEM, SImode,
- plus_constant (XEXP (operands[1], 0), 4));
-
+ operands[2] = adjust_address (operands[1], SImode, 4);
+
/* If the computed address is held in the low order register
then load the high order register first, otherwise always
load the low order register first. */
@@ -12727,18 +14250,16 @@ thumb_load_double_from_address (rtx *operands)
case LABEL_REF:
/* With no registers to worry about we can just load the value
directly. */
- operands[2] = gen_rtx (MEM, SImode,
- plus_constant (XEXP (operands[1], 0), 4));
-
+ operands[2] = adjust_address (operands[1], SImode, 4);
+
output_asm_insn ("ldr\t%H0, %2", operands);
output_asm_insn ("ldr\t%0, %1", operands);
break;
-
+
default:
- abort ();
- break;
+ gcc_unreachable ();
}
-
+
return "";
}
@@ -12779,21 +14300,52 @@ thumb_output_move_mem_multiple (int n, rtx *operands)
operands[4] = operands[5];
operands[5] = tmp;
}
-
+
output_asm_insn ("ldmia\t%1!, {%4, %5, %6}", operands);
output_asm_insn ("stmia\t%0!, {%4, %5, %6}", operands);
break;
default:
- abort ();
+ gcc_unreachable ();
+ }
+
+ return "";
+}
+
+/* Output a call-via instruction for thumb state. */
+const char *
+thumb_call_via_reg (rtx reg)
+{
+ int regno = REGNO (reg);
+ rtx *labelp;
+
+ gcc_assert (regno < LR_REGNUM);
+
+ /* If we are in the normal text section we can use a single instance
+ per compilation unit. If we are doing function sections, then we need
+ an entry per section, since we can't rely on reachability. */
+ if (in_section == text_section)
+ {
+ thumb_call_reg_needed = 1;
+
+ if (thumb_call_via_label[regno] == NULL)
+ thumb_call_via_label[regno] = gen_label_rtx ();
+ labelp = thumb_call_via_label + regno;
+ }
+ else
+ {
+ if (cfun->machine->call_via[regno] == NULL)
+ cfun->machine->call_via[regno] = gen_label_rtx ();
+ labelp = cfun->machine->call_via + regno;
}
+ output_asm_insn ("bl\t%a0", labelp);
return "";
}
/* Routines for generating rtl. */
void
-thumb_expand_movstrqi (rtx *operands)
+thumb_expand_movmemqi (rtx *operands)
{
rtx out = copy_to_mode_reg (SImode, XEXP (operands[0], 0));
rtx in = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
@@ -12805,90 +14357,54 @@ thumb_expand_movstrqi (rtx *operands)
emit_insn (gen_movmem12b (out, in, out, in));
len -= 12;
}
-
+
if (len >= 8)
{
emit_insn (gen_movmem8b (out, in, out, in));
len -= 8;
}
-
+
if (len >= 4)
{
rtx reg = gen_reg_rtx (SImode);
- emit_insn (gen_movsi (reg, gen_rtx (MEM, SImode, in)));
- emit_insn (gen_movsi (gen_rtx (MEM, SImode, out), reg));
+ emit_insn (gen_movsi (reg, gen_rtx_MEM (SImode, in)));
+ emit_insn (gen_movsi (gen_rtx_MEM (SImode, out), reg));
len -= 4;
offset += 4;
}
-
+
if (len >= 2)
{
rtx reg = gen_reg_rtx (HImode);
- emit_insn (gen_movhi (reg, gen_rtx (MEM, HImode,
- plus_constant (in, offset))));
- emit_insn (gen_movhi (gen_rtx (MEM, HImode, plus_constant (out, offset)),
+ emit_insn (gen_movhi (reg, gen_rtx_MEM (HImode,
+ plus_constant (in, offset))));
+ emit_insn (gen_movhi (gen_rtx_MEM (HImode, plus_constant (out, offset)),
reg));
len -= 2;
offset += 2;
}
-
+
if (len)
{
rtx reg = gen_reg_rtx (QImode);
- emit_insn (gen_movqi (reg, gen_rtx (MEM, QImode,
- plus_constant (in, offset))));
- emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (out, offset)),
+ emit_insn (gen_movqi (reg, gen_rtx_MEM (QImode,
+ plus_constant (in, offset))));
+ emit_insn (gen_movqi (gen_rtx_MEM (QImode, plus_constant (out, offset)),
reg));
}
}
-int
-thumb_cmp_operand (rtx op, enum machine_mode mode)
-{
- return ((GET_CODE (op) == CONST_INT
- && INTVAL (op) < 256
- && INTVAL (op) >= 0)
- || s_register_operand (op, mode));
-}
-
-int
-thumb_cmpneg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return (GET_CODE (op) == CONST_INT
- && INTVAL (op) < 0
- && INTVAL (op) > -256);
-}
-
-/* Return TRUE if a result can be stored in OP without clobbering the
- condition code register. Prior to reload we only accept a
- register. After reload we have to be able to handle memory as
- well, since a pseudo may not get a hard reg and reload cannot
- handle output-reloads on jump insns.
-
- We could possibly handle mem before reload as well, but that might
- complicate things with the need to handle increment
- side-effects. */
-
-int
-thumb_cbrch_target_operand (rtx op, enum machine_mode mode)
-{
- return (s_register_operand (op, mode)
- || ((reload_in_progress || reload_completed)
- && memory_operand (op, mode)));
-}
-
-/* Handle storing a half-word to memory during reload. */
void
thumb_reload_out_hi (rtx *operands)
{
emit_insn (gen_thumb_movhi_clobber (operands[0], operands[1], operands[2]));
}
-/* Handle reading a half-word from memory during reload. */
+/* Handle reading a half-word from memory during reload. */
void
thumb_reload_in_hi (rtx *operands ATTRIBUTE_UNUSED)
{
- abort ();
+ gcc_unreachable ();
}
/* Return the length of a function name prefix
@@ -12899,7 +14415,7 @@ arm_get_strip_length (int c)
switch (c)
{
ARM_NAME_ENCODING_LENGTHS
- default: return 0;
+ default: return 0;
}
}
@@ -12909,7 +14425,7 @@ const char *
arm_strip_name_encoding (const char *name)
{
int skip;
-
+
while ((skip = arm_get_strip_length (* name)))
name += skip;
@@ -12937,6 +14453,31 @@ arm_asm_output_labelref (FILE *stream, const char *name)
asm_fprintf (stream, "%U%s", name);
}
+static void
+arm_file_end (void)
+{
+ int regno;
+
+ if (! thumb_call_reg_needed)
+ return;
+
+ switch_to_section (text_section);
+ asm_fprintf (asm_out_file, "\t.code 16\n");
+ ASM_OUTPUT_ALIGN (asm_out_file, 1);
+
+ for (regno = 0; regno < LR_REGNUM; regno++)
+ {
+ rtx label = thumb_call_via_label[regno];
+
+ if (label != 0)
+ {
+ targetm.asm_out.internal_label (asm_out_file, "L",
+ CODE_LABEL_NUMBER (label));
+ asm_fprintf (asm_out_file, "\tbx\t%r\n", regno);
+ }
+ }
+}
+
rtx aof_pic_label;
#ifdef AOF_ASSEMBLER
@@ -12984,7 +14525,7 @@ aof_dump_pic_table (FILE *f)
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);
@@ -12995,25 +14536,56 @@ aof_dump_pic_table (FILE *f)
int arm_text_section_count = 1;
-char *
-aof_text_section (void )
+/* A get_unnamed_section callback for switching to the text section. */
+
+static void
+aof_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED)
{
- static char buf[100];
- sprintf (buf, "\tAREA |C$$code%d|, CODE, READONLY",
+ fprintf (asm_out_file, "\tAREA |C$$code%d|, CODE, READONLY",
arm_text_section_count++);
if (flag_pic)
- strcat (buf, ", PIC, REENTRANT");
- return buf;
+ fprintf (asm_out_file, ", PIC, REENTRANT");
+ fprintf (asm_out_file, "\n");
}
static int arm_data_section_count = 1;
-char *
-aof_data_section (void)
+/* A get_unnamed_section callback for switching to the data section. */
+
+static void
+aof_output_data_section_asm_op (const void *data ATTRIBUTE_UNUSED)
{
- static char buf[100];
- sprintf (buf, "\tAREA |C$$data%d|, DATA", arm_data_section_count++);
- return buf;
+ 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
@@ -13074,7 +14646,7 @@ aof_dump_imports (FILE *f)
automagically. */
if (arm_main_function)
{
- text_section ();
+ switch_to_section (text_section);
fputs ("\tIMPORT __main\n", f);
fputs ("\tDCD __main\n", f);
}
@@ -13125,7 +14697,7 @@ aof_file_start (void)
fputs ("__f5\tFN\t5\n", asm_out_file);
fputs ("__f6\tFN\t6\n", asm_out_file);
fputs ("__f7\tFN\t7\n", asm_out_file);
- text_section ();
+ switch_to_section (text_section);
}
static void
@@ -13133,67 +14705,12 @@ 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 */
-#ifdef OBJECT_FORMAT_ELF
-/* Switch to an arbitrary section NAME with attributes as specified
- by FLAGS. ALIGN specifies any known alignment requirements for
- the section; 0 if the default should be used.
-
- Differs from the default elf version only in the prefix character
- used before the section type. */
-
-static void
-arm_elf_asm_named_section (const char *name, unsigned int flags)
-{
- char flagchars[10], *f = flagchars;
-
- if (! named_section_first_declaration (name))
- {
- fprintf (asm_out_file, "\t.section\t%s\n", name);
- return;
- }
-
- if (!(flags & SECTION_DEBUG))
- *f++ = 'a';
- if (flags & SECTION_WRITE)
- *f++ = 'w';
- if (flags & SECTION_CODE)
- *f++ = 'x';
- if (flags & SECTION_SMALL)
- *f++ = 's';
- if (flags & SECTION_MERGE)
- *f++ = 'M';
- if (flags & SECTION_STRINGS)
- *f++ = 'S';
- if (flags & SECTION_TLS)
- *f++ = 'T';
- *f = '\0';
-
- fprintf (asm_out_file, "\t.section\t%s,\"%s\"", name, flagchars);
-
- if (!(flags & SECTION_NOTYPE))
- {
- const char *type;
-
- if (flags & SECTION_BSS)
- type = "nobits";
- else
- type = "progbits";
-
- fprintf (asm_out_file, ",%%%s", type);
-
- if (flags & SECTION_ENTSIZE)
- fprintf (asm_out_file, ",%d", flags & SECTION_ENTSIZE);
- }
-
- putc ('\n', asm_out_file);
-}
-#endif
-
#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
@@ -13207,21 +14724,22 @@ 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)
- && (!flag_writable_strings || TREE_CODE (decl) != STRING_CST))
+ if (optimize > 0 && TREE_CONSTANT (decl))
SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
#endif
/* If we are referencing a function that is weak then encode a long call
flag in the function name, otherwise if the function is static or
or known to be defined in this file then encode a short call flag. */
- if (first && TREE_CODE_CLASS (TREE_CODE (decl)) == 'd')
+ if (first && DECL_P (decl))
{
if (TREE_CODE (decl) == FUNCTION_DECL && DECL_WEAK (decl))
arm_encode_call_attribute (decl, LONG_CALL_FLAG_CHAR);
else if (! TREE_PUBLIC (decl))
arm_encode_call_attribute (decl, SHORT_CALL_FLAG_CHAR);
}
+
+ default_encode_section_info (decl, rtl, first);
}
#endif /* !ARM_PE */
@@ -13247,6 +14765,7 @@ arm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
{
static int thunk_label = 0;
char label[256];
+ char labelpc[256];
int mi_delta = delta;
const char *const mi_op = mi_delta < 0 ? "sub" : "add";
int shift = 0;
@@ -13261,6 +14780,23 @@ arm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
fputs ("\tldr\tr12, ", file);
assemble_name (file, label);
fputc ('\n', file);
+ if (flag_pic)
+ {
+ /* If we are generating PIC, the ldr instruction below loads
+ "(target - 7) - .LTHUNKPCn" into r12. The pc reads as
+ the address of the add + 8, so we have:
+
+ r12 = (target - 7) - .LTHUNKPCn + (.LTHUNKPCn + 8)
+ = target + 1.
+
+ Note that we have "+ 1" because some versions of GNU ld
+ don't set the low bit of the result for R_ARM_REL32
+ relocations against thumb function symbols. */
+ ASM_GENERATE_INTERNAL_LABEL (labelpc, "LTHUNKPC", labelno);
+ assemble_name (file, labelpc);
+ fputs (":\n", file);
+ fputs ("\tadd\tr12, pc, r12\n", file);
+ }
}
while (mi_delta != 0)
{
@@ -13281,7 +14817,20 @@ arm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
ASM_OUTPUT_ALIGN (file, 2);
assemble_name (file, label);
fputs (":\n", file);
- assemble_integer (XEXP (DECL_RTL (function), 0), 4, BITS_PER_WORD, 1);
+ if (flag_pic)
+ {
+ /* Output ".word .LTHUNKn-7-.LTHUNKPCn". */
+ rtx tem = XEXP (DECL_RTL (function), 0);
+ tem = gen_rtx_PLUS (GET_MODE (tem), tem, GEN_INT (-7));
+ tem = gen_rtx_MINUS (GET_MODE (tem),
+ tem,
+ gen_rtx_SYMBOL_REF (Pmode,
+ ggc_strdup (labelpc)));
+ assemble_integer (tem, 4, BITS_PER_WORD, 1);
+ }
+ else
+ /* Output ".word .LTHUNKn". */
+ assemble_integer (XEXP (DECL_RTL (function), 0), 4, BITS_PER_WORD, 1);
}
else
{
@@ -13299,15 +14848,14 @@ arm_emit_vector_const (FILE *file, rtx x)
int i;
const char * pattern;
- if (GET_CODE (x) != CONST_VECTOR)
- abort ();
+ gcc_assert (GET_CODE (x) == CONST_VECTOR);
switch (GET_MODE (x))
{
case V2SImode: pattern = "%08x"; break;
case V4HImode: pattern = "%04x"; break;
case V8QImode: pattern = "%02x"; break;
- default: abort ();
+ default: gcc_unreachable ();
}
fprintf (file, "0x");
@@ -13329,15 +14877,15 @@ arm_output_load_gr (rtx *operands)
rtx offset;
rtx wcgr;
rtx sum;
-
+
if (GET_CODE (operands [1]) != MEM
|| GET_CODE (sum = XEXP (operands [1], 0)) != PLUS
|| GET_CODE (reg = XEXP (sum, 0)) != REG
|| GET_CODE (offset = XEXP (sum, 1)) != CONST_INT
|| ((INTVAL (offset) < 1024) && (INTVAL (offset) > -1024)))
return "wldrw%?\t%0, %1";
-
- /* Fix up an out-of-range load of a GR register. */
+
+ /* Fix up an out-of-range load of a GR register. */
output_asm_insn ("str%?\t%0, [sp, #-4]!\t@ Start of GR load expansion", & reg);
wcgr = operands[0];
operands[0] = reg;
@@ -13350,3 +14898,740 @@ arm_output_load_gr (rtx *operands)
return "";
}
+
+/* Worker function for TARGET_SETUP_INCOMING_VARARGS.
+
+ On the ARM, PRETEND_SIZE is set in order to have the prologue push the last
+ named arg and all anonymous args onto the stack.
+ XXX I know the prologue shouldn't be pushing registers, but it is faster
+ that way. */
+
+static void
+arm_setup_incoming_varargs (CUMULATIVE_ARGS *cum,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ tree type ATTRIBUTE_UNUSED,
+ int *pretend_size,
+ int second_time ATTRIBUTE_UNUSED)
+{
+ cfun->machine->uses_anonymous_args = 1;
+ if (cum->nregs < NUM_ARG_REGS)
+ *pretend_size = (NUM_ARG_REGS - cum->nregs) * UNITS_PER_WORD;
+}
+
+/* Return nonzero if the CONSUMER instruction (a store) does not need
+ PRODUCER's value to calculate the address. */
+
+int
+arm_no_early_store_addr_dep (rtx producer, rtx consumer)
+{
+ rtx value = PATTERN (producer);
+ rtx addr = PATTERN (consumer);
+
+ if (GET_CODE (value) == COND_EXEC)
+ value = COND_EXEC_CODE (value);
+ if (GET_CODE (value) == PARALLEL)
+ value = XVECEXP (value, 0, 0);
+ value = XEXP (value, 0);
+ if (GET_CODE (addr) == COND_EXEC)
+ addr = COND_EXEC_CODE (addr);
+ if (GET_CODE (addr) == PARALLEL)
+ addr = XVECEXP (addr, 0, 0);
+ addr = XEXP (addr, 0);
+
+ return !reg_overlap_mentioned_p (value, addr);
+}
+
+/* Return nonzero if the CONSUMER instruction (an ALU op) does not
+ have an early register shift value or amount dependency on the
+ result of PRODUCER. */
+
+int
+arm_no_early_alu_shift_dep (rtx producer, rtx consumer)
+{
+ rtx value = PATTERN (producer);
+ rtx op = PATTERN (consumer);
+ rtx early_op;
+
+ if (GET_CODE (value) == COND_EXEC)
+ value = COND_EXEC_CODE (value);
+ if (GET_CODE (value) == PARALLEL)
+ value = XVECEXP (value, 0, 0);
+ value = XEXP (value, 0);
+ if (GET_CODE (op) == COND_EXEC)
+ op = COND_EXEC_CODE (op);
+ if (GET_CODE (op) == PARALLEL)
+ op = XVECEXP (op, 0, 0);
+ op = XEXP (op, 1);
+
+ early_op = XEXP (op, 0);
+ /* This is either an actual independent shift, or a shift applied to
+ the first operand of another operation. We want the whole shift
+ operation. */
+ if (GET_CODE (early_op) == REG)
+ early_op = op;
+
+ return !reg_overlap_mentioned_p (value, early_op);
+}
+
+/* Return nonzero if the CONSUMER instruction (an ALU op) does not
+ have an early register shift value dependency on the result of
+ PRODUCER. */
+
+int
+arm_no_early_alu_shift_value_dep (rtx producer, rtx consumer)
+{
+ rtx value = PATTERN (producer);
+ rtx op = PATTERN (consumer);
+ rtx early_op;
+
+ if (GET_CODE (value) == COND_EXEC)
+ value = COND_EXEC_CODE (value);
+ if (GET_CODE (value) == PARALLEL)
+ value = XVECEXP (value, 0, 0);
+ value = XEXP (value, 0);
+ if (GET_CODE (op) == COND_EXEC)
+ op = COND_EXEC_CODE (op);
+ if (GET_CODE (op) == PARALLEL)
+ op = XVECEXP (op, 0, 0);
+ op = XEXP (op, 1);
+
+ early_op = XEXP (op, 0);
+
+ /* This is either an actual independent shift, or a shift applied to
+ the first operand of another operation. We want the value being
+ shifted, in either case. */
+ if (GET_CODE (early_op) != REG)
+ early_op = XEXP (early_op, 0);
+
+ return !reg_overlap_mentioned_p (value, early_op);
+}
+
+/* Return nonzero if the CONSUMER (a mul or mac op) does not
+ have an early register mult dependency on the result of
+ PRODUCER. */
+
+int
+arm_no_early_mul_dep (rtx producer, rtx consumer)
+{
+ rtx value = PATTERN (producer);
+ rtx op = PATTERN (consumer);
+
+ if (GET_CODE (value) == COND_EXEC)
+ value = COND_EXEC_CODE (value);
+ if (GET_CODE (value) == PARALLEL)
+ value = XVECEXP (value, 0, 0);
+ value = XEXP (value, 0);
+ if (GET_CODE (op) == COND_EXEC)
+ op = COND_EXEC_CODE (op);
+ if (GET_CODE (op) == PARALLEL)
+ op = XVECEXP (op, 0, 0);
+ op = XEXP (op, 1);
+
+ return (GET_CODE (op) == PLUS
+ && !reg_overlap_mentioned_p (value, XEXP (op, 0)));
+}
+
+
+/* We can't rely on the caller doing the proper promotion when
+ using APCS or ATPCS. */
+
+static bool
+arm_promote_prototypes (tree t ATTRIBUTE_UNUSED)
+{
+ return !TARGET_AAPCS_BASED;
+}
+
+
+/* AAPCS based ABIs use short enums by default. */
+
+static bool
+arm_default_short_enums (void)
+{
+ return TARGET_AAPCS_BASED && arm_abi != ARM_ABI_AAPCS_LINUX;
+}
+
+
+/* AAPCS requires that anonymous bitfields affect structure alignment. */
+
+static bool
+arm_align_anon_bitfield (void)
+{
+ return TARGET_AAPCS_BASED;
+}
+
+
+/* The generic C++ ABI says 64-bit (long long). The EABI says 32-bit. */
+
+static tree
+arm_cxx_guard_type (void)
+{
+ return TARGET_AAPCS_BASED ? integer_type_node : long_long_integer_type_node;
+}
+
+
+/* The EABI says test the least significant bit of a guard variable. */
+
+static bool
+arm_cxx_guard_mask_bit (void)
+{
+ return TARGET_AAPCS_BASED;
+}
+
+
+/* The EABI specifies that all array cookies are 8 bytes long. */
+
+static tree
+arm_get_cookie_size (tree type)
+{
+ tree size;
+
+ if (!TARGET_AAPCS_BASED)
+ return default_cxx_get_cookie_size (type);
+
+ size = build_int_cst (sizetype, 8);
+ return size;
+}
+
+
+/* The EABI says that array cookies should also contain the element size. */
+
+static bool
+arm_cookie_has_size (void)
+{
+ return TARGET_AAPCS_BASED;
+}
+
+
+/* The EABI says constructors and destructors should return a pointer to
+ the object constructed/destroyed. */
+
+static bool
+arm_cxx_cdtor_returns_this (void)
+{
+ return TARGET_AAPCS_BASED;
+}
+
+/* The EABI says that an inline function may never be the key
+ method. */
+
+static bool
+arm_cxx_key_method_may_be_inline (void)
+{
+ return !TARGET_AAPCS_BASED;
+}
+
+static void
+arm_cxx_determine_class_data_visibility (tree decl)
+{
+ if (!TARGET_AAPCS_BASED)
+ return;
+
+ /* In general, \S 3.2.5.5 of the ARM EABI requires that class data
+ is exported. However, on systems without dynamic vague linkage,
+ \S 3.2.5.6 says that COMDAT class data has hidden linkage. */
+ if (!TARGET_ARM_DYNAMIC_VAGUE_LINKAGE_P && DECL_COMDAT (decl))
+ DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
+ else
+ DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
+ DECL_VISIBILITY_SPECIFIED (decl) = 1;
+}
+
+static bool
+arm_cxx_class_data_always_comdat (void)
+{
+ /* \S 3.2.5.4 of the ARM C++ ABI says that class data only have
+ vague linkage if the class has no key function. */
+ return !TARGET_AAPCS_BASED;
+}
+
+
+/* The EABI says __aeabi_atexit should be used to register static
+ destructors. */
+
+static bool
+arm_cxx_use_aeabi_atexit (void)
+{
+ return TARGET_AAPCS_BASED;
+}
+
+
+void
+arm_set_return_address (rtx source, rtx scratch)
+{
+ arm_stack_offsets *offsets;
+ HOST_WIDE_INT delta;
+ rtx addr;
+ unsigned long saved_regs;
+
+ saved_regs = arm_compute_save_reg_mask ();
+
+ if ((saved_regs & (1 << LR_REGNUM)) == 0)
+ emit_move_insn (gen_rtx_REG (Pmode, LR_REGNUM), source);
+ else
+ {
+ if (frame_pointer_needed)
+ addr = plus_constant(hard_frame_pointer_rtx, -4);
+ else
+ {
+ /* LR will be the first saved register. */
+ offsets = arm_get_frame_offsets ();
+ delta = offsets->outgoing_args - (offsets->frame + 4);
+
+
+ if (delta >= 4096)
+ {
+ emit_insn (gen_addsi3 (scratch, stack_pointer_rtx,
+ GEN_INT (delta & ~4095)));
+ addr = scratch;
+ delta &= 4095;
+ }
+ else
+ addr = stack_pointer_rtx;
+
+ addr = plus_constant (addr, delta);
+ }
+ emit_move_insn (gen_frame_mem (Pmode, addr), source);
+ }
+}
+
+
+void
+thumb_set_return_address (rtx source, rtx scratch)
+{
+ arm_stack_offsets *offsets;
+ HOST_WIDE_INT delta;
+ int reg;
+ rtx addr;
+ unsigned long mask;
+
+ emit_insn (gen_rtx_USE (VOIDmode, source));
+
+ mask = thumb_compute_save_reg_mask ();
+ if (mask & (1 << LR_REGNUM))
+ {
+ offsets = arm_get_frame_offsets ();
+
+ /* Find the saved regs. */
+ if (frame_pointer_needed)
+ {
+ delta = offsets->soft_frame - offsets->saved_args;
+ reg = THUMB_HARD_FRAME_POINTER_REGNUM;
+ }
+ else
+ {
+ delta = offsets->outgoing_args - offsets->saved_args;
+ reg = SP_REGNUM;
+ }
+ /* Allow for the stack frame. */
+ if (TARGET_BACKTRACE)
+ delta -= 16;
+ /* The link register is always the first saved register. */
+ delta -= 4;
+
+ /* Construct the address. */
+ addr = gen_rtx_REG (SImode, reg);
+ if ((reg != SP_REGNUM && delta >= 128)
+ || delta >= 1024)
+ {
+ emit_insn (gen_movsi (scratch, GEN_INT (delta)));
+ emit_insn (gen_addsi3 (scratch, scratch, stack_pointer_rtx));
+ addr = scratch;
+ }
+ else
+ addr = plus_constant (addr, delta);
+
+ emit_move_insn (gen_frame_mem (Pmode, addr), source);
+ }
+ else
+ emit_move_insn (gen_rtx_REG (Pmode, LR_REGNUM), source);
+}
+
+/* Implements target hook vector_mode_supported_p. */
+bool
+arm_vector_mode_supported_p (enum machine_mode mode)
+{
+ if ((mode == V2SImode)
+ || (mode == V4HImode)
+ || (mode == V8QImode))
+ return true;
+
+ return false;
+}
+
+/* Implement TARGET_SHIFT_TRUNCATION_MASK. SImode shifts use normal
+ ARM insns and therefore guarantee that the shift count is modulo 256.
+ DImode shifts (those implemented by lib1funcs.asm or by optabs.c)
+ guarantee no particular behavior for out-of-range counts. */
+
+static unsigned HOST_WIDE_INT
+arm_shift_truncation_mask (enum machine_mode mode)
+{
+ return mode == SImode ? 255 : 0;
+}
+
+
+/* Map internal gcc register numbers to DWARF2 register numbers. */
+
+unsigned int
+arm_dbx_register_number (unsigned int regno)
+{
+ if (regno < 16)
+ return regno;
+
+ /* TODO: Legacy targets output FPA regs as registers 16-23 for backwards
+ compatibility. The EABI defines them as registers 96-103. */
+ if (IS_FPA_REGNUM (regno))
+ return (TARGET_AAPCS_BASED ? 96 : 16) + regno - FIRST_FPA_REGNUM;
+
+ if (IS_VFP_REGNUM (regno))
+ return 64 + regno - FIRST_VFP_REGNUM;
+
+ if (IS_IWMMXT_GR_REGNUM (regno))
+ return 104 + regno - FIRST_IWMMXT_GR_REGNUM;
+
+ if (IS_IWMMXT_REGNUM (regno))
+ return 112 + regno - FIRST_IWMMXT_REGNUM;
+
+ gcc_unreachable ();
+}
+
+
+#ifdef TARGET_UNWIND_INFO
+/* Emit unwind directives for a store-multiple instruction. This should
+ only ever be generated by the function prologue code, so we expect it
+ to have a particular form. */
+
+static void
+arm_unwind_emit_stm (FILE * asm_out_file, rtx p)
+{
+ int i;
+ HOST_WIDE_INT offset;
+ HOST_WIDE_INT nregs;
+ int reg_size;
+ unsigned reg;
+ unsigned lastreg;
+ rtx e;
+
+ /* First insn will adjust the stack pointer. */
+ e = XVECEXP (p, 0, 0);
+ if (GET_CODE (e) != SET
+ || GET_CODE (XEXP (e, 0)) != REG
+ || REGNO (XEXP (e, 0)) != SP_REGNUM
+ || GET_CODE (XEXP (e, 1)) != PLUS)
+ abort ();
+
+ offset = -INTVAL (XEXP (XEXP (e, 1), 1));
+ nregs = XVECLEN (p, 0) - 1;
+
+ reg = REGNO (XEXP (XVECEXP (p, 0, 1), 1));
+ if (reg < 16)
+ {
+ /* The function prologue may also push pc, but not annotate it as it is
+ never restored. We turn this into a stack pointer adjustment. */
+ if (nregs * 4 == offset - 4)
+ {
+ fprintf (asm_out_file, "\t.pad #4\n");
+ offset -= 4;
+ }
+ reg_size = 4;
+ }
+ else if (IS_VFP_REGNUM (reg))
+ {
+ /* FPA register saves use an additional word. */
+ offset -= 4;
+ reg_size = 8;
+ }
+ else if (reg >= FIRST_FPA_REGNUM && reg <= LAST_FPA_REGNUM)
+ {
+ /* FPA registers are done differently. */
+ asm_fprintf (asm_out_file, "\t.save %r, %wd\n", reg, nregs);
+ return;
+ }
+ else
+ /* Unknown register type. */
+ abort ();
+
+ /* If the stack increment doesn't match the size of the saved registers,
+ something has gone horribly wrong. */
+ if (offset != nregs * reg_size)
+ abort ();
+
+ fprintf (asm_out_file, "\t.save {");
+
+ offset = 0;
+ lastreg = 0;
+ /* The remaining insns will describe the stores. */
+ for (i = 1; i <= nregs; i++)
+ {
+ /* Expect (set (mem <addr>) (reg)).
+ Where <addr> is (reg:SP) or (plus (reg:SP) (const_int)). */
+ e = XVECEXP (p, 0, i);
+ if (GET_CODE (e) != SET
+ || GET_CODE (XEXP (e, 0)) != MEM
+ || GET_CODE (XEXP (e, 1)) != REG)
+ abort ();
+
+ reg = REGNO (XEXP (e, 1));
+ if (reg < lastreg)
+ abort ();
+
+ if (i != 1)
+ fprintf (asm_out_file, ", ");
+ /* We can't use %r for vfp because we need to use the
+ double precision register names. */
+ if (IS_VFP_REGNUM (reg))
+ asm_fprintf (asm_out_file, "d%d", (reg - FIRST_VFP_REGNUM) / 2);
+ else
+ asm_fprintf (asm_out_file, "%r", reg);
+
+#ifdef ENABLE_CHECKING
+ /* Check that the addresses are consecutive. */
+ e = XEXP (XEXP (e, 0), 0);
+ if (GET_CODE (e) == PLUS)
+ {
+ offset += reg_size;
+ if (GET_CODE (XEXP (e, 0)) != REG
+ || REGNO (XEXP (e, 0)) != SP_REGNUM
+ || GET_CODE (XEXP (e, 1)) != CONST_INT
+ || offset != INTVAL (XEXP (e, 1)))
+ abort ();
+ }
+ else if (i != 1
+ || GET_CODE (e) != REG
+ || REGNO (e) != SP_REGNUM)
+ abort ();
+#endif
+ }
+ fprintf (asm_out_file, "}\n");
+}
+
+/* Emit unwind directives for a SET. */
+
+static void
+arm_unwind_emit_set (FILE * asm_out_file, rtx p)
+{
+ rtx e0;
+ rtx e1;
+
+ e0 = XEXP (p, 0);
+ e1 = XEXP (p, 1);
+ switch (GET_CODE (e0))
+ {
+ case MEM:
+ /* Pushing a single register. */
+ if (GET_CODE (XEXP (e0, 0)) != PRE_DEC
+ || GET_CODE (XEXP (XEXP (e0, 0), 0)) != REG
+ || REGNO (XEXP (XEXP (e0, 0), 0)) != SP_REGNUM)
+ abort ();
+
+ asm_fprintf (asm_out_file, "\t.save ");
+ if (IS_VFP_REGNUM (REGNO (e1)))
+ asm_fprintf(asm_out_file, "{d%d}\n",
+ (REGNO (e1) - FIRST_VFP_REGNUM) / 2);
+ else
+ asm_fprintf(asm_out_file, "{%r}\n", REGNO (e1));
+ break;
+
+ case REG:
+ if (REGNO (e0) == SP_REGNUM)
+ {
+ /* A stack increment. */
+ if (GET_CODE (e1) != PLUS
+ || GET_CODE (XEXP (e1, 0)) != REG
+ || REGNO (XEXP (e1, 0)) != SP_REGNUM
+ || GET_CODE (XEXP (e1, 1)) != CONST_INT)
+ abort ();
+
+ asm_fprintf (asm_out_file, "\t.pad #%wd\n",
+ -INTVAL (XEXP (e1, 1)));
+ }
+ else if (REGNO (e0) == HARD_FRAME_POINTER_REGNUM)
+ {
+ HOST_WIDE_INT offset;
+ unsigned reg;
+
+ if (GET_CODE (e1) == PLUS)
+ {
+ if (GET_CODE (XEXP (e1, 0)) != REG
+ || GET_CODE (XEXP (e1, 1)) != CONST_INT)
+ abort ();
+ reg = REGNO (XEXP (e1, 0));
+ offset = INTVAL (XEXP (e1, 1));
+ asm_fprintf (asm_out_file, "\t.setfp %r, %r, #%wd\n",
+ HARD_FRAME_POINTER_REGNUM, reg,
+ INTVAL (XEXP (e1, 1)));
+ }
+ else if (GET_CODE (e1) == REG)
+ {
+ reg = REGNO (e1);
+ asm_fprintf (asm_out_file, "\t.setfp %r, %r\n",
+ HARD_FRAME_POINTER_REGNUM, reg);
+ }
+ else
+ abort ();
+ }
+ else if (GET_CODE (e1) == REG && REGNO (e1) == SP_REGNUM)
+ {
+ /* Move from sp to reg. */
+ asm_fprintf (asm_out_file, "\t.movsp %r\n", REGNO (e0));
+ }
+ else if (GET_CODE (e1) == PLUS
+ && GET_CODE (XEXP (e1, 0)) == REG
+ && REGNO (XEXP (e1, 0)) == SP_REGNUM
+ && GET_CODE (XEXP (e1, 1)) == CONST_INT)
+ {
+ /* Set reg to offset from sp. */
+ asm_fprintf (asm_out_file, "\t.movsp %r, #%d\n",
+ REGNO (e0), (int)INTVAL(XEXP (e1, 1)));
+ }
+ else
+ abort ();
+ break;
+
+ default:
+ abort ();
+ }
+}
+
+
+/* Emit unwind directives for the given insn. */
+
+static void
+arm_unwind_emit (FILE * asm_out_file, rtx insn)
+{
+ rtx pat;
+
+ if (!ARM_EABI_UNWIND_TABLES)
+ return;
+
+ if (GET_CODE (insn) == NOTE || !RTX_FRAME_RELATED_P (insn))
+ return;
+
+ pat = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX);
+ if (pat)
+ pat = XEXP (pat, 0);
+ else
+ pat = PATTERN (insn);
+
+ switch (GET_CODE (pat))
+ {
+ case SET:
+ arm_unwind_emit_set (asm_out_file, pat);
+ break;
+
+ case SEQUENCE:
+ /* Store multiple. */
+ arm_unwind_emit_stm (asm_out_file, pat);
+ break;
+
+ default:
+ abort();
+ }
+}
+
+
+/* Output a reference from a function exception table to the type_info
+ object X. The EABI specifies that the symbol should be relocated by
+ an R_ARM_TARGET2 relocation. */
+
+static bool
+arm_output_ttype (rtx x)
+{
+ fputs ("\t.word\t", asm_out_file);
+ output_addr_const (asm_out_file, x);
+ /* Use special relocations for symbol references. */
+ if (GET_CODE (x) != CONST_INT)
+ fputs ("(TARGET2)", asm_out_file);
+ fputc ('\n', asm_out_file);
+
+ return TRUE;
+}
+#endif /* TARGET_UNWIND_INFO */
+
+
+/* Output unwind directives for the start/end of a function. */
+
+void
+arm_output_fn_unwind (FILE * f, bool prologue)
+{
+ if (!ARM_EABI_UNWIND_TABLES)
+ return;
+
+ if (prologue)
+ fputs ("\t.fnstart\n", f);
+ else
+ fputs ("\t.fnend\n", f);
+}
+
+static bool
+arm_emit_tls_decoration (FILE *fp, rtx x)
+{
+ enum tls_reloc reloc;
+ rtx val;
+
+ val = XVECEXP (x, 0, 0);
+ reloc = INTVAL (XVECEXP (x, 0, 1));
+
+ output_addr_const (fp, val);
+
+ switch (reloc)
+ {
+ case TLS_GD32:
+ fputs ("(tlsgd)", fp);
+ break;
+ case TLS_LDM32:
+ fputs ("(tlsldm)", fp);
+ break;
+ case TLS_LDO32:
+ fputs ("(tlsldo)", fp);
+ break;
+ case TLS_IE32:
+ fputs ("(gottpoff)", fp);
+ break;
+ case TLS_LE32:
+ fputs ("(tpoff)", fp);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ switch (reloc)
+ {
+ case TLS_GD32:
+ case TLS_LDM32:
+ case TLS_IE32:
+ fputs (" + (. - ", fp);
+ output_addr_const (fp, XVECEXP (x, 0, 2));
+ fputs (" - ", fp);
+ output_addr_const (fp, XVECEXP (x, 0, 3));
+ fputc (')', fp);
+ break;
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+bool
+arm_output_addr_const_extra (FILE *fp, rtx x)
+{
+ if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
+ return arm_emit_tls_decoration (fp, x);
+ else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_PIC_LABEL)
+ {
+ char label[256];
+ int labelno = INTVAL (XVECEXP (x, 0, 0));
+
+ ASM_GENERATE_INTERNAL_LABEL (label, "LPIC", labelno);
+ assemble_name_raw (fp, label);
+
+ return TRUE;
+ }
+ else if (GET_CODE (x) == CONST_VECTOR)
+ return arm_emit_vector_const (fp, x);
+
+ return FALSE;
+}
+
+#include "gt-arm.h"
diff --git a/contrib/gcc/config/arm/arm.h b/contrib/gcc/config/arm/arm.h
index 94d8b94..784142c 100644
--- a/contrib/gcc/config/arm/arm.h
+++ b/contrib/gcc/config/arm/arm.h
@@ -1,6 +1,6 @@
/* Definitions of target machine for GNU compiler, for ARM.
Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 2001, 2002, 2003, 2004, 2005, 2006 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)
@@ -20,19 +20,24 @@
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, 59 Temple Place - Suite 330, Boston,
- MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301, USA. */
#ifndef GCC_ARM_H
#define GCC_ARM_H
+/* The architecture define. */
+extern char arm_arch_name[];
+
/* Target CPU builtins. */
#define TARGET_CPU_CPP_BUILTINS() \
do \
{ \
- if (TARGET_ARM) \
- builtin_define ("__arm__"); \
- else \
+ /* Define __arm__ even when in thumb mode, for \
+ consistency with armcc. */ \
+ builtin_define ("__arm__"); \
+ builtin_define ("__APCS_32__"); \
+ if (TARGET_THUMB) \
builtin_define ("__thumb__"); \
\
if (TARGET_BIG_END) \
@@ -50,60 +55,53 @@
builtin_define ("__THUMBEL__"); \
} \
\
- if (TARGET_APCS_32) \
- builtin_define ("__APCS_32__"); \
- else \
- builtin_define ("__APCS_26__"); \
- \
if (TARGET_SOFT_FLOAT) \
builtin_define ("__SOFTFP__"); \
\
- /* FIXME: TARGET_HARD_FLOAT currently implies \
- FPA. */ \
- if (TARGET_VFP && !TARGET_HARD_FLOAT) \
+ if (TARGET_VFP) \
builtin_define ("__VFP_FP__"); \
\
/* Add a define for interworking. \
Needed when building libgcc.a. */ \
- if (TARGET_INTERWORK) \
+ if (arm_cpp_interwork) \
builtin_define ("__THUMB_INTERWORK__"); \
\
builtin_assert ("cpu=arm"); \
builtin_assert ("machine=arm"); \
+ \
+ builtin_define (arm_arch_name); \
+ if (arm_arch_cirrus) \
+ builtin_define ("__MAVERICK__"); \
+ if (arm_arch_xscale) \
+ builtin_define ("__XSCALE__"); \
+ if (arm_arch_iwmmxt) \
+ builtin_define ("__IWMMXT__"); \
+ if (TARGET_AAPCS_BASED) \
+ builtin_define ("__ARM_EABI__"); \
} while (0)
-#define TARGET_CPU_arm2 0x0000
-#define TARGET_CPU_arm250 0x0000
-#define TARGET_CPU_arm3 0x0000
-#define TARGET_CPU_arm6 0x0001
-#define TARGET_CPU_arm600 0x0001
-#define TARGET_CPU_arm610 0x0002
-#define TARGET_CPU_arm7 0x0001
-#define TARGET_CPU_arm7m 0x0004
-#define TARGET_CPU_arm7dm 0x0004
-#define TARGET_CPU_arm7dmi 0x0004
-#define TARGET_CPU_arm700 0x0001
-#define TARGET_CPU_arm710 0x0002
-#define TARGET_CPU_arm7100 0x0002
-#define TARGET_CPU_arm7500 0x0002
-#define TARGET_CPU_arm7500fe 0x1001
-#define TARGET_CPU_arm7tdmi 0x0008
-#define TARGET_CPU_arm8 0x0010
-#define TARGET_CPU_arm810 0x0020
-#define TARGET_CPU_strongarm 0x0040
-#define TARGET_CPU_strongarm110 0x0040
-#define TARGET_CPU_strongarm1100 0x0040
-#define TARGET_CPU_arm9 0x0080
-#define TARGET_CPU_arm9tdmi 0x0080
-#define TARGET_CPU_xscale 0x0100
-#define TARGET_CPU_ep9312 0x0200
-#define TARGET_CPU_iwmmxt 0x0400
-#define TARGET_CPU_arm926ej_s 0x0800
-#define TARGET_CPU_arm1026ej_s 0x1000
-#define TARGET_CPU_arm1136j_s 0x2000
-#define TARGET_CPU_arm1136jf_s 0x4000
-/* Configure didn't specify. */
-#define TARGET_CPU_generic 0x8000
+/* The various ARM cores. */
+enum processor_type
+{
+#define ARM_CORE(NAME, IDENT, ARCH, FLAGS, COSTS) \
+ IDENT,
+#include "arm-cores.def"
+#undef ARM_CORE
+ /* Used to indicate that no processor has been specified. */
+ arm_none
+};
+
+enum target_cpus
+{
+#define ARM_CORE(NAME, IDENT, ARCH, FLAGS, COSTS) \
+ TARGET_CPU_##IDENT,
+#include "arm-cores.def"
+#undef ARM_CORE
+ TARGET_CPU_generic
+};
+
+/* The processor for which instructions should be scheduled. */
+extern enum processor_type arm_tune;
typedef enum arm_cond_code
{
@@ -119,10 +117,6 @@ extern arm_cc arm_current_cc;
extern int arm_target_label;
extern int arm_ccfsm_state;
extern GTY(()) rtx arm_target_insn;
-/* Run-time compilation parameters selecting different hardware subsets. */
-extern int target_flags;
-/* The floating point instruction architecture, can be 2 or 3 */
-extern const char * target_fp_name;
/* Define the information needed to generate branch insns. This is
stored from the compare operation. */
extern GTY(()) rtx arm_compare_op0;
@@ -140,147 +134,14 @@ extern GTY(()) rtx aof_pic_label;
#define TARGET_CPU_DEFAULT TARGET_CPU_generic
#endif
-/* If the configuration file doesn't specify the cpu, the subtarget may
- override it. If it doesn't, then default to an ARM6. */
-#if TARGET_CPU_DEFAULT == TARGET_CPU_generic
-#undef TARGET_CPU_DEFAULT
-
-#ifdef SUBTARGET_CPU_DEFAULT
-#define TARGET_CPU_DEFAULT SUBTARGET_CPU_DEFAULT
-#else
-#define TARGET_CPU_DEFAULT TARGET_CPU_arm6
-#endif
-#endif
-
-#if TARGET_CPU_DEFAULT == TARGET_CPU_arm2
-#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_2__"
-#else
-#if TARGET_CPU_DEFAULT == TARGET_CPU_arm6 || TARGET_CPU_DEFAULT == TARGET_CPU_arm610 || TARGET_CPU_DEFAULT == TARGET_CPU_arm7500fe
-#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_3__"
-#else
-#if TARGET_CPU_DEFAULT == TARGET_CPU_arm7m
-#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_3M__"
-#else
-#if TARGET_CPU_DEFAULT == TARGET_CPU_arm7tdmi || TARGET_CPU_DEFAULT == TARGET_CPU_arm9 || TARGET_CPU_DEFAULT == TARGET_CPU_arm9tdmi
-#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_4T__"
-#else
-#if TARGET_CPU_DEFAULT == TARGET_CPU_arm8 || TARGET_CPU_DEFAULT == TARGET_CPU_arm810 || TARGET_CPU_DEFAULT == TARGET_CPU_strongarm || TARGET_CPU_DEFAULT == TARGET_CPU_strongarm110 || TARGET_CPU_DEFAULT == TARGET_CPU_strongarm1100
-#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_4__"
-#else
-#if TARGET_CPU_DEFAULT == TARGET_CPU_xscale
-#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_5TE__ -D__XSCALE__"
-#else
-#if TARGET_CPU_DEFAULT == TARGET_CPU_ep9312
-#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_4T__ -D__MAVERICK__"
-/* Set TARGET_DEFAULT to the default, but without soft-float. */
-#ifdef TARGET_DEFAULT
-#undef TARGET_DEFAULT
-#define TARGET_DEFAULT \
- (ARM_FLAG_APCS_32 | ARM_FLAG_MMU_TRAPS | ARM_FLAG_APCS_FRAME)
-#endif
-#else
-#if TARGET_CPU_DEFAULT == TARGET_CPU_iwmmxt
-#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_5TE__ -D__XSCALE__ -D__IWMMXT__"
-#else
-#error Unrecognized value in TARGET_CPU_DEFAULT.
-#endif
-#endif
-#endif
-#endif
-#endif
-#endif
-#endif
-#endif
#undef CPP_SPEC
-#define CPP_SPEC "%(cpp_cpu_arch) %(subtarget_cpp_spec) \
-%{mapcs-32:%{mapcs-26: \
- %e-mapcs-26 and -mapcs-32 may not be used together}} \
+#define CPP_SPEC "%(subtarget_cpp_spec) \
%{msoft-float:%{mhard-float: \
%e-msoft-float and -mhard_float may not be used together}} \
%{mbig-endian:%{mlittle-endian: \
%e-mbig-endian and -mlittle-endian may not be used together}}"
-/* Set the architecture define -- if -march= is set, then it overrides
- the -mcpu= setting. */
-#define CPP_CPU_ARCH_SPEC "\
-%{march=arm2:-D__ARM_ARCH_2__} \
-%{march=arm250:-D__ARM_ARCH_2__} \
-%{march=arm3:-D__ARM_ARCH_2__} \
-%{march=arm6:-D__ARM_ARCH_3__} \
-%{march=arm600:-D__ARM_ARCH_3__} \
-%{march=arm610:-D__ARM_ARCH_3__} \
-%{march=arm7:-D__ARM_ARCH_3__} \
-%{march=arm700:-D__ARM_ARCH_3__} \
-%{march=arm710:-D__ARM_ARCH_3__} \
-%{march=arm720:-D__ARM_ARCH_3__} \
-%{march=arm7100:-D__ARM_ARCH_3__} \
-%{march=arm7500:-D__ARM_ARCH_3__} \
-%{march=arm7500fe:-D__ARM_ARCH_3__} \
-%{march=arm7m:-D__ARM_ARCH_3M__} \
-%{march=arm7dm:-D__ARM_ARCH_3M__} \
-%{march=arm7dmi:-D__ARM_ARCH_3M__} \
-%{march=arm7tdmi:-D__ARM_ARCH_4T__} \
-%{march=arm8:-D__ARM_ARCH_4__} \
-%{march=arm810:-D__ARM_ARCH_4__} \
-%{march=arm9:-D__ARM_ARCH_4T__} \
-%{march=arm920:-D__ARM_ARCH_4__} \
-%{march=arm920t:-D__ARM_ARCH_4T__} \
-%{march=arm9tdmi:-D__ARM_ARCH_4T__} \
-%{march=strongarm:-D__ARM_ARCH_4__} \
-%{march=strongarm110:-D__ARM_ARCH_4__} \
-%{march=strongarm1100:-D__ARM_ARCH_4__} \
-%{march=xscale:-D__ARM_ARCH_5TE__} \
-%{march=xscale:-D__XSCALE__} \
-%{march=ep9312:-D__ARM_ARCH_4T__} \
-%{march=ep9312:-D__MAVERICK__} \
-%{march=armv2:-D__ARM_ARCH_2__} \
-%{march=armv2a:-D__ARM_ARCH_2__} \
-%{march=armv3:-D__ARM_ARCH_3__} \
-%{march=armv3m:-D__ARM_ARCH_3M__} \
-%{march=armv4:-D__ARM_ARCH_4__} \
-%{march=armv4t:-D__ARM_ARCH_4T__} \
-%{march=armv5:-D__ARM_ARCH_5__} \
-%{march=armv5t:-D__ARM_ARCH_5T__} \
-%{march=armv5e:-D__ARM_ARCH_5E__} \
-%{march=armv5te:-D__ARM_ARCH_5TE__} \
-%{!march=*: \
- %{mcpu=arm2:-D__ARM_ARCH_2__} \
- %{mcpu=arm250:-D__ARM_ARCH_2__} \
- %{mcpu=arm3:-D__ARM_ARCH_2__} \
- %{mcpu=arm6:-D__ARM_ARCH_3__} \
- %{mcpu=arm600:-D__ARM_ARCH_3__} \
- %{mcpu=arm610:-D__ARM_ARCH_3__} \
- %{mcpu=arm7:-D__ARM_ARCH_3__} \
- %{mcpu=arm700:-D__ARM_ARCH_3__} \
- %{mcpu=arm710:-D__ARM_ARCH_3__} \
- %{mcpu=arm720:-D__ARM_ARCH_3__} \
- %{mcpu=arm7100:-D__ARM_ARCH_3__} \
- %{mcpu=arm7500:-D__ARM_ARCH_3__} \
- %{mcpu=arm7500fe:-D__ARM_ARCH_3__} \
- %{mcpu=arm7m:-D__ARM_ARCH_3M__} \
- %{mcpu=arm7dm:-D__ARM_ARCH_3M__} \
- %{mcpu=arm7dmi:-D__ARM_ARCH_3M__} \
- %{mcpu=arm7tdmi:-D__ARM_ARCH_4T__} \
- %{mcpu=arm8:-D__ARM_ARCH_4__} \
- %{mcpu=arm810:-D__ARM_ARCH_4__} \
- %{mcpu=arm9:-D__ARM_ARCH_4T__} \
- %{mcpu=arm920:-D__ARM_ARCH_4__} \
- %{mcpu=arm920t:-D__ARM_ARCH_4T__} \
- %{mcpu=arm9tdmi:-D__ARM_ARCH_4T__} \
- %{mcpu=strongarm:-D__ARM_ARCH_4__} \
- %{mcpu=strongarm110:-D__ARM_ARCH_4__} \
- %{mcpu=strongarm1100:-D__ARM_ARCH_4__} \
- %{mcpu=xscale:-D__ARM_ARCH_5TE__} \
- %{mcpu=xscale:-D__XSCALE__} \
- %{mcpu=ep9312:-D__ARM_ARCH_4T__} \
- %{mcpu=ep9312:-D__MAVERICK__} \
- %{mcpu=iwmmxt:-D__ARM_ARCH_5TE__} \
- %{mcpu=iwmmxt:-D__XSCALE__} \
- %{mcpu=iwmmxt:-D__IWMMXT__} \
- %{!mcpu*:%(cpp_cpu_arch_default)}} \
-"
-
#ifndef CC1_SPEC
#define CC1_SPEC ""
#endif
@@ -295,8 +156,6 @@ extern GTY(()) rtx aof_pic_label;
Do not define this macro if it does not need to do anything. */
#define EXTRA_SPECS \
- { "cpp_cpu_arch", CPP_CPU_ARCH_SPEC }, \
- { "cpp_cpu_arch_default", CPP_ARCH_DEFAULT_SPEC }, \
{ "subtarget_cpp_spec", SUBTARGET_CPP_SPEC }, \
SUBTARGET_EXTRA_SPECS
@@ -313,271 +172,77 @@ extern GTY(()) rtx aof_pic_label;
#define TARGET_VERSION fputs (" (ARM/generic)", stderr);
#endif
-/* Nonzero if the function prologue (and epilogue) should obey
- the ARM Procedure Call Standard. */
-#define ARM_FLAG_APCS_FRAME (1 << 0)
-
-/* Nonzero if the function prologue should output the function name to enable
- the post mortem debugger to print a backtrace (very useful on RISCOS,
- unused on RISCiX). Specifying this flag also enables
- -fno-omit-frame-pointer.
- XXX Must still be implemented in the prologue. */
-#define ARM_FLAG_POKE (1 << 1)
-
-/* Nonzero if floating point instructions are emulated by the FPE, in which
- case instruction scheduling becomes very uninteresting. */
-#define ARM_FLAG_FPE (1 << 2)
-
-/* Nonzero if destined for a processor in 32-bit program mode. Takes out bit
- that assume restoration of the condition flags when returning from a
- branch and link (ie a function). */
-#define ARM_FLAG_APCS_32 (1 << 3)
-
-/* FLAGS 0x0008 and 0x0010 are now spare (used to be arm3/6 selection). */
-
-/* Nonzero if stack checking should be performed on entry to each function
- which allocates temporary variables on the stack. */
-#define ARM_FLAG_APCS_STACK (1 << 4)
-
-/* Nonzero if floating point parameters should be passed to functions in
- floating point registers. */
-#define ARM_FLAG_APCS_FLOAT (1 << 5)
-
-/* Nonzero if re-entrant, position independent code should be generated.
- This is equivalent to -fpic. */
-#define ARM_FLAG_APCS_REENT (1 << 6)
-
-/* Nonzero if the MMU will trap unaligned word accesses, so shorts must
- be loaded using either LDRH or LDRB instructions. */
-#define ARM_FLAG_MMU_TRAPS (1 << 7)
-
-/* Nonzero if all floating point instructions are missing (and there is no
- emulator either). Generate function calls for all ops in this case. */
-#define ARM_FLAG_SOFT_FLOAT (1 << 8)
-
-/* Nonzero if we should compile with BYTES_BIG_ENDIAN set to 1. */
-#define ARM_FLAG_BIG_END (1 << 9)
-
-/* Nonzero if we should compile for Thumb interworking. */
-#define ARM_FLAG_INTERWORK (1 << 10)
-
-/* Nonzero if we should have little-endian words even when compiling for
- big-endian (for backwards compatibility with older versions of GCC). */
-#define ARM_FLAG_LITTLE_WORDS (1 << 11)
-
-/* Nonzero if we need to protect the prolog from scheduling */
-#define ARM_FLAG_NO_SCHED_PRO (1 << 12)
-
-/* Nonzero if a call to abort should be generated if a noreturn
- function tries to return. */
-#define ARM_FLAG_ABORT_NORETURN (1 << 13)
-
-/* Nonzero if function prologues should not load the PIC register. */
-#define ARM_FLAG_SINGLE_PIC_BASE (1 << 14)
-
-/* Nonzero if all call instructions should be indirect. */
-#define ARM_FLAG_LONG_CALLS (1 << 15)
-
-/* Nonzero means that the target ISA is the THUMB, not the ARM. */
-#define ARM_FLAG_THUMB (1 << 16)
-
-/* Set if a TPCS style stack frame should be generated, for non-leaf
- functions, even if they do not need one. */
-#define THUMB_FLAG_BACKTRACE (1 << 17)
-
-/* Set if a TPCS style stack frame should be generated, for leaf
- functions, even if they do not need one. */
-#define THUMB_FLAG_LEAF_BACKTRACE (1 << 18)
-
-/* Set if externally visible functions should assume that they
- might be called in ARM mode, from a non-thumb aware code. */
-#define THUMB_FLAG_CALLEE_SUPER_INTERWORKING (1 << 19)
-
-/* Set if calls via function pointers should assume that their
- destination is non-Thumb aware. */
-#define THUMB_FLAG_CALLER_SUPER_INTERWORKING (1 << 20)
-
-/* Nonzero means target uses VFP FP. */
-#define ARM_FLAG_VFP (1 << 21)
-
-/* Nonzero means to use ARM/Thumb Procedure Call Standard conventions. */
-#define ARM_FLAG_ATPCS (1 << 22)
-
-/* Fix invalid Cirrus instruction combinations by inserting NOPs. */
-#define CIRRUS_FIX_INVALID_INSNS (1 << 23)
-
-#define TARGET_APCS_FRAME (target_flags & ARM_FLAG_APCS_FRAME)
-#define TARGET_POKE_FUNCTION_NAME (target_flags & ARM_FLAG_POKE)
-#define TARGET_FPE (target_flags & ARM_FLAG_FPE)
-#define TARGET_APCS_32 (target_flags & ARM_FLAG_APCS_32)
-#define TARGET_APCS_STACK (target_flags & ARM_FLAG_APCS_STACK)
-#define TARGET_APCS_FLOAT (target_flags & ARM_FLAG_APCS_FLOAT)
-#define TARGET_APCS_REENT (target_flags & ARM_FLAG_APCS_REENT)
-#define TARGET_ATPCS (target_flags & ARM_FLAG_ATPCS)
-#define TARGET_MMU_TRAPS (target_flags & ARM_FLAG_MMU_TRAPS)
-#define TARGET_SOFT_FLOAT (target_flags & ARM_FLAG_SOFT_FLOAT)
-#define TARGET_HARD_FLOAT (! TARGET_SOFT_FLOAT)
-#define TARGET_CIRRUS (arm_is_cirrus)
-#define TARGET_ANY_HARD_FLOAT (TARGET_HARD_FLOAT || TARGET_CIRRUS)
+#define TARGET_SOFT_FLOAT (arm_float_abi == ARM_FLOAT_ABI_SOFT)
+/* Use hardware floating point instructions. */
+#define TARGET_HARD_FLOAT (arm_float_abi != ARM_FLOAT_ABI_SOFT)
+/* Use hardware floating point calling convention. */
+#define TARGET_HARD_FLOAT_ABI (arm_float_abi == ARM_FLOAT_ABI_HARD)
+#define TARGET_FPA (arm_fp_model == ARM_FP_MODEL_FPA)
+#define TARGET_MAVERICK (arm_fp_model == ARM_FP_MODEL_MAVERICK)
+#define TARGET_VFP (arm_fp_model == ARM_FP_MODEL_VFP)
#define TARGET_IWMMXT (arm_arch_iwmmxt)
#define TARGET_REALLY_IWMMXT (TARGET_IWMMXT && TARGET_ARM)
-#define TARGET_VFP (target_flags & ARM_FLAG_VFP)
-#define TARGET_BIG_END (target_flags & ARM_FLAG_BIG_END)
-#define TARGET_INTERWORK (target_flags & ARM_FLAG_INTERWORK)
-#define TARGET_LITTLE_WORDS (target_flags & ARM_FLAG_LITTLE_WORDS)
-#define TARGET_NO_SCHED_PRO (target_flags & ARM_FLAG_NO_SCHED_PRO)
-#define TARGET_ABORT_NORETURN (target_flags & ARM_FLAG_ABORT_NORETURN)
-#define TARGET_SINGLE_PIC_BASE (target_flags & ARM_FLAG_SINGLE_PIC_BASE)
-#define TARGET_LONG_CALLS (target_flags & ARM_FLAG_LONG_CALLS)
-#define TARGET_THUMB (target_flags & ARM_FLAG_THUMB)
+#define TARGET_IWMMXT_ABI (TARGET_ARM && arm_abi == ARM_ABI_IWMMXT)
#define TARGET_ARM (! TARGET_THUMB)
#define TARGET_EITHER 1 /* (TARGET_ARM | TARGET_THUMB) */
-#define TARGET_CALLEE_INTERWORKING (target_flags & THUMB_FLAG_CALLEE_SUPER_INTERWORKING)
-#define TARGET_CALLER_INTERWORKING (target_flags & THUMB_FLAG_CALLER_SUPER_INTERWORKING)
-#define TARGET_BACKTRACE (leaf_function_p () \
- ? (target_flags & THUMB_FLAG_LEAF_BACKTRACE) \
- : (target_flags & THUMB_FLAG_BACKTRACE))
-#define TARGET_CIRRUS_FIX_INVALID_INSNS (target_flags & CIRRUS_FIX_INVALID_INSNS)
-
-/* SUBTARGET_SWITCHES is used to add flags on a per-config basis. */
-#ifndef SUBTARGET_SWITCHES
-#define SUBTARGET_SWITCHES
+#define TARGET_BACKTRACE (leaf_function_p () \
+ ? TARGET_TPCS_LEAF_FRAME \
+ : TARGET_TPCS_FRAME)
+#define TARGET_LDRD (arm_arch5e && ARM_DOUBLEWORD_ALIGN)
+#define TARGET_AAPCS_BASED \
+ (arm_abi != ARM_ABI_APCS && arm_abi != ARM_ABI_ATPCS)
+
+#define TARGET_HARD_TP (target_thread_pointer == TP_CP15)
+#define TARGET_SOFT_TP (target_thread_pointer == TP_SOFT)
+
+/* True iff the full BPABI is being used. If TARGET_BPABI is true,
+ then TARGET_AAPCS_BASED must be true -- but the converse does not
+ hold. TARGET_BPABI implies the use of the BPABI runtime library,
+ etc., in addition to just the AAPCS calling conventions. */
+#ifndef TARGET_BPABI
+#define TARGET_BPABI false
#endif
-#define TARGET_SWITCHES \
-{ \
- {"apcs", ARM_FLAG_APCS_FRAME, "" }, \
- {"apcs-frame", ARM_FLAG_APCS_FRAME, \
- N_("Generate APCS conformant stack frames") }, \
- {"no-apcs-frame", -ARM_FLAG_APCS_FRAME, "" }, \
- {"poke-function-name", ARM_FLAG_POKE, \
- N_("Store function names in object code") }, \
- {"no-poke-function-name", -ARM_FLAG_POKE, "" }, \
- {"fpe", ARM_FLAG_FPE, "" }, \
- {"apcs-32", ARM_FLAG_APCS_32, \
- N_("Use the 32-bit version of the APCS") }, \
- {"apcs-26", -ARM_FLAG_APCS_32, ""}, \
- {"apcs-stack-check", ARM_FLAG_APCS_STACK, "" }, \
- {"no-apcs-stack-check", -ARM_FLAG_APCS_STACK, "" }, \
- {"apcs-float", ARM_FLAG_APCS_FLOAT, \
- N_("Pass FP arguments in FP registers") }, \
- {"no-apcs-float", -ARM_FLAG_APCS_FLOAT, "" }, \
- {"apcs-reentrant", ARM_FLAG_APCS_REENT, \
- N_("Generate re-entrant, PIC code") }, \
- {"no-apcs-reentrant", -ARM_FLAG_APCS_REENT, "" }, \
- {"alignment-traps", ARM_FLAG_MMU_TRAPS, \
- N_("The MMU will trap on unaligned accesses") }, \
- {"no-alignment-traps", -ARM_FLAG_MMU_TRAPS, "" }, \
- {"soft-float", ARM_FLAG_SOFT_FLOAT, \
- N_("Use library calls to perform FP operations") }, \
- {"hard-float", -ARM_FLAG_SOFT_FLOAT, \
- N_("Use hardware floating point instructions") }, \
- {"big-endian", ARM_FLAG_BIG_END, \
- N_("Assume target CPU is configured as big endian") }, \
- {"little-endian", -ARM_FLAG_BIG_END, \
- N_("Assume target CPU is configured as little endian") }, \
- {"words-little-endian", ARM_FLAG_LITTLE_WORDS, \
- N_("Assume big endian bytes, little endian words") }, \
- {"thumb-interwork", ARM_FLAG_INTERWORK, \
- N_("Support calls between Thumb and ARM instruction sets") }, \
- {"no-thumb-interwork", -ARM_FLAG_INTERWORK, "" }, \
- {"abort-on-noreturn", ARM_FLAG_ABORT_NORETURN, \
- N_("Generate a call to abort if a noreturn function returns")}, \
- {"no-abort-on-noreturn", -ARM_FLAG_ABORT_NORETURN, "" }, \
- {"no-sched-prolog", ARM_FLAG_NO_SCHED_PRO, \
- N_("Do not move instructions into a function's prologue") }, \
- {"sched-prolog", -ARM_FLAG_NO_SCHED_PRO, "" }, \
- {"single-pic-base", ARM_FLAG_SINGLE_PIC_BASE, \
- N_("Do not load the PIC register in function prologues") }, \
- {"no-single-pic-base", -ARM_FLAG_SINGLE_PIC_BASE, "" }, \
- {"long-calls", ARM_FLAG_LONG_CALLS, \
- N_("Generate call insns as indirect calls, if necessary") }, \
- {"no-long-calls", -ARM_FLAG_LONG_CALLS, "" }, \
- {"thumb", ARM_FLAG_THUMB, \
- N_("Compile for the Thumb not the ARM") }, \
- {"no-thumb", -ARM_FLAG_THUMB, "" }, \
- {"arm", -ARM_FLAG_THUMB, "" }, \
- {"tpcs-frame", THUMB_FLAG_BACKTRACE, \
- N_("Thumb: Generate (non-leaf) stack frames even if not needed") }, \
- {"no-tpcs-frame", -THUMB_FLAG_BACKTRACE, "" }, \
- {"tpcs-leaf-frame", THUMB_FLAG_LEAF_BACKTRACE, \
- N_("Thumb: Generate (leaf) stack frames even if not needed") }, \
- {"no-tpcs-leaf-frame", -THUMB_FLAG_LEAF_BACKTRACE, "" }, \
- {"callee-super-interworking", THUMB_FLAG_CALLEE_SUPER_INTERWORKING, \
- N_("Thumb: Assume non-static functions may be called from ARM code") }, \
- {"no-callee-super-interworking", -THUMB_FLAG_CALLEE_SUPER_INTERWORKING, \
- "" }, \
- {"caller-super-interworking", THUMB_FLAG_CALLER_SUPER_INTERWORKING, \
- N_("Thumb: Assume function pointers may go to non-Thumb aware code") }, \
- {"no-caller-super-interworking", -THUMB_FLAG_CALLER_SUPER_INTERWORKING, \
- "" }, \
- {"cirrus-fix-invalid-insns", CIRRUS_FIX_INVALID_INSNS, \
- N_("Cirrus: Place NOPs to avoid invalid instruction combinations") }, \
- {"no-cirrus-fix-invalid-insns", -CIRRUS_FIX_INVALID_INSNS, \
- N_("Cirrus: Do not break up invalid instruction combinations with NOPs") },\
- SUBTARGET_SWITCHES \
- {"", TARGET_DEFAULT, "" } \
-}
-
-#define TARGET_OPTIONS \
-{ \
- {"cpu=", & arm_select[0].string, \
- N_("Specify the name of the target CPU"), 0}, \
- {"arch=", & arm_select[1].string, \
- N_("Specify the name of the target architecture"), 0}, \
- {"tune=", & arm_select[2].string, "", 0}, \
- {"fpe=", & target_fp_name, "" , 0}, \
- {"fp=", & target_fp_name, \
- N_("Specify the version of the floating point emulator"), 0},\
- {"structure-size-boundary=", & structure_size_string, \
- N_("Specify the minimum bit alignment of structures"), 0}, \
- {"pic-register=", & arm_pic_register_string, \
- N_("Specify the register to be used for PIC addressing"), 0} \
-}
-
/* Support for a compile-time default CPU, et cetera. The rules are:
--with-arch is ignored if -march or -mcpu are specified.
--with-cpu is ignored if -march or -mcpu are specified, and is overridden
by --with-arch.
--with-tune is ignored if -mtune or -mcpu are specified (but not affected
by -march).
- --with-float is ignored if -mhard-float or -msoft-float are
- specified. */
+ --with-float is ignored if -mhard-float, -msoft-float or -mfloat-abi are
+ specified.
+ --with-fpu is ignored if -mfpu is specified.
+ --with-abi is ignored is -mabi is specified. */
#define OPTION_DEFAULT_SPECS \
{"arch", "%{!march=*:%{!mcpu=*:-march=%(VALUE)}}" }, \
{"cpu", "%{!march=*:%{!mcpu=*:-mcpu=%(VALUE)}}" }, \
{"tune", "%{!mcpu=*:%{!mtune=*:-mtune=%(VALUE)}}" }, \
- {"float", "%{!msoft-float:%{!mhard-float:-m%(VALUE)-float}}" }
-
-struct arm_cpu_select
-{
- const char * string;
- const char * name;
- const struct processors * processors;
-};
-
-/* This is a magic array. If the user specifies a command line switch
- which matches one of the entries in TARGET_OPTIONS then the corresponding
- string pointer will be set to the value specified by the user. */
-extern struct arm_cpu_select arm_select[];
-
-enum prog_mode_type
+ {"float", \
+ "%{!msoft-float:%{!mhard-float:%{!mfloat-abi=*:-mfloat-abi=%(VALUE)}}}" }, \
+ {"fpu", "%{!mfpu=*:-mfpu=%(VALUE)}"}, \
+ {"abi", "%{!mabi=*:-mabi=%(VALUE)}"}, \
+ {"mode", "%{!marm:%{!mthumb:-m%(VALUE)}}"},
+
+/* Which floating point model to use. */
+enum arm_fp_model
{
- prog_mode26,
- prog_mode32
+ ARM_FP_MODEL_UNKNOWN,
+ /* FPA model (Hardware or software). */
+ ARM_FP_MODEL_FPA,
+ /* Cirrus Maverick floating point model. */
+ ARM_FP_MODEL_MAVERICK,
+ /* VFP floating point model. */
+ ARM_FP_MODEL_VFP
};
-/* Recast the program mode class to be the prog_mode attribute. */
-#define arm_prog_mode ((enum attr_prog_mode) arm_prgmode)
+extern enum arm_fp_model arm_fp_model;
-extern enum prog_mode_type arm_prgmode;
-
-/* What sort of floating point unit do we have? Hardware or software.
- If software, is it issue 2 or issue 3? */
+/* Which floating point hardware is available. Also update
+ fp_model_for_fpu in arm.c when adding entries to this list. */
enum fputype
{
- /* Software floating point, FPA style double fmt. */
- FPUTYPE_SOFT_FPA,
+ /* No FP hardware. */
+ FPUTYPE_NONE,
/* Full FPA support. */
FPUTYPE_FPA,
/* Emulated FPA hardware, Issue 2 emulator (no LFM/SFM). */
@@ -585,7 +250,9 @@ enum fputype
/* Emulated FPA hardware, Issue 3 emulator. */
FPUTYPE_FPA_EMU3,
/* Cirrus Maverick floating point co-processor. */
- FPUTYPE_MAVERICK
+ FPUTYPE_MAVERICK,
+ /* VFP. */
+ FPUTYPE_VFP
};
/* Recast the floating point class to be the floating point attribute. */
@@ -597,30 +264,62 @@ extern enum fputype arm_fpu_tune;
/* What type of floating point instructions are available */
extern enum fputype arm_fpu_arch;
-/* Default floating point architecture. Override in sub-target if
- necessary. */
-#ifndef FPUTYPE_DEFAULT
-#define FPUTYPE_DEFAULT FPUTYPE_FPA_EMU2
+enum float_abi_type
+{
+ ARM_FLOAT_ABI_SOFT,
+ ARM_FLOAT_ABI_SOFTFP,
+ ARM_FLOAT_ABI_HARD
+};
+
+extern enum float_abi_type arm_float_abi;
+
+#ifndef TARGET_DEFAULT_FLOAT_ABI
+#define TARGET_DEFAULT_FLOAT_ABI ARM_FLOAT_ABI_SOFT
#endif
-#if TARGET_CPU_DEFAULT == TARGET_CPU_ep9312
-#undef FPUTYPE_DEFAULT
-#define FPUTYPE_DEFAULT FPUTYPE_MAVERICK
+/* Which ABI to use. */
+enum arm_abi_type
+{
+ ARM_ABI_APCS,
+ ARM_ABI_ATPCS,
+ ARM_ABI_AAPCS,
+ ARM_ABI_IWMMXT,
+ ARM_ABI_AAPCS_LINUX
+};
+
+extern enum arm_abi_type arm_abi;
+
+#ifndef ARM_DEFAULT_ABI
+#define ARM_DEFAULT_ABI ARM_ABI_APCS
#endif
-/* Nonzero if the processor has a fast multiply insn, and one that does
- a 64-bit multiply of two 32-bit values. */
-extern int arm_fast_multiply;
+/* Which thread pointer access sequence to use. */
+enum arm_tp_type {
+ TP_AUTO,
+ TP_SOFT,
+ TP_CP15
+};
-/* Nonzero if this chip supports the ARM Architecture 4 extensions */
+extern enum arm_tp_type target_thread_pointer;
+
+/* Nonzero if this chip supports the ARM Architecture 3M extensions. */
+extern int arm_arch3m;
+
+/* Nonzero if this chip supports the ARM Architecture 4 extensions. */
extern int arm_arch4;
-/* Nonzero if this chip supports the ARM Architecture 5 extensions */
+/* Nonzero if this chip supports the ARM Architecture 4T extensions. */
+extern int arm_arch4t;
+
+/* Nonzero if this chip supports the ARM Architecture 5 extensions. */
extern int arm_arch5;
-/* Nonzero if this chip supports the ARM Architecture 5E extensions */
+/* Nonzero if this chip supports the ARM Architecture 5E extensions. */
extern int arm_arch5e;
+/* Nonzero if this chip supports the ARM Architecture 6 extensions. */
+extern int arm_arch6;
+
/* Nonzero if this chip can benefit from load scheduling. */
extern int arm_ld_sched;
@@ -628,10 +327,10 @@ extern int arm_ld_sched;
extern int thumb_code;
/* Nonzero if this chip is a StrongARM. */
-extern int arm_is_strong;
+extern int arm_tune_strongarm;
/* Nonzero if this chip is a Cirrus variant. */
-extern int arm_is_cirrus;
+extern int arm_arch_cirrus;
/* Nonzero if this chip supports Intel XScale with Wireless MMX technology. */
extern int arm_arch_iwmmxt;
@@ -639,23 +338,27 @@ extern int arm_arch_iwmmxt;
/* Nonzero if this chip is an XScale. */
extern int arm_arch_xscale;
-/* Nonzero if tuning for XScale */
+/* Nonzero if tuning for XScale. */
extern int arm_tune_xscale;
-/* Nonzero if this chip is an ARM6 or an ARM7. */
-extern int arm_is_6_or_7;
+/* Nonzero if tuning for stores via the write buffer. */
+extern int arm_tune_wbuf;
+
+/* Nonzero if we should define __THUMB_INTERWORK__ in the
+ preprocessor.
+ XXX This is a bit of a hack, it's intended to help work around
+ problems in GLD which doesn't understand that armv5t code is
+ interworking clean. */
+extern int arm_cpp_interwork;
#ifndef TARGET_DEFAULT
-#define TARGET_DEFAULT (ARM_FLAG_APCS_FRAME | ARM_FLAG_MMU_TRAPS)
+#define TARGET_DEFAULT (MASK_APCS_FRAME)
#endif
/* The frame pointer register used in gcc has nothing to do with debugging;
that is controlled by the APCS-FRAME option. */
#define CAN_DEBUG_WITHOUT_FP
-#undef TARGET_MEM_FUNCTIONS
-#define TARGET_MEM_FUNCTIONS 1
-
#define OVERRIDE_OPTIONS arm_override_options ()
/* Nonzero if PIC code requires explicit qualifiers to generate
@@ -671,13 +374,13 @@ extern int arm_is_6_or_7;
/* Nonzero if we need to refer to the GOT with a PC-relative
offset. In other words, generate
- .word _GLOBAL_OFFSET_TABLE_ - [. - (.Lxx + 8)]
+ .word _GLOBAL_OFFSET_TABLE_ - [. - (.Lxx + 8)]
rather than
.word _GLOBAL_OFFSET_TABLE_ - (.Lxx + 8)
- The default is true, which matches NetBSD. Subtargets can
+ The default is true, which matches NetBSD. Subtargets can
override this if required. */
#ifndef GOT_PCREL
#define GOT_PCREL 1
@@ -701,20 +404,21 @@ extern int arm_is_6_or_7;
if (MODE == QImode) \
UNSIGNEDP = 1; \
else if (MODE == HImode) \
- UNSIGNEDP = TARGET_MMU_TRAPS != 0; \
+ UNSIGNEDP = 1; \
(MODE) = SImode; \
}
-/* Define this macro if the promotion described by `PROMOTE_MODE'
- should also be done for outgoing function arguments. */
-/* This is required to ensure that push insns always push a word. */
-#define PROMOTE_FUNCTION_ARGS
+#define PROMOTE_FUNCTION_MODE(MODE, UNSIGNEDP, TYPE) \
+ if ((GET_MODE_CLASS (MODE) == MODE_INT \
+ || GET_MODE_CLASS (MODE) == MODE_COMPLEX_INT) \
+ && GET_MODE_SIZE (MODE) < 4) \
+ (MODE) = SImode; \
/* Define this if most significant bit is lowest numbered
in instructions that operate on numbered bit-fields. */
#define BITS_BIG_ENDIAN 0
-/* Define this if most significant byte of a word is the lowest numbered.
+/* Define this if most significant byte of a word is the lowest numbered.
Most ARM processors are run in little endian mode, so that is the default.
If you want to have it run-time selectable, change the definition in a
cover file to be TARGET_BIG_ENDIAN. */
@@ -740,13 +444,17 @@ extern int arm_is_6_or_7;
#define UNITS_PER_WORD 4
-#define PARM_BOUNDARY 32
+/* True if natural alignment is used for doubleword types. */
+#define ARM_DOUBLEWORD_ALIGN TARGET_AAPCS_BASED
-#define IWMMXT_ALIGNMENT 64
+#define DOUBLEWORD_ALIGNMENT 64
-#define STACK_BOUNDARY 32
+#define PARM_BOUNDARY 32
-#define PREFERRED_STACK_BOUNDARY (TARGET_ATPCS ? 64 : 32)
+#define STACK_BOUNDARY (ARM_DOUBLEWORD_ALIGN ? DOUBLEWORD_ALIGNMENT : 32)
+
+#define PREFERRED_STACK_BOUNDARY \
+ (arm_abi == ARM_ABI_ATPCS ? 64 : STACK_BOUNDARY)
#define FUNCTION_BOUNDARY 32
@@ -757,62 +465,30 @@ extern int arm_is_6_or_7;
#define EMPTY_FIELD_BOUNDARY 32
-#define BIGGEST_ALIGNMENT (TARGET_REALLY_IWMMXT ? 64 : 32)
-
-#define TYPE_NEEDS_IWMMXT_ALIGNMENT(TYPE) \
- (TARGET_REALLY_IWMMXT \
- && ((TREE_CODE (TYPE) == VECTOR_TYPE) || (TYPE_MODE (TYPE) == DImode) || (TYPE_MODE (TYPE) == DFmode)))
+#define BIGGEST_ALIGNMENT (ARM_DOUBLEWORD_ALIGN ? DOUBLEWORD_ALIGNMENT : 32)
/* XXX Blah -- this macro is used directly by libobjc. Since it
supports no vector modes, cut out the complexity and fall back
on BIGGEST_FIELD_ALIGNMENT. */
#ifdef IN_TARGET_LIBS
#define BIGGEST_FIELD_ALIGNMENT 64
-#else
-/* An expression for the alignment of a structure field FIELD if the
- alignment computed in the usual way is COMPUTED. GCC uses this
- value instead of the value in `BIGGEST_ALIGNMENT' or
- `BIGGEST_FIELD_ALIGNMENT', if defined, for structure fields only. */
-#define ADJUST_FIELD_ALIGN(FIELD, COMPUTED) \
- (TYPE_NEEDS_IWMMXT_ALIGNMENT (TREE_TYPE (FIELD)) \
- ? IWMMXT_ALIGNMENT \
- : (COMPUTED))
#endif
-/* If defined, a C expression to compute the alignment for a static variable.
- TYPE is the data type, and ALIGN is the alignment that the object
- would ordinarily have. The value of this macro is used instead of that
- alignment to align the object.
-
- If this macro is not defined, then ALIGN is used. */
-#define DATA_ALIGNMENT(TYPE, ALIGN) \
- (TYPE_NEEDS_IWMMXT_ALIGNMENT (TYPE) ? IWMMXT_ALIGNMENT : ALIGN)
-
-/* If defined, a C expression to compute the alignment for a
- variables in the local store. TYPE is the data type, and
- BASIC-ALIGN is the alignment that the object would ordinarily
- have. The value of this macro is used instead of that alignment
- to align the object.
-
- If this macro is not defined, then BASIC-ALIGN is used. */
-#define LOCAL_ALIGNMENT(TYPE, ALIGN) \
- (TYPE_NEEDS_IWMMXT_ALIGNMENT (TYPE) ? IWMMXT_ALIGNMENT : ALIGN)
-
/* Make strings word-aligned so strcpy from constants will be faster. */
#define CONSTANT_ALIGNMENT_FACTOR (TARGET_THUMB || ! arm_tune_xscale ? 1 : 2)
-
+
#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- ((TARGET_REALLY_IWMMXT && TREE_CODE (EXP) == VECTOR_TYPE) ? IWMMXT_ALIGNMENT : \
- (TREE_CODE (EXP) == STRING_CST \
- && (ALIGN) < BITS_PER_WORD * CONSTANT_ALIGNMENT_FACTOR) \
- ? BITS_PER_WORD * CONSTANT_ALIGNMENT_FACTOR : (ALIGN))
+ ((TREE_CODE (EXP) == STRING_CST \
+ && (ALIGN) < BITS_PER_WORD * CONSTANT_ALIGNMENT_FACTOR) \
+ ? BITS_PER_WORD * CONSTANT_ALIGNMENT_FACTOR : (ALIGN))
/* Setting STRUCTURE_SIZE_BOUNDARY to 32 produces more efficient code, but the
value set in previous versions of this toolchain was 8, which produces more
compact structures. The command line option -mstructure_size_boundary=<n>
can be used to change this value. For compatibility with the ARM SDK
however the value should be left at 32. ARM SDT Reference Manual (ARM DUI
- 0020D) page 2-20 says "Structures are aligned on word boundaries". */
+ 0020D) page 2-20 says "Structures are aligned on word boundaries".
+ The AAPCS specifies a value of 8. */
#define STRUCTURE_SIZE_BOUNDARY arm_structure_size_boundary
extern int arm_structure_size_boundary;
@@ -824,12 +500,30 @@ extern int arm_structure_size_boundary;
#define DEFAULT_STRUCTURE_SIZE_BOUNDARY 32
#endif
-/* Used when parsing command line option -mstructure_size_boundary. */
-extern const char * structure_size_string;
-
/* Nonzero if move instructions will actually fail to work
when given unaligned data. */
#define STRICT_ALIGNMENT 1
+
+/* wchar_t is unsigned under the AAPCS. */
+#ifndef WCHAR_TYPE
+#define WCHAR_TYPE (TARGET_AAPCS_BASED ? "unsigned int" : "int")
+
+#define WCHAR_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef SIZE_TYPE
+#define SIZE_TYPE (TARGET_AAPCS_BASED ? "unsigned int" : "long unsigned int")
+#endif
+
+#ifndef PTRDIFF_TYPE
+#define PTRDIFF_TYPE (TARGET_AAPCS_BASED ? "int" : "long int")
+#endif
+
+/* AAPCS requires that structure alignment is affected by bitfields. */
+#ifndef PCC_BITFIELD_TYPE_MATTERS
+#define PCC_BITFIELD_TYPE_MATTERS TARGET_AAPCS_BASED
+#endif
+
/* Standard register usage. */
@@ -841,7 +535,7 @@ extern const char * structure_size_string;
r4-r8 S register variable
r9 S (rfp) register variable (real frame pointer)
-
+
r10 F S (sl) stack limit (used by -mapcs-stack-check)
r11 F S (fp) argument pointer
r12 (ip) temp workspace
@@ -872,6 +566,11 @@ extern const char * structure_size_string;
mvf1-mvf3 Cirrus floating point scratch
mvf4-mvf15 S Cirrus floating point variable. */
+/* s0-s15 VFP scratch (aka d0-d7).
+ s16-s31 S VFP variable (aka d8-d15).
+ vfpcc Not a real register. Represents the VFP condition
+ code flags. */
+
/* The stack backtrace structure is as follows:
fp points to here: | save code pointer | [fp]
| return link value | [fp, #-4]
@@ -896,17 +595,22 @@ extern const char * structure_size_string;
/* 1 for registers that have pervasive standard uses
and are not available for the register allocator. */
-#define FIXED_REGISTERS \
-{ \
- 0,0,0,0,0,0,0,0, \
- 0,0,0,0,0,1,0,1, \
- 0,0,0,0,0,0,0,0, \
+#define FIXED_REGISTERS \
+{ \
+ 0,0,0,0,0,0,0,0, \
+ 0,0,0,0,0,1,0,1, \
+ 0,0,0,0,0,0,0,0, \
1,1,1, \
1,1,1,1,1,1,1,1, \
- 1,1,1,1,1,1,1,1, \
- 1,1,1,1,1,1,1,1, \
- 1,1,1,1,1,1,1,1, \
- 1,1,1,1 \
+ 1,1,1,1,1,1,1,1, \
+ 1,1,1,1,1,1,1,1, \
+ 1,1,1,1,1,1,1,1, \
+ 1,1,1,1, \
+ 1,1,1,1,1,1,1,1, \
+ 1,1,1,1,1,1,1,1, \
+ 1,1,1,1,1,1,1,1, \
+ 1,1,1,1,1,1,1,1, \
+ 1 \
}
/* 1 for registers not available across function calls.
@@ -915,7 +619,7 @@ extern const char * structure_size_string;
The latter must include the registers where values are returned
and the register where structure-value addresses are passed.
Aside from that, you can include as many other registers as you like.
- The CC is not preserved over function calls on the ARM 6, so it is
+ The CC is not preserved over function calls on the ARM 6, so it is
easier to assume this for all. SFP is preserved, since FP is. */
#define CALL_USED_REGISTERS \
{ \
@@ -927,7 +631,12 @@ extern const char * structure_size_string;
1,1,1,1,1,1,1,1, \
1,1,1,1,1,1,1,1, \
1,1,1,1,1,1,1,1, \
- 1,1,1,1 \
+ 1,1,1,1, \
+ 1,1,1,1,1,1,1,1, \
+ 1,1,1,1,1,1,1,1, \
+ 1,1,1,1,1,1,1,1, \
+ 1,1,1,1,1,1,1,1, \
+ 1 \
}
#ifndef SUBTARGET_CONDITIONAL_REGISTER_USAGE
@@ -938,10 +647,10 @@ extern const char * structure_size_string;
{ \
int regno; \
\
- if (TARGET_SOFT_FLOAT || TARGET_THUMB) \
+ if (TARGET_SOFT_FLOAT || TARGET_THUMB || !TARGET_FPA) \
{ \
- for (regno = FIRST_ARM_FP_REGNUM; \
- regno <= LAST_ARM_FP_REGNUM; ++regno) \
+ for (regno = FIRST_FPA_REGNUM; \
+ regno <= LAST_FPA_REGNUM; ++regno) \
fixed_regs[regno] = call_used_regs[regno] = 1; \
} \
\
@@ -961,16 +670,28 @@ extern const char * structure_size_string;
if (TARGET_THUMB) \
fixed_regs[LR_REGNUM] = call_used_regs[LR_REGNUM] = 1; \
\
- if (TARGET_CIRRUS) \
+ if (TARGET_ARM && TARGET_HARD_FLOAT) \
{ \
- for (regno = FIRST_ARM_FP_REGNUM; \
- regno <= LAST_ARM_FP_REGNUM; ++ regno) \
- fixed_regs[regno] = call_used_regs[regno] = 1; \
- for (regno = FIRST_CIRRUS_FP_REGNUM; \
- regno <= LAST_CIRRUS_FP_REGNUM; ++ regno) \
+ if (TARGET_MAVERICK) \
{ \
- fixed_regs[regno] = 0; \
- call_used_regs[regno] = regno < FIRST_CIRRUS_FP_REGNUM + 4; \
+ for (regno = FIRST_FPA_REGNUM; \
+ regno <= LAST_FPA_REGNUM; ++ regno) \
+ fixed_regs[regno] = call_used_regs[regno] = 1; \
+ for (regno = FIRST_CIRRUS_FP_REGNUM; \
+ regno <= LAST_CIRRUS_FP_REGNUM; ++ regno) \
+ { \
+ fixed_regs[regno] = 0; \
+ call_used_regs[regno] = regno < FIRST_CIRRUS_FP_REGNUM + 4; \
+ } \
+ } \
+ if (TARGET_VFP) \
+ { \
+ for (regno = FIRST_VFP_REGNUM; \
+ regno <= LAST_VFP_REGNUM; ++ regno) \
+ { \
+ fixed_regs[regno] = 0; \
+ call_used_regs[regno] = regno < FIRST_VFP_REGNUM + 16; \
+ } \
} \
} \
\
@@ -983,7 +704,7 @@ extern const char * structure_size_string;
scratch registers. */ \
for (regno = FIRST_IWMMXT_GR_REGNUM; \
regno <= LAST_IWMMXT_GR_REGNUM; ++ regno) \
- fixed_regs[regno] = call_used_regs[regno] = 0; \
+ fixed_regs[regno] = 0; \
/* The XScale ABI has wR0 - wR9 as scratch registers, \
the rest as call-preserved registers. */ \
for (regno = FIRST_IWMMXT_REGNUM; \
@@ -1004,14 +725,21 @@ extern const char * structure_size_string;
fixed_regs[10] = 1; \
call_used_regs[10] = 1; \
} \
- if (TARGET_APCS_FRAME) \
+ /* -mcaller-super-interworking reserves r11 for calls to \
+ _interwork_r11_call_via_rN(). Making the register global \
+ is an easy way of ensuring that it remains valid for all \
+ calls. */ \
+ if (TARGET_APCS_FRAME || TARGET_CALLER_INTERWORKING \
+ || TARGET_TPCS_FRAME || TARGET_TPCS_LEAF_FRAME) \
{ \
fixed_regs[ARM_HARD_FRAME_POINTER_REGNUM] = 1; \
call_used_regs[ARM_HARD_FRAME_POINTER_REGNUM] = 1; \
+ if (TARGET_CALLER_INTERWORKING) \
+ global_regs[ARM_HARD_FRAME_POINTER_REGNUM] = 1; \
} \
SUBTARGET_CONDITIONAL_REGISTER_USAGE \
}
-
+
/* These are a couple of extensions to the formats accepted
by asm_fprintf:
%@ prints out ASM_COMMENT_START
@@ -1032,7 +760,8 @@ extern const char * structure_size_string;
/* Convert fron bytes to ints. */
#define ARM_NUM_INTS(X) (((X) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
-/* The number of (integer) registers required to hold a quantity of type MODE. */
+/* The number of (integer) registers required to hold a quantity of type MODE.
+ Also used for VFP registers. */
#define ARM_NUM_REGS(MODE) \
ARM_NUM_INTS (GET_MODE_SIZE (MODE))
@@ -1047,20 +776,6 @@ extern const char * structure_size_string;
/* Return the register number of the N'th (integer) argument. */
#define ARG_REGISTER(N) (N - 1)
-#if 0 /* FIXME: The ARM backend has special code to handle structure
- returns, and will reserve its own hidden first argument. So
- if this macro is enabled a *second* hidden argument will be
- reserved, which will break binary compatibility with old
- toolchains and also thunk handling. One day this should be
- fixed. */
-/* RTX for structure returns. NULL means use a hidden first argument. */
-#define STRUCT_VALUE 0
-#else
-/* Register in which address to store a structure value
- is passed to a function. */
-#define STRUCT_VALUE_REGNUM ARG_REGISTER (1)
-#endif
-
/* Specify the registers used for certain standard purposes.
The values of these macros are register numbers. */
@@ -1073,8 +788,20 @@ extern const char * structure_size_string;
#define FIRST_HI_REGNUM 8
#define LAST_HI_REGNUM 11
+#ifndef TARGET_UNWIND_INFO
+/* We use sjlj exceptions for backwards compatibility. */
+#define MUST_USE_SJLJ_EXCEPTIONS 1
+#endif
+
+/* We can generate DWARF2 Unwind info, even though we don't use it. */
+#define DWARF2_UNWIND_INFO 1
+
+/* Use r0 and r1 to pass exception handling information. */
+#define EH_RETURN_DATA_REGNO(N) (((N) < 2) ? N : INVALID_REGNUM)
+
/* The register that holds the return address in exception handlers. */
-#define EXCEPTION_LR_REGNUM 2
+#define ARM_EH_STACKADJ_REGNUM 2
+#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (SImode, ARM_EH_STACKADJ_REGNUM)
/* The native (Norcroft) Pascal compiler for the ARM passes the static chain
as an invisible last argument (possible since varargs don't exist in
@@ -1111,8 +838,10 @@ extern const char * structure_size_string;
#define STACK_POINTER_REGNUM SP_REGNUM
/* ARM floating pointer registers. */
-#define FIRST_ARM_FP_REGNUM 16
-#define LAST_ARM_FP_REGNUM 23
+#define FIRST_FPA_REGNUM 16
+#define LAST_FPA_REGNUM 23
+#define IS_FPA_REGNUM(REGNUM) \
+ (((REGNUM) >= FIRST_FPA_REGNUM) && ((REGNUM) <= LAST_FPA_REGNUM))
#define FIRST_IWMMXT_GR_REGNUM 43
#define LAST_IWMMXT_GR_REGNUM 46
@@ -1134,19 +863,33 @@ extern const char * structure_size_string;
#define IS_CIRRUS_REGNUM(REGNUM) \
(((REGNUM) >= FIRST_CIRRUS_FP_REGNUM) && ((REGNUM) <= LAST_CIRRUS_FP_REGNUM))
+#define FIRST_VFP_REGNUM 63
+#define LAST_VFP_REGNUM 94
+#define IS_VFP_REGNUM(REGNUM) \
+ (((REGNUM) >= FIRST_VFP_REGNUM) && ((REGNUM) <= LAST_VFP_REGNUM))
+
/* The number of hard registers is 16 ARM + 8 FPA + 1 CC + 1 SFP + 1 AFP. */
/* + 16 Cirrus registers take us up to 43. */
/* Intel Wireless MMX Technology registers add 16 + 4 more. */
-#define FIRST_PSEUDO_REGISTER 63
+/* VFP adds 32 + 1 more. */
+#define FIRST_PSEUDO_REGISTER 96
+
+#define DBX_REGISTER_NUMBER(REGNO) arm_dbx_register_number (REGNO)
/* Value should be nonzero if functions must have frame pointers.
Zero means the frame pointer need not be set up (and parms may be accessed
- via the stack pointer) in functions that seem suitable.
+ via the stack pointer) in functions that seem suitable.
If we have to have a frame pointer we might as well make use of it.
APCS says that the frame pointer does not need to be pushed in leaf
functions, or simple tail call functions. */
+
+#ifndef SUBTARGET_FRAME_POINTER_REQUIRED
+#define SUBTARGET_FRAME_POINTER_REQUIRED 0
+#endif
+
#define FRAME_POINTER_REQUIRED \
(current_function_has_nonlocal_label \
+ || SUBTARGET_FRAME_POINTER_REQUIRED \
|| (TARGET_ARM && TARGET_APCS_FRAME && ! leaf_function_p ()))
/* Return number of consecutive hard regs needed starting at reg REGNO
@@ -1158,9 +901,10 @@ extern const char * structure_size_string;
mode. */
#define HARD_REGNO_NREGS(REGNO, MODE) \
((TARGET_ARM \
- && REGNO >= FIRST_ARM_FP_REGNUM \
+ && REGNO >= FIRST_FPA_REGNUM \
&& REGNO != FRAME_POINTER_REGNUM \
&& REGNO != ARG_POINTER_REGNUM) \
+ && !IS_VFP_REGNUM (REGNO) \
? 1 : ARM_NUM_REGS (MODE))
/* Return true if REGNO is suitable for holding a quantity of type MODE. */
@@ -1174,18 +918,16 @@ extern const char * structure_size_string;
#define MODES_TIEABLE_P(MODE1, MODE2) \
(GET_MODE_CLASS (MODE1) == GET_MODE_CLASS (MODE2))
-#define VECTOR_MODE_SUPPORTED_P(MODE) \
- ((MODE) == V2SImode || (MODE) == V4HImode || (MODE) == V8QImode)
-
#define VALID_IWMMXT_REG_MODE(MODE) \
- (VECTOR_MODE_SUPPORTED_P (MODE) || (MODE) == DImode)
+ (arm_vector_mode_supported_p (MODE) || (MODE) == DImode)
/* The order in which register should be allocated. It is good to use ip
since no saving is required (though calls clobber it) and it never contains
function parameters. It is quite good to use lr since other calls may
- clobber it anyway. Allocate r0 through r3 in reverse order since r3 is
+ clobber it anyway. Allocate r0 through r3 in reverse order since r3 is
least likely to contain a function parameter; in addition results are
returned in r0. */
+
#define REG_ALLOC_ORDER \
{ \
3, 2, 1, 0, 12, 14, 4, 5, \
@@ -1196,7 +938,12 @@ extern const char * structure_size_string;
43, 44, 45, 46, 47, 48, 49, 50, \
51, 52, 53, 54, 55, 56, 57, 58, \
59, 60, 61, 62, \
- 24, 25, 26 \
+ 24, 25, 26, \
+ 78, 77, 76, 75, 74, 73, 72, 71, \
+ 70, 69, 68, 67, 66, 65, 64, 63, \
+ 79, 80, 81, 82, 83, 84, 85, 86, \
+ 87, 88, 89, 90, 91, 92, 93, 94, \
+ 95 \
}
/* Interrupt functions can only use registers that have already been
@@ -1215,6 +962,7 @@ enum reg_class
NO_REGS,
FPA_REGS,
CIRRUS_REGS,
+ VFP_REGS,
IWMMXT_GR_REGS,
IWMMXT_REGS,
LO_REGS,
@@ -1222,6 +970,7 @@ enum reg_class
BASE_REGS,
HI_REGS,
CC_REG,
+ VFPCC_REG,
GENERAL_REGS,
ALL_REGS,
LIM_REG_CLASSES
@@ -1235,6 +984,7 @@ enum reg_class
"NO_REGS", \
"FPA_REGS", \
"CIRRUS_REGS", \
+ "VFP_REGS", \
"IWMMXT_GR_REGS", \
"IWMMXT_REGS", \
"LO_REGS", \
@@ -1242,6 +992,7 @@ enum reg_class
"BASE_REGS", \
"HI_REGS", \
"CC_REG", \
+ "VFPCC_REG", \
"GENERAL_REGS", \
"ALL_REGS", \
}
@@ -1249,20 +1000,22 @@ enum reg_class
/* Define which registers fit in which classes.
This is an initializer for a vector of HARD_REG_SET
of length N_REG_CLASSES. */
-#define REG_CLASS_CONTENTS \
-{ \
- { 0x00000000, 0x0 }, /* NO_REGS */ \
- { 0x00FF0000, 0x0 }, /* FPA_REGS */ \
- { 0xF8000000, 0x000007FF }, /* CIRRUS_REGS */ \
- { 0x00000000, 0x00007800 }, /* IWMMXT_GR_REGS */\
- { 0x00000000, 0x7FFF8000 }, /* IWMMXT_REGS */ \
- { 0x000000FF, 0x0 }, /* LO_REGS */ \
- { 0x00002000, 0x0 }, /* STACK_REG */ \
- { 0x000020FF, 0x0 }, /* BASE_REGS */ \
- { 0x0000FF00, 0x0 }, /* HI_REGS */ \
- { 0x01000000, 0x0 }, /* CC_REG */ \
- { 0x0200FFFF, 0x0 }, /* GENERAL_REGS */\
- { 0xFAFFFFFF, 0x7FFFFFFF } /* ALL_REGS */ \
+#define REG_CLASS_CONTENTS \
+{ \
+ { 0x00000000, 0x00000000, 0x00000000 }, /* NO_REGS */ \
+ { 0x00FF0000, 0x00000000, 0x00000000 }, /* FPA_REGS */ \
+ { 0xF8000000, 0x000007FF, 0x00000000 }, /* CIRRUS_REGS */ \
+ { 0x00000000, 0x80000000, 0x7FFFFFFF }, /* VFP_REGS */ \
+ { 0x00000000, 0x00007800, 0x00000000 }, /* IWMMXT_GR_REGS */ \
+ { 0x00000000, 0x7FFF8000, 0x00000000 }, /* IWMMXT_REGS */ \
+ { 0x000000FF, 0x00000000, 0x00000000 }, /* LO_REGS */ \
+ { 0x00002000, 0x00000000, 0x00000000 }, /* STACK_REG */ \
+ { 0x000020FF, 0x00000000, 0x00000000 }, /* BASE_REGS */ \
+ { 0x0000FF00, 0x00000000, 0x00000000 }, /* HI_REGS */ \
+ { 0x01000000, 0x00000000, 0x00000000 }, /* CC_REG */ \
+ { 0x00000000, 0x00000000, 0x80000000 }, /* VFPCC_REG */ \
+ { 0x0200FFFF, 0x00000000, 0x00000000 }, /* GENERAL_REGS */ \
+ { 0xFAFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF } /* ALL_REGS */ \
}
/* The same information, inverted:
@@ -1271,11 +1024,21 @@ enum reg_class
or could index an array. */
#define REGNO_REG_CLASS(REGNO) arm_regno_class (REGNO)
-/* FPA registers can't do dubreg as all values are reformatted to internal
- precision. */
+/* FPA registers can't do subreg as all values are reformatted to internal
+ precision. VFP registers may only be accessed in the mode they
+ were set. */
#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
(GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \
- ? reg_classes_intersect_p (FPA_REGS, (CLASS)) : 0)
+ ? reg_classes_intersect_p (FPA_REGS, (CLASS)) \
+ || reg_classes_intersect_p (VFP_REGS, (CLASS)) \
+ : 0)
+
+/* We need to define this for LO_REGS on thumb. Otherwise we can end up
+ using r0-r4 for function arguments, r7 for the stack frame and don't
+ have enough left over to do doubleword arithmetic. */
+#define CLASS_LIKELY_SPILLED_P(CLASS) \
+ ((TARGET_THUMB && (CLASS) == LO_REGS) \
+ || (CLASS) == CC_REG)
/* The class value for index registers, and the one for base regs. */
#define INDEX_REG_CLASS (TARGET_THUMB ? LO_REGS : GENERAL_REGS)
@@ -1283,12 +1046,14 @@ enum reg_class
/* For the Thumb the high registers cannot be used as base registers
when addressing quantities in QI or HI mode; if we don't know the
- mode, then we must be conservative. After reload we must also be
- conservative, since we can't support SP+reg addressing, and we
- can't fix up any bad substitutions. */
+ mode, then we must be conservative. */
#define MODE_BASE_REG_CLASS(MODE) \
(TARGET_ARM ? GENERAL_REGS : \
- (((MODE) == SImode && !reload_completed) ? BASE_REGS : LO_REGS))
+ (((MODE) == SImode) ? BASE_REGS : LO_REGS))
+
+/* For Thumb we can not support SP+reg addressing, so we return LO_REGS
+ instead of BASE_REGS. */
+#define MODE_BASE_REG_REG_CLASS(MODE) BASE_REG_CLASS
/* When SMALL_REGISTER_CLASSES is nonzero, the compiler allows
registers explicitly used in the rtl to be used as spill registers
@@ -1296,89 +1061,6 @@ enum reg_class
registers. */
#define SMALL_REGISTER_CLASSES TARGET_THUMB
-/* Get reg_class from a letter such as appears in the machine description.
- We only need constraint `f' for FPA_REGS (`r' == GENERAL_REGS) for the
- ARM, but several more letters for the Thumb. */
-#define REG_CLASS_FROM_LETTER(C) \
- ( (C) == 'f' ? FPA_REGS \
- : (C) == 'v' ? CIRRUS_REGS \
- : (C) == 'y' ? IWMMXT_REGS \
- : (C) == 'z' ? IWMMXT_GR_REGS \
- : (C) == 'l' ? (TARGET_ARM ? GENERAL_REGS : LO_REGS) \
- : TARGET_ARM ? NO_REGS \
- : (C) == 'h' ? HI_REGS \
- : (C) == 'b' ? BASE_REGS \
- : (C) == 'k' ? STACK_REG \
- : (C) == 'c' ? CC_REG \
- : NO_REGS)
-
-/* The letters I, J, K, L and M in a register constraint string
- can be used to stand for particular ranges of immediate operands.
- This macro defines what the ranges are.
- C is the letter, and VALUE is a constant value.
- Return 1 if VALUE is in the range specified by C.
- I: immediate arithmetic operand (i.e. 8 bits shifted as required).
- J: valid indexing constants.
- K: ~value ok in rhs argument of data operand.
- L: -value ok in rhs argument of data operand.
- M: 0..32, or a power of 2 (for shifts, or mult done by shift). */
-#define CONST_OK_FOR_ARM_LETTER(VALUE, C) \
- ((C) == 'I' ? const_ok_for_arm (VALUE) : \
- (C) == 'J' ? ((VALUE) < 4096 && (VALUE) > -4096) : \
- (C) == 'K' ? (const_ok_for_arm (~(VALUE))) : \
- (C) == 'L' ? (const_ok_for_arm (-(VALUE))) : \
- (C) == 'M' ? (((VALUE >= 0 && VALUE <= 32)) \
- || (((VALUE) & ((VALUE) - 1)) == 0)) \
- : 0)
-
-#define CONST_OK_FOR_THUMB_LETTER(VAL, C) \
- ((C) == 'I' ? (unsigned HOST_WIDE_INT) (VAL) < 256 : \
- (C) == 'J' ? (VAL) > -256 && (VAL) < 0 : \
- (C) == 'K' ? thumb_shiftable_const (VAL) : \
- (C) == 'L' ? (VAL) > -8 && (VAL) < 8 : \
- (C) == 'M' ? ((unsigned HOST_WIDE_INT) (VAL) < 1024 \
- && ((VAL) & 3) == 0) : \
- (C) == 'N' ? ((unsigned HOST_WIDE_INT) (VAL) < 32) : \
- (C) == 'O' ? ((VAL) >= -508 && (VAL) <= 508) \
- : 0)
-
-#define CONST_OK_FOR_LETTER_P(VALUE, C) \
- (TARGET_ARM ? \
- CONST_OK_FOR_ARM_LETTER (VALUE, C) : CONST_OK_FOR_THUMB_LETTER (VALUE, C))
-
-/* Constant letter 'G' for the FPA immediate constants.
- 'H' means the same constant negated. */
-#define CONST_DOUBLE_OK_FOR_ARM_LETTER(X, C) \
- ((C) == 'G' ? const_double_rtx_ok_for_fpa (X) : \
- (C) == 'H' ? neg_const_double_rtx_ok_for_fpa (X) : 0)
-
-#define CONST_DOUBLE_OK_FOR_LETTER_P(X, C) \
- (TARGET_ARM ? \
- CONST_DOUBLE_OK_FOR_ARM_LETTER (X, C) : 0)
-
-/* For the ARM, `Q' means that this is a memory operand that is just
- an offset from a register.
- `S' means any symbol that has the SYMBOL_REF_FLAG set or a CONSTANT_POOL
- address. This means that the symbol is in the text segment and can be
- accessed without using a load. */
-
-#define EXTRA_CONSTRAINT_ARM(OP, C) \
- ((C) == 'Q' ? GET_CODE (OP) == MEM && GET_CODE (XEXP (OP, 0)) == REG : \
- (C) == 'R' ? (GET_CODE (OP) == MEM \
- && GET_CODE (XEXP (OP, 0)) == SYMBOL_REF \
- && CONSTANT_POOL_ADDRESS_P (XEXP (OP, 0))) : \
- (C) == 'S' ? (optimize > 0 && CONSTANT_ADDRESS_P (OP)) : \
- (C) == 'T' ? cirrus_memory_offset (OP) : \
- 0)
-
-#define EXTRA_CONSTRAINT_THUMB(X, C) \
- ((C) == 'Q' ? (GET_CODE (X) == MEM \
- && GET_CODE (XEXP (X, 0)) == LABEL_REF) : 0)
-
-#define EXTRA_CONSTRAINT(X, C) \
- (TARGET_ARM ? \
- EXTRA_CONSTRAINT_ARM (X, C) : EXTRA_CONSTRAINT_THUMB (X, C))
-
/* Given an rtx X being reloaded into a reg required to be
in class CLASS, return the class of reg to actually use.
In general this is just CLASS, but for the Thumb we prefer
@@ -1406,15 +1088,27 @@ enum reg_class
or out of a register in CLASS in MODE. If it can be done directly,
NO_REGS is returned. */
#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, X) \
- (TARGET_ARM ? \
- (((MODE) == HImode && ! arm_arch4 && true_regnum (X) == -1) \
+ /* Restrict which direct reloads are allowed for VFP/iWMMXt regs. */ \
+ ((TARGET_VFP && TARGET_HARD_FLOAT \
+ && (CLASS) == VFP_REGS) \
+ ? coproc_secondary_reload_class (MODE, X, FALSE) \
+ : (TARGET_IWMMXT && (CLASS) == IWMMXT_REGS) \
+ ? coproc_secondary_reload_class (MODE, X, TRUE) \
+ : TARGET_ARM \
+ ? (((MODE) == HImode && ! arm_arch4 && true_regnum (X) == -1) \
? GENERAL_REGS : NO_REGS) \
: THUMB_SECONDARY_OUTPUT_RELOAD_CLASS (CLASS, MODE, X))
-
+
/* If we need to load shorts byte-at-a-time, then we need a scratch. */
#define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, X) \
+ /* Restrict which direct reloads are allowed for VFP/iWMMXt regs. */ \
+ ((TARGET_VFP && TARGET_HARD_FLOAT \
+ && (CLASS) == VFP_REGS) \
+ ? coproc_secondary_reload_class (MODE, X, FALSE) : \
+ (TARGET_IWMMXT && (CLASS) == IWMMXT_REGS) ? \
+ coproc_secondary_reload_class (MODE, X, TRUE) : \
/* Cannot load constants into Cirrus registers. */ \
- ((TARGET_CIRRUS \
+ (TARGET_MAVERICK && TARGET_HARD_FLOAT \
&& (CLASS) == CIRRUS_REGS \
&& (CONSTANT_P (X) || GET_CODE (X) == SYMBOL_REF)) \
? GENERAL_REGS : \
@@ -1422,7 +1116,7 @@ enum reg_class
(((CLASS) == IWMMXT_REGS || (CLASS) == IWMMXT_GR_REGS) \
&& CONSTANT_P (X)) \
? GENERAL_REGS : \
- (((MODE) == HImode && ! arm_arch4 && TARGET_MMU_TRAPS \
+ (((MODE) == HImode && ! arm_arch4 \
&& (GET_CODE (X) == MEM \
|| ((GET_CODE (X) == REG || GET_CODE (X) == SUBREG) \
&& true_regnum (X) == -1))) \
@@ -1448,9 +1142,9 @@ enum reg_class
HOST_WIDE_INT val = INTVAL (XEXP (X, 1)); \
HOST_WIDE_INT low, high; \
\
- if (MODE == DImode || (TARGET_SOFT_FLOAT && MODE == DFmode)) \
+ if (MODE == DImode || (MODE == DFmode && TARGET_SOFT_FLOAT)) \
low = ((val & 0xf) ^ 0x8) - 0x8; \
- else if (TARGET_CIRRUS) \
+ else if (TARGET_MAVERICK && TARGET_HARD_FLOAT) \
/* Need to be careful, -256 is not a valid offset. */ \
low = val >= 0 ? (val & 0xff) : -((-val) & 0xff); \
else if (MODE == SImode \
@@ -1462,7 +1156,7 @@ enum reg_class
/* Need to be careful, -256 is not a valid offset. */ \
low = val >= 0 ? (val & 0xff) : -((-val) & 0xff); \
else if (GET_MODE_CLASS (MODE) == MODE_FLOAT \
- && TARGET_HARD_FLOAT) \
+ && TARGET_HARD_FLOAT && TARGET_FPA) \
/* Need to be careful, -1024 is not a valid offset. */ \
low = val >= 0 ? (val & 0x3ff) : -((-val) & 0x3ff); \
else \
@@ -1497,30 +1191,22 @@ enum reg_class
/* We could probably achieve better results by defining PROMOTE_MODE to help
cope with the variances between the Thumb's signed and unsigned byte and
halfword load instructions. */
-#define THUMB_LEGITIMIZE_RELOAD_ADDRESS(X, MODE, OPNUM, TYPE, IND_LEVELS, WIN) \
-{ \
- if (GET_CODE (X) == PLUS \
- && GET_MODE_SIZE (MODE) < 4 \
- && GET_CODE (XEXP (X, 0)) == REG \
- && XEXP (X, 0) == stack_pointer_rtx \
- && GET_CODE (XEXP (X, 1)) == CONST_INT \
- && ! thumb_legitimate_offset_p (MODE, INTVAL (XEXP (X, 1)))) \
- { \
- rtx orig_X = X; \
- X = copy_rtx (X); \
- push_reload (orig_X, NULL_RTX, &X, NULL, \
- MODE_BASE_REG_CLASS (MODE), \
- Pmode, VOIDmode, 0, 0, OPNUM, TYPE); \
- goto WIN; \
- } \
-}
+#define THUMB_LEGITIMIZE_RELOAD_ADDRESS(X, MODE, OPNUM, TYPE, IND_L, WIN) \
+do { \
+ rtx new_x = thumb_legitimize_reload_address (&X, MODE, OPNUM, TYPE, IND_L); \
+ if (new_x) \
+ { \
+ X = new_x; \
+ goto WIN; \
+ } \
+} while (0)
#define LEGITIMIZE_RELOAD_ADDRESS(X, MODE, OPNUM, TYPE, IND_LEVELS, WIN) \
if (TARGET_ARM) \
ARM_LEGITIMIZE_RELOAD_ADDRESS (X, MODE, OPNUM, TYPE, IND_LEVELS, WIN); \
else \
THUMB_LEGITIMIZE_RELOAD_ADDRESS (X, MODE, OPNUM, TYPE, IND_LEVELS, WIN)
-
+
/* Return the maximum number of consecutive registers
needed to represent mode MODE in a register of class CLASS.
ARM regs are UNITS_PER_WORD bits while FPA regs can hold any FP mode */
@@ -1535,6 +1221,8 @@ enum reg_class
(TARGET_ARM ? \
((FROM) == FPA_REGS && (TO) != FPA_REGS ? 20 : \
(FROM) != FPA_REGS && (TO) == FPA_REGS ? 20 : \
+ (FROM) == VFP_REGS && (TO) != VFP_REGS ? 10 : \
+ (FROM) != VFP_REGS && (TO) == VFP_REGS ? 10 : \
(FROM) == IWMMXT_REGS && (TO) != IWMMXT_REGS ? 4 : \
(FROM) != IWMMXT_REGS && (TO) == IWMMXT_REGS ? 4 : \
(FROM) == IWMMXT_GR_REGS || (TO) == IWMMXT_GR_REGS ? 20 : \
@@ -1550,12 +1238,26 @@ enum reg_class
makes the stack pointer a smaller address. */
#define STACK_GROWS_DOWNWARD 1
-/* Define this if the nominal address of the stack frame
+/* Define this to nonzero if the nominal address of the stack frame
is at the high-address end of the local variables;
that is, each additional local variable allocated
goes at a more negative offset in the frame. */
#define FRAME_GROWS_DOWNWARD 1
+/* The amount of scratch space needed by _interwork_{r7,r11}_call_via_rN().
+ When present, it is one word in size, and sits at the top of the frame,
+ between the soft frame pointer and either r7 or r11.
+
+ We only need _interwork_rM_call_via_rN() for -mcaller-super-interworking,
+ and only then if some outgoing arguments are passed on the stack. It would
+ be tempting to also check whether the stack arguments are passed by indirect
+ calls, but there seems to be no reason in principle why a post-reload pass
+ couldn't convert a direct call into an indirect one. */
+#define CALLER_INTERWORKING_SLOT_SIZE \
+ (TARGET_CALLER_INTERWORKING \
+ && current_function_outgoing_args_size != 0 \
+ ? UNITS_PER_WORD : 0)
+
/* Offset within stack frame to start allocating local variables at.
If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
first local allocated. Otherwise, it is the offset to the BEGINNING
@@ -1590,11 +1292,13 @@ enum reg_class
/* Define how to find the value returned by a library function
assuming the value has mode MODE. */
#define LIBCALL_VALUE(MODE) \
- (TARGET_ARM && TARGET_HARD_FLOAT && GET_MODE_CLASS (MODE) == MODE_FLOAT \
- ? gen_rtx_REG (MODE, FIRST_ARM_FP_REGNUM) \
- : TARGET_ARM && TARGET_CIRRUS && GET_MODE_CLASS (MODE) == MODE_FLOAT \
+ (TARGET_ARM && TARGET_HARD_FLOAT_ABI && TARGET_FPA \
+ && GET_MODE_CLASS (MODE) == MODE_FLOAT \
+ ? gen_rtx_REG (MODE, FIRST_FPA_REGNUM) \
+ : TARGET_ARM && TARGET_HARD_FLOAT_ABI && TARGET_MAVERICK \
+ && GET_MODE_CLASS (MODE) == MODE_FLOAT \
? gen_rtx_REG (MODE, FIRST_CIRRUS_FP_REGNUM) \
- : TARGET_REALLY_IWMMXT && VECTOR_MODE_SUPPORTED_P (MODE) \
+ : TARGET_IWMMXT_ABI && arm_vector_mode_supported_p (MODE) \
? gen_rtx_REG (MODE, FIRST_IWMMXT_REGNUM) \
: gen_rtx_REG (MODE, ARG_REGISTER (1)))
@@ -1603,16 +1307,22 @@ enum reg_class
If the precise function being called is known, FUNC is its FUNCTION_DECL;
otherwise, FUNC is 0. */
#define FUNCTION_VALUE(VALTYPE, FUNC) \
- LIBCALL_VALUE (TYPE_MODE (VALTYPE))
+ arm_function_value (VALTYPE, FUNC);
/* 1 if N is a possible register number for a function value.
On the ARM, only r0 and f0 can return results. */
/* On a Cirrus chip, mvf0 can return results. */
#define FUNCTION_VALUE_REGNO_P(REGNO) \
((REGNO) == ARG_REGISTER (1) \
- || (TARGET_ARM && ((REGNO) == FIRST_CIRRUS_FP_REGNUM) && TARGET_CIRRUS) \
- || (TARGET_ARM && ((REGNO) == FIRST_IWMMXT_REGNUM) && TARGET_IWMMXT) \
- || (TARGET_ARM && ((REGNO) == FIRST_ARM_FP_REGNUM) && TARGET_HARD_FLOAT))
+ || (TARGET_ARM && ((REGNO) == FIRST_CIRRUS_FP_REGNUM) \
+ && TARGET_HARD_FLOAT_ABI && TARGET_MAVERICK) \
+ || ((REGNO) == FIRST_IWMMXT_REGNUM && TARGET_IWMMXT_ABI) \
+ || (TARGET_ARM && ((REGNO) == FIRST_FPA_REGNUM) \
+ && TARGET_HARD_FLOAT_ABI && TARGET_FPA))
+
+/* Amount of memory needed for an untyped call to save all possible return
+ registers. */
+#define APPLY_RESULT_SIZE arm_apply_result_size()
/* How large values are returned */
/* A C expression which can inhibit the returning of certain function values
@@ -1630,7 +1340,7 @@ enum reg_class
#define CALL_SHORT 0x00000002 /* Never call indirect. */
/* These bits describe the different types of function supported
- by the ARM backend. They are exclusive. ie a function cannot be both a
+ by the ARM backend. They are exclusive. i.e. a function cannot be both a
normal function and an interworked function, for example. Knowing the
type of a function is important for determining its prologue and
epilogue sequences.
@@ -1643,7 +1353,6 @@ enum reg_class
#define ARM_FT_UNKNOWN 0 /* Type has not yet been determined. */
#define ARM_FT_NORMAL 1 /* Your normal, straightforward function. */
#define ARM_FT_INTERWORKED 2 /* A function that supports interworking. */
-#define ARM_FT_EXCEPTION_HANDLER 3 /* A C++ exception handler. */
#define ARM_FT_ISR 4 /* An interrupt service routine. */
#define ARM_FT_FIQ 5 /* A fast interrupt service routine. */
#define ARM_FT_EXCEPTION 6 /* An ARM exception handler (subcase of ISR). */
@@ -1664,6 +1373,23 @@ enum reg_class
#define IS_NAKED(t) (t & ARM_FT_NAKED)
#define IS_NESTED(t) (t & ARM_FT_NESTED)
+
+/* Structure used to hold the function stack frame layout. Offsets are
+ relative to the stack pointer on function entry. Positive offsets are
+ in the direction of stack growth.
+ Only soft_frame is used in thumb mode. */
+
+typedef struct arm_stack_offsets GTY(())
+{
+ int saved_args; /* ARG_POINTER_REGNUM. */
+ int frame; /* ARM_HARD_FRAME_POINTER_REGNUM. */
+ int saved_regs;
+ int soft_frame; /* FRAME_POINTER_REGNUM. */
+ int locals_base; /* THUMB_HARD_FRAME_POINTER_REGNUM. */
+ int outgoing_args; /* STACK_POINTER_REGNUM. */
+}
+arm_stack_offsets;
+
/* A C structure for machine-specific, per-function data.
This is added to the cfun structure. */
typedef struct machine_function GTY(())
@@ -1677,7 +1403,7 @@ typedef struct machine_function GTY(())
/* Records if the save of LR has been eliminated. */
int lr_save_eliminated;
/* The size of the stack frame. Only valid after reload. */
- int frame_size;
+ arm_stack_offsets stack_offsets;
/* Records the type of the current function. */
unsigned long func_type;
/* Record if the function has a variable argument list. */
@@ -1685,9 +1411,19 @@ typedef struct machine_function GTY(())
/* Records if sibcalls are blocked because an argument
register is needed to preserve stack alignment. */
int sibcall_blocked;
+ /* The PIC register for this function. This might be a pseudo. */
+ rtx pic_reg;
+ /* Labels for per-function Thumb call-via stubs. One per potential calling
+ register. We can never call via LR or PC. We can call via SP if a
+ trampoline happens to be on the top of the stack. */
+ rtx call_via[14];
}
machine_function;
+/* As in the machine_function, a global set of call-via labels, for code
+ that is in text_section. */
+extern GTY(()) rtx thumb_call_via_label[14];
+
/* A C type for declaring a variable that is used as the first argument of
`FUNCTION_ARG' and other related values. For some target machines, the
type `int' suffices and can hold the number of bytes of argument so far. */
@@ -1701,6 +1437,7 @@ typedef struct
int nargs;
/* One of CALL_NORMAL, CALL_LONG or CALL_SHORT. */
int call_cookie;
+ int can_split;
} CUMULATIVE_ARGS;
/* Define where to put the arguments to a function.
@@ -1718,28 +1455,22 @@ typedef struct
On the ARM, normally the first 16 bytes are passed in registers r0-r3; all
other arguments are passed on the stack. If (NAMED == 0) (which happens
- only in assign_parms, since SETUP_INCOMING_VARARGS is defined), say it is
- passed in the stack (function_prologue will indeed make it pass in the
- stack if necessary). */
+ only in assign_parms, since TARGET_SETUP_INCOMING_VARARGS is
+ defined), say it is passed in the stack (function_prologue will
+ indeed make it pass in the stack if necessary). */
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
arm_function_arg (&(CUM), (MODE), (TYPE), (NAMED))
-/* For an arg passed partly in registers and partly in memory,
- this is the number of registers used.
- For args passed entirely in registers or entirely in memory, zero. */
-#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
- (VECTOR_MODE_SUPPORTED_P (MODE) ? 0 : \
- NUM_ARG_REGS > (CUM).nregs \
- && (NUM_ARG_REGS < ((CUM).nregs + ARM_NUM_REGS2 (MODE, TYPE))) \
- ? NUM_ARG_REGS - (CUM).nregs : 0)
-
-/* A C expression that indicates when an argument must be passed by
- reference. If nonzero for an argument, a copy of that argument is
- made in memory and a pointer to the argument is passed instead of
- the argument itself. The pointer is passed in whatever way is
- appropriate for passing a pointer to that type. */
-#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \
- arm_function_arg_pass_by_reference (&CUM, MODE, TYPE, NAMED)
+#define FUNCTION_ARG_PADDING(MODE, TYPE) \
+ (arm_pad_arg_upward (MODE, TYPE) ? upward : downward)
+
+#define BLOCK_REG_PADDING(MODE, TYPE, FIRST) \
+ (arm_pad_reg_upward (MODE, TYPE, FIRST) ? upward : downward)
+
+/* For AAPCS, padding should never be below the argument. For other ABIs,
+ * mimic the default. */
+#define PAD_VARARGS_DOWN \
+ ((TARGET_AAPCS_BASED) ? 0 : BYTES_BIG_ENDIAN)
/* Initialize a variable CUM of type CUMULATIVE_ARGS
for a call to a function whose data type is FNTYPE.
@@ -1753,52 +1484,28 @@ typedef struct
(TYPE is null for libcalls where that information may not be available.) */
#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
(CUM).nargs += 1; \
- if (VECTOR_MODE_SUPPORTED_P (MODE)) \
- if ((CUM).named_count <= (CUM).nargs) \
- (CUM).nregs += 2; \
- else \
- (CUM).iwmmxt_nregs += 1; \
+ if (arm_vector_mode_supported_p (MODE) \
+ && (CUM).named_count > (CUM).nargs) \
+ (CUM).iwmmxt_nregs += 1; \
else \
- (CUM).nregs += ARM_NUM_REGS2 (MODE, TYPE)
+ (CUM).nregs += ARM_NUM_REGS2 (MODE, TYPE)
/* If defined, a C expression that gives the alignment boundary, in bits, of an
argument with the specified mode and type. If it is not defined,
`PARM_BOUNDARY' is used for all arguments. */
#define FUNCTION_ARG_BOUNDARY(MODE,TYPE) \
- (TARGET_REALLY_IWMMXT && (VALID_IWMMXT_REG_MODE (MODE) || ((MODE) == DFmode)) \
- ? IWMMXT_ALIGNMENT : PARM_BOUNDARY)
+ ((ARM_DOUBLEWORD_ALIGN && arm_needs_doubleword_align (MODE, TYPE)) \
+ ? DOUBLEWORD_ALIGNMENT \
+ : PARM_BOUNDARY )
/* 1 if N is a possible register number for function argument passing.
On the ARM, r0-r3 are used to pass args. */
#define FUNCTION_ARG_REGNO_P(REGNO) \
(IN_RANGE ((REGNO), 0, 3) \
- || (TARGET_REALLY_IWMMXT && IN_RANGE ((REGNO), FIRST_IWMMXT_REGNUM, FIRST_IWMMXT_REGNUM + 9)))
-
-/* Implement `va_arg'. */
-#define EXPAND_BUILTIN_VA_ARG(valist, type) \
- arm_va_arg (valist, type)
+ || (TARGET_IWMMXT_ABI \
+ && IN_RANGE ((REGNO), FIRST_IWMMXT_REGNUM, FIRST_IWMMXT_REGNUM + 9)))
-/* Perform any actions needed for a function that is receiving a variable
- number of arguments. CUM is as above. MODE and TYPE are the mode and type
- of the current parameter. PRETEND_SIZE is a variable that should be set to
- the amount of stack that must be pushed by the prolog to pretend that our
- caller pushed it.
-
- Normally, this macro will push all remaining incoming registers on the
- stack and set PRETEND_SIZE to the length of the registers pushed.
-
- On the ARM, PRETEND_SIZE is set in order to have the prologue push the last
- named arg and all anonymous args onto the stack.
- XXX I know the prologue shouldn't be pushing registers, but it is faster
- that way. */
-#define SETUP_INCOMING_VARARGS(CUM, MODE, TYPE, PRETEND_SIZE, NO_RTL) \
-{ \
- cfun->machine->uses_anonymous_args = 1; \
- if ((CUM).nregs < NUM_ARG_REGS) \
- (PRETEND_SIZE) = (NUM_ARG_REGS - (CUM).nregs) * UNITS_PER_WORD; \
-}
-
/* If your target environment doesn't prefix user functions with an
underscore, you may wish to re-define this to prevent any conflicts.
e.g. AOF may prefix mcount with an underscore. */
@@ -1836,7 +1543,7 @@ typedef struct
assemble_name (STREAM, ARM_MCOUNT_NAME); \
fputc ('\n', STREAM); \
ASM_GENERATE_INTERNAL_LABEL (temp, "LP", LABELNO); \
- sym = gen_rtx (SYMBOL_REF, Pmode, temp); \
+ sym = gen_rtx_SYMBOL_REF (Pmode, temp); \
assemble_aligned_integer (UNITS_PER_WORD, sym); \
}
#endif
@@ -1906,64 +1613,17 @@ typedef struct
((TO) == THUMB_HARD_FRAME_POINTER_REGNUM && TARGET_ARM) ? 0 : \
1)
-#define THUMB_REG_PUSHED_P(reg) \
- (regs_ever_live [reg] \
- && (! call_used_regs [reg] \
- || (flag_pic && (reg) == PIC_OFFSET_TABLE_REGNUM)) \
- && !(TARGET_SINGLE_PIC_BASE && ((reg) == arm_pic_register)))
-
/* Define the offset between two registers, one to be eliminated, and the
other its replacement, at the start of a routine. */
-#define ARM_INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
- do \
- { \
- (OFFSET) = arm_compute_initial_elimination_offset (FROM, TO); \
- } \
- while (0)
-
-/* Note: This macro must match the code in thumb_function_prologue(). */
-#define THUMB_INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
-{ \
- (OFFSET) = 0; \
- if ((FROM) == ARG_POINTER_REGNUM) \
- { \
- int count_regs = 0; \
- int regno; \
- for (regno = 8; regno < 13; regno ++) \
- if (THUMB_REG_PUSHED_P (regno)) \
- count_regs ++; \
- if (count_regs) \
- (OFFSET) += 4 * count_regs; \
- count_regs = 0; \
- for (regno = 0; regno <= LAST_LO_REGNUM; regno ++) \
- if (THUMB_REG_PUSHED_P (regno)) \
- count_regs ++; \
- if (count_regs || ! leaf_function_p () || thumb_far_jump_used_p (0))\
- (OFFSET) += 4 * (count_regs + 1); \
- if (TARGET_BACKTRACE) \
- { \
- if ((count_regs & 0xFF) == 0 && (regs_ever_live[3] != 0)) \
- (OFFSET) += 20; \
- else \
- (OFFSET) += 16; \
- } \
- } \
- if ((TO) == STACK_POINTER_REGNUM) \
- { \
- (OFFSET) += current_function_outgoing_args_size; \
- (OFFSET) += thumb_get_frame_size (); \
- } \
-}
-
#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
if (TARGET_ARM) \
- ARM_INITIAL_ELIMINATION_OFFSET (FROM, TO, OFFSET); \
+ (OFFSET) = arm_compute_initial_elimination_offset (FROM, TO); \
else \
- THUMB_INITIAL_ELIMINATION_OFFSET (FROM, TO, OFFSET)
-
+ (OFFSET) = thumb_compute_initial_elimination_offset (FROM, TO)
+
/* Special case handling of the location of arguments passed on the stack. */
#define DEBUGGER_ARG_OFFSET(value, addr) value ? value : arm_debugger_arg_offset (value, addr)
-
+
/* Initialize data used by insn expanders. This is called from insn_emit,
once for every function before code is generated. */
#define INIT_EXPANDERS arm_init_expanders ()
@@ -2016,13 +1676,14 @@ typedef struct
ARM_TRAMPOLINE_TEMPLATE (FILE) \
else \
THUMB_TRAMPOLINE_TEMPLATE (FILE)
-
+
/* Length in units of the trampoline for entering a nested function. */
#define TRAMPOLINE_SIZE (TARGET_ARM ? 16 : 24)
/* Alignment required for a trampoline in bits. */
#define TRAMPOLINE_ALIGNMENT 32
+
/* Emit RTL insns to initialize the variable parts of a trampoline.
FNADDR is an RTX for the address of the function's pure code.
CXT is an RTX for the static chain value for the function. */
@@ -2037,6 +1698,9 @@ typedef struct
plus_constant (TRAMP, \
TARGET_ARM ? 12 : 20)), \
FNADDR); \
+ emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"), \
+ 0, VOIDmode, 2, TRAMP, Pmode, \
+ plus_constant (TRAMP, TRAMPOLINE_SIZE), Pmode); \
}
#endif
@@ -2077,6 +1741,11 @@ typedef struct
? THUMB_REGNO_MODE_OK_FOR_BASE_P (REGNO, MODE) \
: ARM_REGNO_OK_FOR_BASE_P (REGNO))
+/* Nonzero if X can be the base register in a reg+reg addressing mode.
+ For Thumb, we can not use SP + reg, so reject SP. */
+#define REGNO_MODE_OK_FOR_REG_BASE_P(X, MODE) \
+ REGNO_OK_FOR_INDEX_P (X)
+
/* For ARM code, we don't care about the mode, but for Thumb, the index
must be suitable for use in a QImode load. */
#define REGNO_OK_FOR_INDEX_P(REGNO) \
@@ -2109,7 +1778,7 @@ typedef struct
On the ARM, allow any integer (invalid ones are removed later by insn
patterns), nice doubles and symbol_refs which refer to the function's
constant pool XXX.
-
+
When generating pic allow anything. */
#define ARM_LEGITIMATE_CONSTANT_P(X) (flag_pic || ! label_mentioned_p (X))
@@ -2119,8 +1788,10 @@ typedef struct
|| CONSTANT_ADDRESS_P (X) \
|| flag_pic)
-#define LEGITIMATE_CONSTANT_P(X) \
- (TARGET_ARM ? ARM_LEGITIMATE_CONSTANT_P (X) : THUMB_LEGITIMATE_CONSTANT_P (X))
+#define LEGITIMATE_CONSTANT_P(X) \
+ (!arm_tls_referenced_p (X) \
+ && (TARGET_ARM ? ARM_LEGITIMATE_CONSTANT_P (X) \
+ : THUMB_LEGITIMATE_CONSTANT_P (X)))
/* Special characters prefixed to function names
in order to encode attribute like information.
@@ -2146,7 +1817,7 @@ typedef struct
case SHORT_CALL_FLAG_CHAR: return 1; \
case LONG_CALL_FLAG_CHAR: return 1; \
case '*': return 1; \
- SUBTARGET_NAME_ENCODING_LENGTHS
+ SUBTARGET_NAME_ENCODING_LENGTHS
/* This is how to output a reference to a user-level label named NAME.
`assemble_name' uses this. */
@@ -2154,8 +1825,75 @@ typedef struct
#define ASM_OUTPUT_LABELREF(FILE, NAME) \
arm_asm_output_labelref (FILE, NAME)
+/* The EABI specifies that constructors should go in .init_array.
+ Other targets use .ctors for compatibility. */
+#ifndef ARM_EABI_CTORS_SECTION_OP
+#define ARM_EABI_CTORS_SECTION_OP \
+ "\t.section\t.init_array,\"aw\",%init_array"
+#endif
+#ifndef ARM_EABI_DTORS_SECTION_OP
+#define ARM_EABI_DTORS_SECTION_OP \
+ "\t.section\t.fini_array,\"aw\",%fini_array"
+#endif
+#define ARM_CTORS_SECTION_OP \
+ "\t.section\t.ctors,\"aw\",%progbits"
+#define ARM_DTORS_SECTION_OP \
+ "\t.section\t.dtors,\"aw\",%progbits"
+
+/* Define CTORS_SECTION_ASM_OP. */
+#undef CTORS_SECTION_ASM_OP
+#undef DTORS_SECTION_ASM_OP
+#ifndef IN_LIBGCC2
+# define CTORS_SECTION_ASM_OP \
+ (TARGET_AAPCS_BASED ? ARM_EABI_CTORS_SECTION_OP : ARM_CTORS_SECTION_OP)
+# define DTORS_SECTION_ASM_OP \
+ (TARGET_AAPCS_BASED ? ARM_EABI_DTORS_SECTION_OP : ARM_DTORS_SECTION_OP)
+#else /* !defined (IN_LIBGCC2) */
+/* In libgcc, CTORS_SECTION_ASM_OP must be a compile-time constant,
+ so we cannot use the definition above. */
+# ifdef __ARM_EABI__
+/* The .ctors section is not part of the EABI, so we do not define
+ CTORS_SECTION_ASM_OP when in libgcc; that prevents crtstuff
+ from trying to use it. We do define it when doing normal
+ compilation, as .init_array can be used instead of .ctors. */
+/* There is no need to emit begin or end markers when using
+ init_array; the dynamic linker will compute the size of the
+ array itself based on special symbols created by the static
+ linker. However, we do need to arrange to set up
+ exception-handling here. */
+# define CTOR_LIST_BEGIN asm (ARM_EABI_CTORS_SECTION_OP)
+# define CTOR_LIST_END /* empty */
+# define DTOR_LIST_BEGIN asm (ARM_EABI_DTORS_SECTION_OP)
+# define DTOR_LIST_END /* empty */
+# else /* !defined (__ARM_EABI__) */
+# define CTORS_SECTION_ASM_OP ARM_CTORS_SECTION_OP
+# define DTORS_SECTION_ASM_OP ARM_DTORS_SECTION_OP
+# endif /* !defined (__ARM_EABI__) */
+#endif /* !defined (IN_LIBCC2) */
+
+/* True if the operating system can merge entities with vague linkage
+ (e.g., symbols in COMDAT group) during dynamic linking. */
+#ifndef TARGET_ARM_DYNAMIC_VAGUE_LINKAGE_P
+#define TARGET_ARM_DYNAMIC_VAGUE_LINKAGE_P true
+#endif
+
+/* Set the short-call flag for any function compiled in the current
+ compilation unit. We skip this for functions with the section
+ attribute when long-calls are in effect as this tells the compiler
+ that the section might be placed a long way from the caller.
+ See arm_is_longcall_p() for more information. */
#define ARM_DECLARE_FUNCTION_SIZE(STREAM, NAME, DECL) \
- arm_encode_call_attribute (DECL, SHORT_CALL_FLAG_CHAR)
+ if (!TARGET_LONG_CALLS || ! DECL_SECTION_NAME (DECL)) \
+ arm_encode_call_attribute (DECL, SHORT_CALL_FLAG_CHAR)
+
+#define ARM_OUTPUT_FN_UNWIND(F, PROLOGUE) arm_output_fn_unwind (F, PROLOGUE)
+
+#ifdef TARGET_UNWIND_INFO
+#define ARM_EABI_UNWIND_TABLES \
+ ((!USING_SJLJ_EXCEPTIONS && flag_exceptions) || flag_unwind_tables)
+#else
+#define ARM_EABI_UNWIND_TABLES 0
+#endif
/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
and check its validity for a certain class.
@@ -2214,12 +1952,16 @@ typedef struct
? THUMB_REG_OK_FOR_INDEX_P (X) \
: ARM_REG_OK_FOR_INDEX_P (X))
+/* Nonzero if X can be the base register in a reg+reg addressing mode.
+ For Thumb, we can not use SP + reg, so reject SP. */
+#define REG_MODE_OK_FOR_REG_BASE_P(X, MODE) \
+ REG_OK_FOR_INDEX_P (X)
/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
that is a valid memory address for an instruction.
The MODE argument is the machine mode for the MEM expression
that wants to use this address. */
-
+
#define ARM_BASE_REGISTER_RTX_P(X) \
(GET_CODE (X) == REG && ARM_REG_OK_FOR_BASE_P (X))
@@ -2228,7 +1970,7 @@ typedef struct
#define ARM_GO_IF_LEGITIMATE_ADDRESS(MODE,X,WIN) \
{ \
- if (arm_legitimate_address_p (MODE, X, REG_STRICT_P)) \
+ if (arm_legitimate_address_p (MODE, X, SET, REG_STRICT_P)) \
goto WIN; \
}
@@ -2242,7 +1984,7 @@ typedef struct
if (TARGET_ARM) \
ARM_GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN) \
else /* if (TARGET_THUMB) */ \
- THUMB_GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN)
+ THUMB_GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN)
/* Try machine-dependent ways of modifying an illegitimate address
@@ -2250,15 +1992,11 @@ typedef struct
#define ARM_LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
do { \
X = arm_legitimize_address (X, OLDX, MODE); \
- \
- if (memory_address_p (MODE, X)) \
- goto WIN; \
} while (0)
-#define THUMB_LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
-do { \
- if (flag_pic) \
- (X) = legitimize_pic_address (OLDX, MODE, NULL_RTX); \
+#define THUMB_LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
+do { \
+ X = thumb_legitimize_address (X, OLDX, MODE); \
} while (0)
#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
@@ -2267,8 +2005,11 @@ do { \
ARM_LEGITIMIZE_ADDRESS (X, OLDX, MODE, WIN); \
else \
THUMB_LEGITIMIZE_ADDRESS (X, OLDX, MODE, WIN); \
+ \
+ if (memory_address_p (MODE, X)) \
+ goto WIN; \
} while (0)
-
+
/* Go to LABEL if ADDR (a legitimate address expression)
has an effect that depends on the machine mode it is used for. */
#define ARM_GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \
@@ -2281,28 +2022,19 @@ do { \
/* Nothing helpful to do for the Thumb */
#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \
if (TARGET_ARM) \
- ARM_GO_IF_MODE_DEPENDENT_ADDRESS (ADDR, LABEL)
+ ARM_GO_IF_MODE_DEPENDENT_ADDRESS (ADDR, LABEL)
/* Specify the machine mode that this machine uses
for the index in the tablejump instruction. */
#define CASE_VECTOR_MODE Pmode
-/* Define as C expression which evaluates to nonzero if the tablejump
- instruction expects the table to contain offsets from the address of the
- table.
- Do not define this if the table should contain absolute addresses. */
-/* #define CASE_VECTOR_PC_RELATIVE 1 */
-
/* signed 'char' is most compatible, but RISC OS wants it unsigned.
unsigned is probably best, but may break some code. */
#ifndef DEFAULT_SIGNED_CHAR
#define DEFAULT_SIGNED_CHAR 0
#endif
-/* Don't cse the address of the function being compiled. */
-#define NO_RECURSIVE_FUNCTION_CSE 1
-
/* Max number of bytes we can move from memory to memory
in one reasonably fast instruction. */
#define MOVE_MAX 4
@@ -2317,17 +2049,17 @@ do { \
/* Define if loading in MODE, an integral mode narrower than BITS_PER_WORD
will either zero-extend or sign-extend. The value of this macro should
be the code that says which one of the two operations is implicitly
- done, NIL if none. */
+ done, UNKNOWN if none. */
#define LOAD_EXTEND_OP(MODE) \
(TARGET_THUMB ? ZERO_EXTEND : \
((arm_arch4 || (MODE) == QImode) ? ZERO_EXTEND \
- : ((BYTES_BIG_ENDIAN && (MODE) == HImode) ? SIGN_EXTEND : NIL)))
+ : ((BYTES_BIG_ENDIAN && (MODE) == HImode) ? SIGN_EXTEND : UNKNOWN)))
/* Nonzero if access to memory by bytes is slow and undesirable. */
#define SLOW_BYTE_ACCESS 0
#define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) 1
-
+
/* Immediate shift counts are truncated by the output routines (or was it
the assembler?). Shift counts in a register are truncated by ARM. Note
that the native compiler puts too large (> 32) immediate shift counts
@@ -2345,9 +2077,6 @@ do { \
/* Calling from registers is a massive pain. */
#define NO_FUNCTION_CSE 1
-/* Chars and shorts should be passed as ints. */
-#define PROMOTE_PROTOTYPES 1
-
/* The machine modes of pointers and functions */
#define Pmode SImode
#define FUNCTION_MODE Pmode
@@ -2361,7 +2090,7 @@ do { \
(TARGET_ARM ? 10 : \
((GET_MODE_SIZE (M) < 4 ? 8 : 2 * GET_MODE_SIZE (M)) \
* (CLASS == LO_REGS ? 1 : 2)))
-
+
/* Try to generate sequences that don't involve branches, we can then use
conditional instructions */
#define BRANCH_COST \
@@ -2371,26 +2100,23 @@ do { \
/* We decide which register to use based on the compilation options and
the assembler in use; this is more general than the APCS restriction of
using sb (r9) all the time. */
-extern int arm_pic_register;
-
-/* Used when parsing command line option -mpic-register=. */
-extern const char * arm_pic_register_string;
+extern unsigned arm_pic_register;
/* The register number of the register used to address a table of static
data addresses in memory. */
#define PIC_OFFSET_TABLE_REGNUM arm_pic_register
-#define FINALIZE_PIC arm_finalize_pic (1)
-
/* We can't directly access anything that contains a symbol,
- nor can we indirect via the constant pool. */
+ nor can we indirect via the constant pool. One exception is
+ UNSPEC_TLS, which is always PIC. */
#define LEGITIMATE_PIC_OPERAND_P(X) \
(!(symbol_mentioned_p (X) \
|| label_mentioned_p (X) \
|| (GET_CODE (X) == SYMBOL_REF \
&& CONSTANT_POOL_ADDRESS_P (X) \
&& (symbol_mentioned_p (get_pool_constant (X)) \
- || label_mentioned_p (get_pool_constant (X))))))
+ || label_mentioned_p (get_pool_constant (X))))) \
+ || tls_mentioned_p (X))
/* We need to know when we are making a constant pool; this determines
whether data needs to be in the GOT or can be referenced via a GOT
@@ -2410,7 +2136,12 @@ extern int making_const_table;
#define SELECT_CC_MODE(OP, X, Y) arm_select_cc_mode (OP, X, Y)
-#define REVERSIBLE_CC_MODE(MODE) ((MODE) != CCFPEmode)
+#define REVERSIBLE_CC_MODE(MODE) 1
+
+#define REVERSE_CONDITION(CODE,MODE) \
+ (((MODE) == CCFPmode || (MODE) == CCFPEmode) \
+ ? reverse_condition_maybe_unordered (code) \
+ : reverse_condition (code))
#define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \
do \
@@ -2420,7 +2151,8 @@ extern int making_const_table;
|| (const_ok_for_arm (- INTVAL (OP1))))) \
{ \
rtx const_op = OP1; \
- CODE = arm_canonicalize_comparison ((CODE), &const_op); \
+ CODE = arm_canonicalize_comparison ((CODE), GET_MODE (OP0), \
+ &const_op); \
OP1 = const_op; \
} \
} \
@@ -2593,7 +2325,7 @@ extern int making_const_table;
} \
\
default: \
- abort(); \
+ gcc_unreachable (); \
} \
} \
else if (GET_CODE (X) == PRE_INC || GET_CODE (X) == POST_INC \
@@ -2601,8 +2333,7 @@ extern int making_const_table;
{ \
extern enum machine_mode output_memory_reference_mode; \
\
- if (GET_CODE (XEXP (X, 0)) != REG) \
- abort (); \
+ gcc_assert (GET_CODE (XEXP (X, 0)) == REG); \
\
if (GET_CODE (X) == PRE_DEC || GET_CODE (X) == PRE_INC) \
asm_fprintf (STREAM, "[%r, #%s%d]!", \
@@ -2646,8 +2377,7 @@ extern int making_const_table;
asm_fprintf (STREAM, "%r!", REGNO (XEXP (X, 0))); \
else if (GET_CODE (X) == PLUS) \
{ \
- if (GET_CODE (XEXP (X, 0)) != REG) \
- abort (); \
+ gcc_assert (GET_CODE (XEXP (X, 0)) == REG); \
if (GET_CODE (XEXP (X, 1)) == CONST_INT) \
asm_fprintf (STREAM, "[%r, #%wd]", \
REGNO (XEXP (X, 0)), \
@@ -2667,10 +2397,9 @@ extern int making_const_table;
else \
THUMB_PRINT_OPERAND_ADDRESS (STREAM, X)
-#define OUTPUT_ADDR_CONST_EXTRA(FILE, X, FAIL) \
- if (GET_CODE (X) != CONST_VECTOR \
- || ! arm_emit_vector_const (FILE, X)) \
- goto FAIL;
+#define OUTPUT_ADDR_CONST_EXTRA(file, x, fail) \
+ if (arm_output_addr_const_extra (file, x) == FALSE) \
+ goto fail
/* A C expression whose value is RTL representing the value of the return
address for the frame COUNT steps up from the current frame. */
@@ -2678,7 +2407,7 @@ extern int making_const_table;
#define RETURN_ADDR_RTX(COUNT, FRAME) \
arm_return_addr (COUNT, FRAME)
-/* Mask of the bits in the PC that contain the real return address
+/* Mask of the bits in the PC that contain the real return address
when running in 26-bit mode. */
#define RETURN_ADDR_MASK26 (0x03fffffc)
@@ -2695,61 +2424,11 @@ extern int making_const_table;
in 26 bit mode, the condition codes must be masked out of the \
return address. This does not apply to ARM6 and later processors \
when running in 32 bit mode. */ \
- ((!TARGET_APCS_32) ? (gen_int_mode (RETURN_ADDR_MASK26, Pmode)) \
- : (arm_arch4 || TARGET_THUMB) ? \
- (gen_int_mode ((unsigned long)0xffffffff, Pmode)) \
+ ((arm_arch4 || TARGET_THUMB) \
+ ? (gen_int_mode ((unsigned long)0xffffffff, Pmode)) \
: arm_gen_return_addr_mask ())
-/* Define the codes that are matched by predicates in arm.c */
-#define PREDICATE_CODES \
- {"s_register_operand", {SUBREG, REG}}, \
- {"arm_hard_register_operand", {REG}}, \
- {"f_register_operand", {SUBREG, REG}}, \
- {"arm_add_operand", {SUBREG, REG, CONST_INT}}, \
- {"arm_addimm_operand", {CONST_INT}}, \
- {"fpa_add_operand", {SUBREG, REG, CONST_DOUBLE}}, \
- {"fpa_rhs_operand", {SUBREG, REG, CONST_DOUBLE}}, \
- {"arm_rhs_operand", {SUBREG, REG, CONST_INT}}, \
- {"arm_not_operand", {SUBREG, REG, CONST_INT}}, \
- {"reg_or_int_operand", {SUBREG, REG, CONST_INT}}, \
- {"index_operand", {SUBREG, REG, CONST_INT}}, \
- {"thumb_cmp_operand", {SUBREG, REG, CONST_INT}}, \
- {"thumb_cmpneg_operand", {CONST_INT}}, \
- {"thumb_cbrch_target_operand", {SUBREG, REG, MEM}}, \
- {"offsettable_memory_operand", {MEM}}, \
- {"bad_signed_byte_operand", {MEM}}, \
- {"alignable_memory_operand", {MEM}}, \
- {"shiftable_operator", {PLUS, MINUS, AND, IOR, XOR}}, \
- {"minmax_operator", {SMIN, SMAX, UMIN, UMAX}}, \
- {"shift_operator", {ASHIFT, ASHIFTRT, LSHIFTRT, ROTATERT, MULT}}, \
- {"di_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE, MEM}}, \
- {"nonimmediate_di_operand", {SUBREG, REG, MEM}}, \
- {"soft_df_operand", {SUBREG, REG, CONST_DOUBLE, MEM}}, \
- {"nonimmediate_soft_df_operand", {SUBREG, REG, MEM}}, \
- {"load_multiple_operation", {PARALLEL}}, \
- {"store_multiple_operation", {PARALLEL}}, \
- {"equality_operator", {EQ, NE}}, \
- {"arm_comparison_operator", {EQ, NE, LE, LT, GE, GT, GEU, GTU, LEU, \
- LTU, UNORDERED, ORDERED, UNLT, UNLE, \
- UNGE, UNGT}}, \
- {"arm_rhsm_operand", {SUBREG, REG, CONST_INT, MEM}}, \
- {"const_shift_operand", {CONST_INT}}, \
- {"multi_register_push", {PARALLEL}}, \
- {"cc_register", {REG}}, \
- {"logical_binary_operator", {AND, IOR, XOR}}, \
- {"cirrus_register_operand", {REG}}, \
- {"cirrus_fp_register", {REG}}, \
- {"cirrus_shift_const", {CONST_INT}}, \
- {"dominant_cc_register", {REG}},
-
-/* Define this if you have special predicates that know special things
- about modes. Genrecog will warn about certain forms of
- match_operand without a mode; if the operand predicate is listed in
- SPECIAL_MODE_PREDICATES, the warning will be suppressed. */
-#define SPECIAL_MODE_PREDICATES \
- "cc_register", "dominant_cc_register",
-
enum arm_builtins
{
ARM_BUILTIN_GETWCX,
@@ -2860,8 +2539,8 @@ enum arm_builtins
ARM_BUILTIN_WMINUH,
ARM_BUILTIN_WMINUB,
- ARM_BUILTIN_WMULUH,
- ARM_BUILTIN_WMULSH,
+ ARM_BUILTIN_WMULUM,
+ ARM_BUILTIN_WMULSM,
ARM_BUILTIN_WMULUL,
ARM_BUILTIN_PSADBH,
@@ -2912,6 +2591,8 @@ enum arm_builtins
ARM_BUILTIN_WUNPCKELUH,
ARM_BUILTIN_WUNPCKELUW,
+ ARM_BUILTIN_THREAD_POINTER,
+
ARM_BUILTIN_MAX
};
#endif /* ! GCC_ARM_H */
diff --git a/contrib/gcc/config/arm/arm.md b/contrib/gcc/config/arm/arm.md
index 0a5e647..b28e3d0 100644
--- a/contrib/gcc/config/arm/arm.md
+++ b/contrib/gcc/config/arm/arm.md
@@ -1,6 +1,6 @@
;;- Machine description for ARM for GNU compiler
;; Copyright 1991, 1993, 1994, 1995, 1996, 1996, 1997, 1998, 1999, 2000,
-;; 2001, 2002, 2003 2004 Free Software Foundation, Inc.
+;; 2001, 2002, 2003, 2004, 2005, 2006 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).
@@ -19,8 +19,8 @@
;; 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, 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
@@ -30,12 +30,15 @@
;; Register numbers
(define_constants
- [(IP_REGNUM 12) ; Scratch register
+ [(R0_REGNUM 0) ; First CORE register
+ (IP_REGNUM 12) ; Scratch register
(SP_REGNUM 13) ; Stack pointer
(LR_REGNUM 14) ; Return address register
(PC_REGNUM 15) ; Program counter
(CC_REGNUM 24) ; Condition code pseudo register
- (LAST_ARM_REGNUM 15)
+ (LAST_ARM_REGNUM 15) ;
+ (FPA_F0_REGNUM 16) ; FIRST_FPA_REGNUM
+ (FPA_F7_REGNUM 23) ; LAST_FPA_REGNUM
]
)
;; 3rd operand to select_dominance_cc_mode
@@ -87,6 +90,9 @@
(UNSPEC_CLRDI 17) ; Used by the intrinsic form of the iWMMXt CLRDI instruction.
(UNSPEC_WMADDS 18) ; Used by the intrinsic form of the iWMMXt WMADDS instruction.
(UNSPEC_WMADDU 19) ; Used by the intrinsic form of the iWMMXt WMADDU instruction.
+ (UNSPEC_TLS 20) ; A symbol that has been treated properly for TLS usage.
+ (UNSPEC_PIC_LABEL 21) ; A label used for PIC access that does not appear in the
+ ; instruction stream.
]
)
@@ -117,6 +123,8 @@
(VUNSPEC_WCMP_EQ 11) ; Used by the iWMMXt WCMPEQ instructions
(VUNSPEC_WCMP_GTU 12) ; Used by the iWMMXt WCMPGTU instructions
(VUNSPEC_WCMP_GT 13) ; Used by the iwMMXT WCMPGT instructions
+ (VUNSPEC_EH_RETURN 20); Use to override the return address for exception
+ ; handling.
]
)
@@ -128,24 +136,21 @@
; patterns that share the same RTL in both ARM and Thumb code.
(define_attr "is_thumb" "no,yes" (const (symbol_ref "thumb_code")))
-; PROG_MODE attribute is used to determine whether condition codes are
-; clobbered by a call insn: they are if in prog32 mode. This is controlled
-; by the -mapcs-{32,26} flag, and possibly the -mcpu=... option.
-(define_attr "prog_mode" "prog26,prog32" (const (symbol_ref "arm_prog_mode")))
-
; IS_STRONGARM is set to 'yes' when compiling for StrongARM, it affects
; scheduling decisions for the load unit and the multiplier.
-(define_attr "is_strongarm" "no,yes" (const (symbol_ref "arm_is_strong")))
+(define_attr "is_strongarm" "no,yes" (const (symbol_ref "arm_tune_strongarm")))
+
+; IS_XSCALE is set to 'yes' when compiling for XScale.
+(define_attr "is_xscale" "no,yes" (const (symbol_ref "arm_tune_xscale")))
;; Operand number of an input operand that is shifted. Zero if the
;; given instruction does not shift one of its input operands.
-(define_attr "is_xscale" "no,yes" (const (symbol_ref "arm_tune_xscale")))
(define_attr "shift" "" (const_int 0))
; Floating Point Unit. If we only have floating point emulation, then there
; is no point in scheduling the floating point insns. (Well, for best
; performance we should try and group them together).
-(define_attr "fpu" "softfpa,fpa,fpe2,fpe3,maverick"
+(define_attr "fpu" "none,fpa,fpe2,fpe3,maverick,vfp"
(const (symbol_ref "arm_fpu_attr")))
; LENGTH of an instruction (in bytes)
@@ -167,13 +172,26 @@
(set_attr "length" "4")
(set_attr "pool_range" "250")])
+;; The instruction used to implement a particular pattern. This
+;; information is used by pipeline descriptions to provide accurate
+;; scheduling information.
+
+(define_attr "insn"
+ "smulxy,smlaxy,smlalxy,smulwy,smlawx,mul,muls,mla,mlas,umull,umulls,umlal,umlals,smull,smulls,smlal,smlals,smlawy,smuad,smuadx,smlad,smladx,smusd,smusdx,smlsd,smlsdx,smmul,smmulr,other"
+ (const_string "other"))
+
; TYPE attribute is used to detect floating point instructions which, if
; running on a co-processor can run in parallel with other, basic instructions
; If write-buffer scheduling is enabled then it can also be used in the
; scheduling of writes.
; Classification of each insn
-; normal any data instruction that doesn't hit memory or fp regs
+; alu any alu instruction that doesn't hit memory or fp
+; regs or have a shifted source operand
+; alu_shift any data instruction that doesn't hit memory or fp
+; regs, but has a source operand shifted by a constant
+; alu_shift_reg any data instruction that doesn't hit memory or fp
+; regs, but has a source operand shifted by a register value
; mult a multiply instruction
; block blockage insn, this blocks all functional units
; float a floating point arithmetic operation (subject to expansion)
@@ -187,23 +205,35 @@
; even on a machine with an fpa.
; f_load a floating point load from memory
; f_store a floating point store to memory
+; f_load[sd] single/double load from memory
+; f_store[sd] single/double store to memory
+; f_flag a transfer of co-processor flags to the CPSR
; f_mem_r a transfer of a floating point register to a real reg via mem
; r_mem_f the reverse of f_mem_r
; f_2_r fast transfer float to arm (no memory needed)
; r_2_f fast transfer arm to float
+; f_cvt convert floating<->integral
+; branch a branch
; call a subroutine call
-; load any load from memory
-; store1 store 1 word to memory from arm registers
+; load_byte load byte(s) from memory to arm registers
+; load1 load 1 word from memory to arm registers
+; load2 load 2 words from memory to arm registers
+; load3 load 3 words from memory to arm registers
+; load4 load 4 words from memory to arm registers
+; store store 1 word to memory from arm registers
; store2 store 2 words
; store3 store 3 words
-; store4 store 4 words
+; store4 store 4 (or more) words
; Additions for Cirrus Maverick co-processor:
; mav_farith Floating point arithmetic (4 cycle)
; mav_dmult Double multiplies (7 cycle)
;
(define_attr "type"
- "normal,mult,block,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith,float_em,f_load,f_store,f_mem_r,r_mem_f,f_2_r,r_2_f,call,load,store1,store2,store3,store4,mav_farith,mav_dmult"
- (const_string "normal"))
+ "alu,alu_shift,alu_shift_reg,mult,block,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith,f_flag,float_em,f_load,f_store,f_loads,f_loadd,f_stores,f_stored,f_mem_r,r_mem_f,f_2_r,r_2_f,f_cvt,branch,call,load_byte,load1,load2,load3,load4,store1,store2,store3,store4,mav_farith,mav_dmult"
+ (if_then_else
+ (eq_attr "insn" "smulxy,smlaxy,smlalxy,smulwy,smlawx,mul,muls,mla,mlas,umull,umulls,umlal,umlals,smull,smulls,smlal,smlals")
+ (const_string "mult")
+ (const_string "alu")))
; Load scheduling, set from the arm_ld_sched variable
; initialized by arm_override_options()
@@ -231,8 +261,7 @@
(define_attr "conds" "use,set,clob,jump_clob,nocond"
(if_then_else (eq_attr "type" "call")
- (if_then_else (eq_attr "prog_mode" "prog32")
- (const_string "clob") (const_string "nocond"))
+ (const_string "clob")
(const_string "nocond")))
; Predicable means that the insn can be conditionally executed based on
@@ -245,13 +274,13 @@
; have one. Later ones, such as StrongARM, have write-back caches, so don't
; suffer blockages enough to warrant modelling this (and it can adversely
; affect the schedule).
-(define_attr "model_wbuf" "no,yes" (const (symbol_ref "arm_is_6_or_7")))
+(define_attr "model_wbuf" "no,yes" (const (symbol_ref "arm_tune_wbuf")))
; WRITE_CONFLICT implies that a read following an unrelated write is likely
; to stall the processor. Used with model_wbuf above.
(define_attr "write_conflict" "no,yes"
(if_then_else (eq_attr "type"
- "block,float_em,f_load,f_store,f_mem_r,r_mem_f,call,load")
+ "block,float_em,f_load,f_store,f_mem_r,r_mem_f,call,load1")
(const_string "yes")
(const_string "no")))
@@ -259,7 +288,7 @@
; than one on the main cpu execution unit.
(define_attr "core_cycles" "single,multi"
(if_then_else (eq_attr "type"
- "normal,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith")
+ "alu,alu_shift,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith")
(const_string "single")
(const_string "multi")))
@@ -267,115 +296,47 @@
;; distant label. Only applicable to Thumb code.
(define_attr "far_jump" "yes,no" (const_string "no"))
-(define_automaton "arm")
-;; Write buffer
-;
-; Strictly, we should model a 4-deep write buffer for ARM7xx based chips
-;
-; The write buffer on some of the arm6 processors is hard to model exactly.
-; There is room in the buffer for up to two addresses and up to eight words
-; of memory, but the two needn't be split evenly. When writing the two
-; addresses are fully pipelined. However, a read from memory that is not
-; currently in the cache will block until the writes have completed.
-; It is normally the case that FCLK and MCLK will be in the ratio 2:1, so
-; writes will take 2 FCLK cycles per word, if FCLK and MCLK are asynchronous
-; (they aren't allowed to be at present) then there is a startup cost of 1MCLK
-; cycle to add as well.
-(define_cpu_unit "write_buf" "arm")
-
-;; Write blockage unit
-;
-; The write_blockage unit models (partially), the fact that reads will stall
-; until the write buffer empties.
-; The f_mem_r and r_mem_f could also block, but they are to the stack,
-; so we don't model them here
-(define_cpu_unit "write_blockage" "arm")
+;;---------------------------------------------------------------------------
+;; Mode macros
-;; Core
-;
-(define_cpu_unit "core" "arm")
-
-(define_insn_reservation "r_mem_f_wbuf" 5
- (and (eq_attr "model_wbuf" "yes")
- (eq_attr "type" "r_mem_f"))
- "core+write_buf*3")
-
-(define_insn_reservation "store1_wbuf" 5
- (and (eq_attr "model_wbuf" "yes")
- (eq_attr "type" "store1"))
- "core+write_buf*3+write_blockage*5")
-
-(define_insn_reservation "store2_wbuf" 7
- (and (eq_attr "model_wbuf" "yes")
- (eq_attr "type" "store2"))
- "core+write_buf*4+write_blockage*7")
-
-(define_insn_reservation "store3_wbuf" 9
- (and (eq_attr "model_wbuf" "yes")
- (eq_attr "type" "store3"))
- "core+write_buf*5+write_blockage*9")
-
-(define_insn_reservation "store4_wbuf" 11
- (and (eq_attr "model_wbuf" "yes")
- (eq_attr "type" "store4"))
- "core+write_buf*6+write_blockage*11")
-
-(define_insn_reservation "store2" 3
- (and (eq_attr "model_wbuf" "no")
- (eq_attr "type" "store2"))
- "core*3")
-
-(define_insn_reservation "store3" 4
- (and (eq_attr "model_wbuf" "no")
- (eq_attr "type" "store3"))
- "core*4")
-
-(define_insn_reservation "store4" 5
- (and (eq_attr "model_wbuf" "no")
- (eq_attr "type" "store4"))
- "core*5")
-
-(define_insn_reservation "store1_ldsched" 1
- (and (eq_attr "ldsched" "yes") (eq_attr "type" "store1"))
- "core")
-
-(define_insn_reservation "load_ldsched_xscale" 3
- (and (and (eq_attr "ldsched" "yes") (eq_attr "type" "load"))
- (eq_attr "is_xscale" "yes"))
- "core")
-
-(define_insn_reservation "load_ldsched" 2
- (and (and (eq_attr "ldsched" "yes") (eq_attr "type" "load"))
- (eq_attr "is_xscale" "no"))
- "core")
-
-(define_insn_reservation "load_or_store" 2
- (and (eq_attr "ldsched" "!yes") (eq_attr "type" "load,store1"))
- "core*2")
-
-(define_insn_reservation "mult" 16
- (and (eq_attr "ldsched" "no") (eq_attr "type" "mult"))
- "core*16")
-
-(define_insn_reservation "mult_ldsched_strongarm" 3
- (and (and (eq_attr "ldsched" "yes") (eq_attr "is_strongarm" "yes"))
- (eq_attr "type" "mult"))
- "core*2")
-
-(define_insn_reservation "mult_ldsched" 4
- (and (and (eq_attr "ldsched" "yes") (eq_attr "is_strongarm" "no"))
- (eq_attr "type" "mult"))
- "core*4")
-
-(define_insn_reservation "multi_cycle" 32
- (and (eq_attr "core_cycles" "multi")
- (eq_attr "type" "!mult,load,store1,store2,store3,store4"))
- "core*32")
-
-(define_insn_reservation "single_cycle" 1
- (eq_attr "core_cycles" "single")
- "core")
+; A list of modes that are exactly 64 bits in size. We use this to expand
+; some splits that are the same for all modes when operating on ARM
+; registers.
+(define_mode_macro ANY64 [DI DF V8QI V4HI V2SI V2SF])
+
+;;---------------------------------------------------------------------------
+;; Predicates
+
+(include "predicates.md")
+(include "constraints.md")
+
+;;---------------------------------------------------------------------------
+;; Pipeline descriptions
+
+;; Processor type. This is created automatically from arm-cores.def.
+(include "arm-tune.md")
+
+;; True if the generic scheduling description should be used.
+
+(define_attr "generic_sched" "yes,no"
+ (const (if_then_else
+ (eq_attr "tune" "arm926ejs,arm1020e,arm1026ejs,arm1136js,arm1136jfs")
+ (const_string "no")
+ (const_string "yes"))))
+
+(define_attr "generic_vfp" "yes,no"
+ (const (if_then_else
+ (and (eq_attr "fpu" "vfp")
+ (eq_attr "tune" "!arm1020e,arm1022e"))
+ (const_string "yes")
+ (const_string "no"))))
+
+(include "arm-generic.md")
+(include "arm926ejs.md")
+(include "arm1020e.md")
+(include "arm1026ejs.md")
+(include "arm1136jfs.md")
;;---------------------------------------------------------------------------
@@ -397,7 +358,7 @@
(clobber (reg:CC CC_REGNUM))])]
"TARGET_EITHER"
"
- if (TARGET_CIRRUS)
+ if (TARGET_HARD_FLOAT && TARGET_MAVERICK)
{
if (!cirrus_fp_register (operands[0], DImode))
operands[0] = force_reg (DImode, operands[0]);
@@ -433,7 +394,7 @@
(plus:DI (match_operand:DI 1 "s_register_operand" "%0, 0")
(match_operand:DI 2 "s_register_operand" "r, 0")))
(clobber (reg:CC CC_REGNUM))]
- "TARGET_ARM && !TARGET_CIRRUS"
+ "TARGET_ARM && !(TARGET_HARD_FLOAT && TARGET_MAVERICK)"
"#"
"TARGET_ARM && reload_completed"
[(parallel [(set (reg:CC_C CC_REGNUM)
@@ -461,7 +422,7 @@
(match_operand:SI 2 "s_register_operand" "r,r"))
(match_operand:DI 1 "s_register_operand" "r,0")))
(clobber (reg:CC CC_REGNUM))]
- "TARGET_ARM && !TARGET_CIRRUS"
+ "TARGET_ARM && !(TARGET_HARD_FLOAT && TARGET_MAVERICK)"
"#"
"TARGET_ARM && reload_completed"
[(parallel [(set (reg:CC_C CC_REGNUM)
@@ -490,7 +451,7 @@
(match_operand:SI 2 "s_register_operand" "r,r"))
(match_operand:DI 1 "s_register_operand" "r,0")))
(clobber (reg:CC CC_REGNUM))]
- "TARGET_ARM && !TARGET_CIRRUS"
+ "TARGET_ARM && !(TARGET_HARD_FLOAT && TARGET_MAVERICK)"
"#"
"TARGET_ARM && reload_completed"
[(parallel [(set (reg:CC_C CC_REGNUM)
@@ -519,9 +480,9 @@
"
if (TARGET_ARM && GET_CODE (operands[2]) == CONST_INT)
{
- arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0],
- operands[1],
- (no_new_pseudos ? 0 : preserve_subexpressions_p ()));
+ arm_split_constant (PLUS, SImode, NULL_RTX,
+ INTVAL (operands[2]), operands[0], operands[1],
+ optimize && !no_new_pseudos);
DONE;
}
"
@@ -531,8 +492,8 @@
; addition.
(define_peephole2
[(match_scratch:SI 3 "r")
- (set (match_operand:SI 0 "s_register_operand" "")
- (plus:SI (match_operand:SI 1 "s_register_operand" "")
+ (set (match_operand:SI 0 "arm_general_register_operand" "")
+ (plus:SI (match_operand:SI 1 "arm_general_register_operand" "")
(match_operand:SI 2 "const_int_operand" "")))]
"TARGET_ARM &&
!(const_ok_for_arm (INTVAL (operands[2]))
@@ -558,7 +519,8 @@
|| const_ok_for_arm (-INTVAL (operands[2])))"
[(clobber (const_int 0))]
"
- arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0],
+ arm_split_constant (PLUS, SImode, curr_insn,
+ INTVAL (operands[2]), operands[0],
operands[1], 0);
DONE;
"
@@ -598,15 +560,14 @@
;; Reloading and elimination of the frame pointer can
;; sometimes cause this optimization to be missed.
(define_peephole2
- [(set (match_operand:SI 0 "register_operand" "")
+ [(set (match_operand:SI 0 "arm_general_register_operand" "")
(match_operand:SI 1 "const_int_operand" ""))
(set (match_dup 0)
- (plus:SI (match_dup 0) (match_operand:SI 2 "register_operand" "")))]
+ (plus:SI (match_dup 0) (reg:SI SP_REGNUM)))]
"TARGET_THUMB
- && REGNO (operands[2]) == STACK_POINTER_REGNUM
&& (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) < 1024
&& (INTVAL (operands[1]) & 3) == 0"
- [(set (match_dup 0) (plus:SI (match_dup 2) (match_dup 1)))]
+ [(set (match_dup 0) (plus:SI (reg:SI SP_REGNUM) (match_dup 1)))]
""
)
@@ -638,32 +599,13 @@
[(set_attr "conds" "set")]
)
-;; These patterns are the same ones as the two regular addsi3_compare0
-;; patterns, except we write them slightly different - the combiner
-;; tends to generate them this way.
-(define_insn "*addsi3_compare0_for_combiner"
- [(set (reg:CC CC_REGNUM)
- (compare:CC
- (match_operand:SI 1 "s_register_operand" "r,r")
- (neg:SI (match_operand:SI 2 "arm_add_operand" "rI,L"))))
- (set (match_operand:SI 0 "s_register_operand" "=r,r")
- (plus:SI (match_dup 1) (match_dup 2)))]
+(define_insn "*compare_negsi_si"
+ [(set (reg:CC_Z CC_REGNUM)
+ (compare:CC_Z
+ (neg:SI (match_operand:SI 0 "s_register_operand" "r"))
+ (match_operand:SI 1 "s_register_operand" "r")))]
"TARGET_ARM"
- "@
- add%?s\\t%0, %1, %2
- sub%?s\\t%0, %1, #%n2"
- [(set_attr "conds" "set")]
-)
-
-(define_insn "*addsi3_compare0_scratch_for_combiner"
- [(set (reg:CC CC_REGNUM)
- (compare:CC
- (match_operand:SI 0 "s_register_operand" "r,r")
- (neg:SI (match_operand:SI 1 "arm_add_operand" "rI,L"))))]
- "TARGET_ARM"
- "@
- cmn%?\\t%0, %1
- cmp%?\\t%0, #%n1"
+ "cmn%?\\t%1, %0"
[(set_attr "conds" "set")]
)
@@ -694,8 +636,8 @@
;; similarly for the beq variant using bcc.
;; This is a common looping idiom (while (n--))
(define_peephole2
- [(set (match_operand:SI 0 "s_register_operand" "")
- (plus:SI (match_operand:SI 1 "s_register_operand" "")
+ [(set (match_operand:SI 0 "arm_general_register_operand" "")
+ (plus:SI (match_operand:SI 1 "arm_general_register_operand" "")
(const_int -1)))
(set (match_operand 2 "cc_register" "")
(compare (match_dup 0) (const_int -1)))
@@ -801,7 +743,10 @@
(match_operand:SI 1 "s_register_operand" "r"))))]
"TARGET_ARM"
"adc%?\\t%0, %1, %3%S2"
- [(set_attr "conds" "use")]
+ [(set_attr "conds" "use")
+ (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "")
+ (const_string "alu_shift")
+ (const_string "alu_shift_reg")))]
)
(define_insn "*addsi3_carryin_alt1"
@@ -864,10 +809,10 @@
(define_expand "addsf3"
[(set (match_operand:SF 0 "s_register_operand" "")
(plus:SF (match_operand:SF 1 "s_register_operand" "")
- (match_operand:SF 2 "fpa_add_operand" "")))]
- "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
+ (match_operand:SF 2 "arm_float_add_operand" "")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT"
"
- if (TARGET_CIRRUS
+ if (TARGET_MAVERICK
&& !cirrus_fp_register (operands[2], SFmode))
operands[2] = force_reg (SFmode, operands[2]);
")
@@ -875,10 +820,10 @@
(define_expand "adddf3"
[(set (match_operand:DF 0 "s_register_operand" "")
(plus:DF (match_operand:DF 1 "s_register_operand" "")
- (match_operand:DF 2 "fpa_add_operand" "")))]
- "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
+ (match_operand:DF 2 "arm_float_add_operand" "")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT"
"
- if (TARGET_CIRRUS
+ if (TARGET_MAVERICK
&& !cirrus_fp_register (operands[2], DFmode))
operands[2] = force_reg (DFmode, operands[2]);
")
@@ -891,7 +836,7 @@
(clobber (reg:CC CC_REGNUM))])]
"TARGET_EITHER"
"
- if (TARGET_CIRRUS
+ if (TARGET_HARD_FLOAT && TARGET_MAVERICK
&& TARGET_ARM
&& cirrus_fp_register (operands[0], DImode)
&& cirrus_fp_register (operands[1], DImode))
@@ -1002,10 +947,9 @@
{
if (TARGET_ARM)
{
- arm_split_constant (MINUS, SImode, INTVAL (operands[1]), operands[0],
- operands[2],
- (no_new_pseudos ? 0
- : preserve_subexpressions_p ()));
+ arm_split_constant (MINUS, SImode, NULL_RTX,
+ INTVAL (operands[1]), operands[0],
+ operands[2], optimize && !no_new_pseudos);
DONE;
}
else /* TARGET_THUMB */
@@ -1036,8 +980,8 @@
&& !const_ok_for_arm (INTVAL (operands[1]))"
[(clobber (const_int 0))]
"
- arm_split_constant (MINUS, SImode, INTVAL (operands[1]), operands[0],
- operands[2], 0);
+ arm_split_constant (MINUS, SImode, curr_insn,
+ INTVAL (operands[1]), operands[0], operands[2], 0);
DONE;
"
[(set_attr "length" "4,16")
@@ -1046,9 +990,9 @@
(define_peephole2
[(match_scratch:SI 3 "r")
- (set (match_operand:SI 0 "s_register_operand" "")
+ (set (match_operand:SI 0 "arm_general_register_operand" "")
(minus:SI (match_operand:SI 1 "const_int_operand" "")
- (match_operand:SI 2 "s_register_operand" "")))]
+ (match_operand:SI 2 "arm_general_register_operand" "")))]
"TARGET_ARM
&& !const_ok_for_arm (INTVAL (operands[1]))
&& const_ok_for_arm (~INTVAL (operands[1]))"
@@ -1087,11 +1031,11 @@
(define_expand "subsf3"
[(set (match_operand:SF 0 "s_register_operand" "")
- (minus:SF (match_operand:SF 1 "fpa_rhs_operand" "")
- (match_operand:SF 2 "fpa_rhs_operand" "")))]
- "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
+ (minus:SF (match_operand:SF 1 "arm_float_rhs_operand" "")
+ (match_operand:SF 2 "arm_float_rhs_operand" "")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT"
"
- if (TARGET_CIRRUS)
+ if (TARGET_MAVERICK)
{
if (!cirrus_fp_register (operands[1], SFmode))
operands[1] = force_reg (SFmode, operands[1]);
@@ -1102,11 +1046,11 @@
(define_expand "subdf3"
[(set (match_operand:DF 0 "s_register_operand" "")
- (minus:DF (match_operand:DF 1 "fpa_rhs_operand" "")
- (match_operand:DF 2 "fpa_rhs_operand" "")))]
- "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
+ (minus:DF (match_operand:DF 1 "arm_float_rhs_operand" "")
+ (match_operand:DF 2 "arm_float_rhs_operand" "")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT"
"
- if (TARGET_CIRRUS)
+ if (TARGET_MAVERICK)
{
if (!cirrus_fp_register (operands[1], DFmode))
operands[1] = force_reg (DFmode, operands[1]);
@@ -1133,7 +1077,7 @@
(match_operand:SI 1 "s_register_operand" "%?r,0")))]
"TARGET_ARM"
"mul%?\\t%0, %2, %1"
- [(set_attr "type" "mult")
+ [(set_attr "insn" "mul")
(set_attr "predicable" "yes")]
)
@@ -1149,12 +1093,12 @@
"TARGET_THUMB"
"*
if (which_alternative < 2)
- return \"mov\\t%0, %1\;mul\\t%0, %0, %2\";
+ return \"mov\\t%0, %1\;mul\\t%0, %2\";
else
- return \"mul\\t%0, %0, %2\";
+ return \"mul\\t%0, %2\";
"
[(set_attr "length" "4,4,2")
- (set_attr "type" "mult")]
+ (set_attr "insn" "mul")]
)
(define_insn "*mulsi3_compare0"
@@ -1165,10 +1109,10 @@
(const_int 0)))
(set (match_operand:SI 0 "s_register_operand" "=&r,&r")
(mult:SI (match_dup 2) (match_dup 1)))]
- "TARGET_ARM && !arm_arch_xscale"
+ "TARGET_ARM"
"mul%?s\\t%0, %2, %1"
[(set_attr "conds" "set")
- (set_attr "type" "mult")]
+ (set_attr "insn" "muls")]
)
(define_insn "*mulsi_compare0_scratch"
@@ -1178,10 +1122,10 @@
(match_operand:SI 1 "s_register_operand" "%?r,0"))
(const_int 0)))
(clobber (match_scratch:SI 0 "=&r,&r"))]
- "TARGET_ARM && !arm_arch_xscale"
+ "TARGET_ARM"
"mul%?s\\t%0, %2, %1"
[(set_attr "conds" "set")
- (set_attr "type" "mult")]
+ (set_attr "insn" "muls")]
)
;; Unnamed templates to match MLA instruction.
@@ -1194,7 +1138,7 @@
(match_operand:SI 3 "s_register_operand" "?r,r,0,0")))]
"TARGET_ARM"
"mla%?\\t%0, %2, %1, %3"
- [(set_attr "type" "mult")
+ [(set_attr "insn" "mla")
(set_attr "predicable" "yes")]
)
@@ -1209,10 +1153,10 @@
(set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r,&r")
(plus:SI (mult:SI (match_dup 2) (match_dup 1))
(match_dup 3)))]
- "TARGET_ARM && !arm_arch_xscale"
+ "TARGET_ARM"
"mla%?s\\t%0, %2, %1, %3"
[(set_attr "conds" "set")
- (set_attr "type" "mult")]
+ (set_attr "insn" "mlas")]
)
(define_insn "*mulsi3addsi_compare0_scratch"
@@ -1224,10 +1168,10 @@
(match_operand:SI 3 "s_register_operand" "?r,r,0,0"))
(const_int 0)))
(clobber (match_scratch:SI 0 "=&r,&r,&r,&r"))]
- "TARGET_ARM && !arm_arch_xscale"
+ "TARGET_ARM"
"mla%?s\\t%0, %2, %1, %3"
[(set_attr "conds" "set")
- (set_attr "type" "mult")]
+ (set_attr "insn" "mlas")]
)
;; Unnamed template to match long long multiply-accumulate (smlal)
@@ -1239,9 +1183,9 @@
(sign_extend:DI (match_operand:SI 2 "s_register_operand" "%r"))
(sign_extend:DI (match_operand:SI 3 "s_register_operand" "r")))
(match_operand:DI 1 "s_register_operand" "0")))]
- "TARGET_ARM && arm_fast_multiply"
+ "TARGET_ARM && arm_arch3m"
"smlal%?\\t%Q0, %R0, %3, %2"
- [(set_attr "type" "mult")
+ [(set_attr "insn" "smlal")
(set_attr "predicable" "yes")]
)
@@ -1250,9 +1194,9 @@
(mult:DI
(sign_extend:DI (match_operand:SI 1 "s_register_operand" "%r"))
(sign_extend:DI (match_operand:SI 2 "s_register_operand" "r"))))]
- "TARGET_ARM && arm_fast_multiply"
+ "TARGET_ARM && arm_arch3m"
"smull%?\\t%Q0, %R0, %1, %2"
- [(set_attr "type" "mult")
+ [(set_attr "insn" "smull")
(set_attr "predicable" "yes")]
)
@@ -1261,9 +1205,9 @@
(mult:DI
(zero_extend:DI (match_operand:SI 1 "s_register_operand" "%r"))
(zero_extend:DI (match_operand:SI 2 "s_register_operand" "r"))))]
- "TARGET_ARM && arm_fast_multiply"
+ "TARGET_ARM && arm_arch3m"
"umull%?\\t%Q0, %R0, %1, %2"
- [(set_attr "type" "mult")
+ [(set_attr "insn" "umull")
(set_attr "predicable" "yes")]
)
@@ -1276,9 +1220,9 @@
(zero_extend:DI (match_operand:SI 2 "s_register_operand" "%r"))
(zero_extend:DI (match_operand:SI 3 "s_register_operand" "r")))
(match_operand:DI 1 "s_register_operand" "0")))]
- "TARGET_ARM && arm_fast_multiply"
+ "TARGET_ARM && arm_arch3m"
"umlal%?\\t%Q0, %R0, %3, %2"
- [(set_attr "type" "mult")
+ [(set_attr "insn" "umlal")
(set_attr "predicable" "yes")]
)
@@ -1291,9 +1235,9 @@
(sign_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")))
(const_int 32))))
(clobber (match_scratch:SI 3 "=&r,&r"))]
- "TARGET_ARM && arm_fast_multiply"
+ "TARGET_ARM && arm_arch3m"
"smull%?\\t%3, %0, %2, %1"
- [(set_attr "type" "mult")
+ [(set_attr "insn" "smull")
(set_attr "predicable" "yes")]
)
@@ -1306,9 +1250,9 @@
(zero_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")))
(const_int 32))))
(clobber (match_scratch:SI 3 "=&r,&r"))]
- "TARGET_ARM && arm_fast_multiply"
+ "TARGET_ARM && arm_arch3m"
"umull%?\\t%3, %0, %2, %1"
- [(set_attr "type" "mult")
+ [(set_attr "insn" "umull")
(set_attr "predicable" "yes")]
)
@@ -1320,7 +1264,7 @@
(match_operand:HI 2 "s_register_operand" "r"))))]
"TARGET_ARM && arm_arch5e"
"smulbb%?\\t%0, %1, %2"
- [(set_attr "type" "mult")
+ [(set_attr "insn" "smulxy")
(set_attr "predicable" "yes")]
)
@@ -1333,7 +1277,7 @@
(match_operand:HI 2 "s_register_operand" "r"))))]
"TARGET_ARM && arm_arch5e"
"smultb%?\\t%0, %1, %2"
- [(set_attr "type" "mult")
+ [(set_attr "insn" "smulxy")
(set_attr "predicable" "yes")]
)
@@ -1346,7 +1290,7 @@
(const_int 16))))]
"TARGET_ARM && arm_arch5e"
"smulbt%?\\t%0, %1, %2"
- [(set_attr "type" "mult")
+ [(set_attr "insn" "smulxy")
(set_attr "predicable" "yes")]
)
@@ -1360,7 +1304,7 @@
(const_int 16))))]
"TARGET_ARM && arm_arch5e"
"smultt%?\\t%0, %1, %2"
- [(set_attr "type" "mult")
+ [(set_attr "insn" "smulxy")
(set_attr "predicable" "yes")]
)
@@ -1373,7 +1317,7 @@
(match_operand:HI 3 "s_register_operand" "r")))))]
"TARGET_ARM && arm_arch5e"
"smlabb%?\\t%0, %2, %3, %1"
- [(set_attr "type" "mult")
+ [(set_attr "insn" "smlaxy")
(set_attr "predicable" "yes")]
)
@@ -1387,16 +1331,16 @@
(match_operand:HI 3 "s_register_operand" "r")))))]
"TARGET_ARM && arm_arch5e"
"smlalbb%?\\t%Q0, %R0, %2, %3"
- [(set_attr "type" "mult")
+ [(set_attr "insn" "smlalxy")
(set_attr "predicable" "yes")])
(define_expand "mulsf3"
[(set (match_operand:SF 0 "s_register_operand" "")
(mult:SF (match_operand:SF 1 "s_register_operand" "")
- (match_operand:SF 2 "fpa_rhs_operand" "")))]
- "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
+ (match_operand:SF 2 "arm_float_rhs_operand" "")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT"
"
- if (TARGET_CIRRUS
+ if (TARGET_MAVERICK
&& !cirrus_fp_register (operands[2], SFmode))
operands[2] = force_reg (SFmode, operands[2]);
")
@@ -1404,10 +1348,10 @@
(define_expand "muldf3"
[(set (match_operand:DF 0 "s_register_operand" "")
(mult:DF (match_operand:DF 1 "s_register_operand" "")
- (match_operand:DF 2 "fpa_rhs_operand" "")))]
- "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
+ (match_operand:DF 2 "arm_float_rhs_operand" "")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT"
"
- if (TARGET_CIRRUS
+ if (TARGET_MAVERICK
&& !cirrus_fp_register (operands[2], DFmode))
operands[2] = force_reg (DFmode, operands[2]);
")
@@ -1416,16 +1360,16 @@
(define_expand "divsf3"
[(set (match_operand:SF 0 "s_register_operand" "")
- (div:SF (match_operand:SF 1 "fpa_rhs_operand" "")
- (match_operand:SF 2 "fpa_rhs_operand" "")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (div:SF (match_operand:SF 1 "arm_float_rhs_operand" "")
+ (match_operand:SF 2 "arm_float_rhs_operand" "")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"")
(define_expand "divdf3"
[(set (match_operand:DF 0 "s_register_operand" "")
- (div:DF (match_operand:DF 1 "fpa_rhs_operand" "")
- (match_operand:DF 2 "fpa_rhs_operand" "")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (div:DF (match_operand:DF 1 "arm_float_rhs_operand" "")
+ (match_operand:DF 2 "arm_float_rhs_operand" "")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"")
;; Modulo insns
@@ -1433,15 +1377,15 @@
(define_expand "modsf3"
[(set (match_operand:SF 0 "s_register_operand" "")
(mod:SF (match_operand:SF 1 "s_register_operand" "")
- (match_operand:SF 2 "fpa_rhs_operand" "")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (match_operand:SF 2 "arm_float_rhs_operand" "")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"")
(define_expand "moddf3"
[(set (match_operand:DF 0 "s_register_operand" "")
(mod:DF (match_operand:DF 1 "s_register_operand" "")
- (match_operand:DF 2 "fpa_rhs_operand" "")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (match_operand:DF 2 "arm_float_rhs_operand" "")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"")
;; Boolean and,ior,xor insns
@@ -1578,10 +1522,10 @@
{
if (GET_CODE (operands[2]) == CONST_INT)
{
- arm_split_constant (AND, SImode, INTVAL (operands[2]), operands[0],
- operands[1],
- (no_new_pseudos
- ? 0 : preserve_subexpressions_p ()));
+ arm_split_constant (AND, SImode, NULL_RTX,
+ INTVAL (operands[2]), operands[0],
+ operands[1], optimize && !no_new_pseudos);
+
DONE;
}
}
@@ -1645,8 +1589,8 @@
|| const_ok_for_arm (~INTVAL (operands[2])))"
[(clobber (const_int 0))]
"
- arm_split_constant (AND, SImode, INTVAL (operands[2]), operands[0],
- operands[1], 0);
+ arm_split_constant (AND, SImode, curr_insn,
+ INTVAL (operands[2]), operands[0], operands[1], 0);
DONE;
"
[(set_attr "length" "4,4,16")
@@ -1712,7 +1656,7 @@
[(set_attr "conds" "set")]
)
-(define_insn "*ne_zeroextractsi"
+(define_insn_and_split "*ne_zeroextractsi"
[(set (match_operand:SI 0 "s_register_operand" "=r")
(ne:SI (zero_extract:SI
(match_operand:SI 1 "s_register_operand" "r")
@@ -1725,11 +1669,112 @@
&& INTVAL (operands[2]) > 0
&& INTVAL (operands[2]) + (INTVAL (operands[3]) & 1) <= 8
&& INTVAL (operands[2]) + INTVAL (operands[3]) <= 32)"
- "*
+ "#"
+ "TARGET_ARM
+ && (INTVAL (operands[3]) >= 0 && INTVAL (operands[3]) < 32
+ && INTVAL (operands[2]) > 0
+ && INTVAL (operands[2]) + (INTVAL (operands[3]) & 1) <= 8
+ && INTVAL (operands[2]) + INTVAL (operands[3]) <= 32)"
+ [(parallel [(set (reg:CC_NOOV CC_REGNUM)
+ (compare:CC_NOOV (and:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))
+ (set (match_dup 0) (and:SI (match_dup 1) (match_dup 2)))])
+ (set (match_dup 0)
+ (if_then_else:SI (eq (reg:CC_NOOV CC_REGNUM) (const_int 0))
+ (match_dup 0) (const_int 1)))]
+ "
operands[2] = GEN_INT (((1 << INTVAL (operands[2])) - 1)
- << INTVAL (operands[3]));
- output_asm_insn (\"ands\\t%0, %1, %2\", operands);
- return \"movne\\t%0, #1\";
+ << INTVAL (operands[3]));
+ "
+ [(set_attr "conds" "clob")
+ (set_attr "length" "8")]
+)
+
+(define_insn_and_split "*ne_zeroextractsi_shifted"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (ne:SI (zero_extract:SI
+ (match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "const_int_operand" "n")
+ (const_int 0))
+ (const_int 0)))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_ARM"
+ "#"
+ "TARGET_ARM"
+ [(parallel [(set (reg:CC_NOOV CC_REGNUM)
+ (compare:CC_NOOV (ashift:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))
+ (set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))])
+ (set (match_dup 0)
+ (if_then_else:SI (eq (reg:CC_NOOV CC_REGNUM) (const_int 0))
+ (match_dup 0) (const_int 1)))]
+ "
+ operands[2] = GEN_INT (32 - INTVAL (operands[2]));
+ "
+ [(set_attr "conds" "clob")
+ (set_attr "length" "8")]
+)
+
+(define_insn_and_split "*ite_ne_zeroextractsi"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (if_then_else:SI (ne (zero_extract:SI
+ (match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "const_int_operand" "n")
+ (match_operand:SI 3 "const_int_operand" "n"))
+ (const_int 0))
+ (match_operand:SI 4 "arm_not_operand" "rIK")
+ (const_int 0)))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_ARM
+ && (INTVAL (operands[3]) >= 0 && INTVAL (operands[3]) < 32
+ && INTVAL (operands[2]) > 0
+ && INTVAL (operands[2]) + (INTVAL (operands[3]) & 1) <= 8
+ && INTVAL (operands[2]) + INTVAL (operands[3]) <= 32)
+ && !reg_overlap_mentioned_p (operands[0], operands[4])"
+ "#"
+ "TARGET_ARM
+ && (INTVAL (operands[3]) >= 0 && INTVAL (operands[3]) < 32
+ && INTVAL (operands[2]) > 0
+ && INTVAL (operands[2]) + (INTVAL (operands[3]) & 1) <= 8
+ && INTVAL (operands[2]) + INTVAL (operands[3]) <= 32)
+ && !reg_overlap_mentioned_p (operands[0], operands[4])"
+ [(parallel [(set (reg:CC_NOOV CC_REGNUM)
+ (compare:CC_NOOV (and:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))
+ (set (match_dup 0) (and:SI (match_dup 1) (match_dup 2)))])
+ (set (match_dup 0)
+ (if_then_else:SI (eq (reg:CC_NOOV CC_REGNUM) (const_int 0))
+ (match_dup 0) (match_dup 4)))]
+ "
+ operands[2] = GEN_INT (((1 << INTVAL (operands[2])) - 1)
+ << INTVAL (operands[3]));
+ "
+ [(set_attr "conds" "clob")
+ (set_attr "length" "8")]
+)
+
+(define_insn_and_split "*ite_ne_zeroextractsi_shifted"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (if_then_else:SI (ne (zero_extract:SI
+ (match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "const_int_operand" "n")
+ (const_int 0))
+ (const_int 0))
+ (match_operand:SI 3 "arm_not_operand" "rIK")
+ (const_int 0)))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_ARM && !reg_overlap_mentioned_p (operands[0], operands[3])"
+ "#"
+ "TARGET_ARM && !reg_overlap_mentioned_p (operands[0], operands[3])"
+ [(parallel [(set (reg:CC_NOOV CC_REGNUM)
+ (compare:CC_NOOV (ashift:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))
+ (set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))])
+ (set (match_dup 0)
+ (if_then_else:SI (eq (reg:CC_NOOV CC_REGNUM) (const_int 0))
+ (match_dup 0) (match_dup 3)))]
+ "
+ operands[2] = GEN_INT (32 - INTVAL (operands[2]));
"
[(set_attr "conds" "clob")
(set_attr "length" "8")]
@@ -1860,9 +1905,10 @@
HOST_WIDE_INT op3_value = mask & INTVAL (operands[3]);
HOST_WIDE_INT mask2 = ((mask & ~op3_value) << start_bit);
- emit_insn (gen_andsi3 (op1, operands[0], GEN_INT (~mask2)));
+ emit_insn (gen_andsi3 (op1, operands[0],
+ gen_int_mode (~mask2, SImode)));
emit_insn (gen_iorsi3 (subtarget, op1,
- GEN_INT (op3_value << start_bit)));
+ gen_int_mode (op3_value << start_bit, SImode)));
}
else if (start_bit == 0
&& !(const_ok_for_arm (mask)
@@ -1898,7 +1944,7 @@
}
else
{
- rtx op0 = GEN_INT (mask);
+ rtx op0 = gen_int_mode (mask, SImode);
rtx op1 = gen_reg_rtx (SImode);
rtx op2 = gen_reg_rtx (SImode);
@@ -1917,7 +1963,7 @@
&& (const_ok_for_arm (mask << start_bit)
|| const_ok_for_arm (~(mask << start_bit))))
{
- op0 = GEN_INT (~(mask << start_bit));
+ op0 = gen_int_mode (~(mask << start_bit), SImode);
emit_insn (gen_andsi3 (op2, operands[0], op0));
}
else
@@ -2048,16 +2094,18 @@
)
(define_insn "andsi_not_shiftsi_si"
- [(set (match_operand:SI 0 "s_register_operand" "=r")
- (and:SI (not:SI (match_operator:SI 4 "shift_operator"
- [(match_operand:SI 2 "s_register_operand" "r")
- (match_operand:SI 3 "arm_rhs_operand" "rM")]))
- (match_operand:SI 1 "s_register_operand" "r")))]
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (and:SI (not:SI (match_operator:SI 4 "shift_operator"
+ [(match_operand:SI 2 "s_register_operand" "r")
+ (match_operand:SI 3 "arm_rhs_operand" "rM")]))
+ (match_operand:SI 1 "s_register_operand" "r")))]
"TARGET_ARM"
"bic%?\\t%0, %1, %2%S4"
[(set_attr "predicable" "yes")
(set_attr "shift" "2")
- ]
+ (set (attr "type") (if_then_else (match_operand 3 "const_int_operand" "")
+ (const_string "alu_shift")
+ (const_string "alu_shift_reg")))]
)
(define_insn "*andsi_notsi_si_compare0"
@@ -2129,10 +2177,9 @@
{
if (TARGET_ARM)
{
- arm_split_constant (IOR, SImode, INTVAL (operands[2]), operands[0],
- operands[1],
- (no_new_pseudos
- ? 0 : preserve_subexpressions_p ()));
+ arm_split_constant (IOR, SImode, NULL_RTX,
+ INTVAL (operands[2]), operands[0], operands[1],
+ optimize && !no_new_pseudos);
DONE;
}
else /* TARGET_THUMB */
@@ -2154,8 +2201,8 @@
&& !const_ok_for_arm (INTVAL (operands[2]))"
[(clobber (const_int 0))]
"
- arm_split_constant (IOR, SImode, INTVAL (operands[2]), operands[0],
- operands[1], 0);
+ arm_split_constant (IOR, SImode, curr_insn,
+ INTVAL (operands[2]), operands[0], operands[1], 0);
DONE;
"
[(set_attr "length" "4,16")
@@ -2173,8 +2220,8 @@
(define_peephole2
[(match_scratch:SI 3 "r")
- (set (match_operand:SI 0 "s_register_operand" "")
- (ior:SI (match_operand:SI 1 "s_register_operand" "")
+ (set (match_operand:SI 0 "arm_general_register_operand" "")
+ (ior:SI (match_operand:SI 1 "arm_general_register_operand" "")
(match_operand:SI 2 "const_int_operand" "")))]
"TARGET_ARM
&& !const_ok_for_arm (INTVAL (operands[2]))
@@ -2427,32 +2474,93 @@
;; Minimum and maximum insns
-(define_insn "smaxsi3"
- [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
- (smax:SI (match_operand:SI 1 "s_register_operand" "0,r,?r")
- (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))
+(define_expand "smaxsi3"
+ [(parallel [
+ (set (match_operand:SI 0 "s_register_operand" "")
+ (smax:SI (match_operand:SI 1 "s_register_operand" "")
+ (match_operand:SI 2 "arm_rhs_operand" "")))
+ (clobber (reg:CC CC_REGNUM))])]
+ "TARGET_ARM"
+ "
+ if (operands[2] == const0_rtx || operands[2] == constm1_rtx)
+ {
+ /* No need for a clobber of the condition code register here. */
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+ gen_rtx_SMAX (SImode, operands[1],
+ operands[2])));
+ DONE;
+ }
+")
+
+(define_insn "*smax_0"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (smax:SI (match_operand:SI 1 "s_register_operand" "r")
+ (const_int 0)))]
+ "TARGET_ARM"
+ "bic%?\\t%0, %1, %1, asr #31"
+ [(set_attr "predicable" "yes")]
+)
+
+(define_insn "*smax_m1"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (smax:SI (match_operand:SI 1 "s_register_operand" "r")
+ (const_int -1)))]
+ "TARGET_ARM"
+ "orr%?\\t%0, %1, %1, asr #31"
+ [(set_attr "predicable" "yes")]
+)
+
+(define_insn "*smax_insn"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (smax:SI (match_operand:SI 1 "s_register_operand" "%0,?r")
+ (match_operand:SI 2 "arm_rhs_operand" "rI,rI")))
(clobber (reg:CC CC_REGNUM))]
"TARGET_ARM"
"@
cmp\\t%1, %2\;movlt\\t%0, %2
- cmp\\t%1, %2\;movge\\t%0, %1
cmp\\t%1, %2\;movge\\t%0, %1\;movlt\\t%0, %2"
[(set_attr "conds" "clob")
- (set_attr "length" "8,8,12")]
+ (set_attr "length" "8,12")]
)
-(define_insn "sminsi3"
- [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
- (smin:SI (match_operand:SI 1 "s_register_operand" "0,r,?r")
- (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))
+(define_expand "sminsi3"
+ [(parallel [
+ (set (match_operand:SI 0 "s_register_operand" "")
+ (smin:SI (match_operand:SI 1 "s_register_operand" "")
+ (match_operand:SI 2 "arm_rhs_operand" "")))
+ (clobber (reg:CC CC_REGNUM))])]
+ "TARGET_ARM"
+ "
+ if (operands[2] == const0_rtx)
+ {
+ /* No need for a clobber of the condition code register here. */
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+ gen_rtx_SMIN (SImode, operands[1],
+ operands[2])));
+ DONE;
+ }
+")
+
+(define_insn "*smin_0"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (smin:SI (match_operand:SI 1 "s_register_operand" "r")
+ (const_int 0)))]
+ "TARGET_ARM"
+ "and%?\\t%0, %1, %1, asr #31"
+ [(set_attr "predicable" "yes")]
+)
+
+(define_insn "*smin_insn"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (smin:SI (match_operand:SI 1 "s_register_operand" "%0,?r")
+ (match_operand:SI 2 "arm_rhs_operand" "rI,rI")))
(clobber (reg:CC CC_REGNUM))]
"TARGET_ARM"
"@
cmp\\t%1, %2\;movge\\t%0, %2
- cmp\\t%1, %2\;movlt\\t%0, %1
cmp\\t%1, %2\;movlt\\t%0, %1\;movge\\t%0, %2"
[(set_attr "conds" "clob")
- (set_attr "length" "8,8,12")]
+ (set_attr "length" "8,12")]
)
(define_insn "umaxsi3"
@@ -2491,8 +2599,8 @@
(clobber (reg:CC CC_REGNUM))]
"TARGET_ARM"
"*
- operands[3] = gen_rtx (minmax_code (operands[3]), SImode, operands[1],
- operands[2]);
+ operands[3] = gen_rtx_fmt_ee (minmax_code (operands[3]), SImode,
+ operands[1], operands[2]);
output_asm_insn (\"cmp\\t%1, %2\", operands);
output_asm_insn (\"str%d3\\t%1, %0\", operands);
output_asm_insn (\"str%D3\\t%2, %0\", operands);
@@ -2513,16 +2621,13 @@
(match_operand:SI 3 "arm_rhs_operand" "rI,rI")])
(match_operand:SI 1 "s_register_operand" "0,?r")]))
(clobber (reg:CC CC_REGNUM))]
- "TARGET_ARM
- && (GET_CODE (operands[1]) != REG
- || (REGNO(operands[1]) != FRAME_POINTER_REGNUM
- && REGNO(operands[1]) != ARG_POINTER_REGNUM))"
+ "TARGET_ARM && !arm_eliminable_register (operands[1])"
"*
{
enum rtx_code code = GET_CODE (operands[4]);
- operands[5] = gen_rtx (minmax_code (operands[5]), SImode, operands[2],
- operands[3]);
+ operands[5] = gen_rtx_fmt_ee (minmax_code (operands[5]), SImode,
+ operands[2], operands[3]);
output_asm_insn (\"cmp\\t%2, %3\", operands);
output_asm_insn (\"%i4%d5\\t%0, %1, %2\", operands);
if (which_alternative != 0 || operands[3] != const0_rtx
@@ -2537,6 +2642,41 @@
;; Shift and rotation insns
+(define_expand "ashldi3"
+ [(set (match_operand:DI 0 "s_register_operand" "")
+ (ashift:DI (match_operand:DI 1 "s_register_operand" "")
+ (match_operand:SI 2 "reg_or_int_operand" "")))]
+ "TARGET_ARM"
+ "
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ if ((HOST_WIDE_INT) INTVAL (operands[2]) == 1)
+ {
+ emit_insn (gen_arm_ashldi3_1bit (operands[0], operands[1]));
+ DONE;
+ }
+ /* Ideally we shouldn't fail here if we could know that operands[1]
+ ends up already living in an iwmmxt register. Otherwise it's
+ cheaper to have the alternate code being generated than moving
+ values to iwmmxt regs and back. */
+ FAIL;
+ }
+ else if (!TARGET_REALLY_IWMMXT && !(TARGET_HARD_FLOAT && TARGET_MAVERICK))
+ FAIL;
+ "
+)
+
+(define_insn "arm_ashldi3_1bit"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,r")
+ (ashift:DI (match_operand:DI 1 "s_register_operand" "?r,0")
+ (const_int 1)))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_ARM"
+ "movs\\t%Q0, %Q1, asl #1\;adc\\t%R0, %R1, %R1"
+ [(set_attr "conds" "clob")
+ (set_attr "length" "8")]
+)
+
(define_expand "ashlsi3"
[(set (match_operand:SI 0 "s_register_operand" "")
(ashift:SI (match_operand:SI 1 "s_register_operand" "")
@@ -2561,6 +2701,41 @@
[(set_attr "length" "2")]
)
+(define_expand "ashrdi3"
+ [(set (match_operand:DI 0 "s_register_operand" "")
+ (ashiftrt:DI (match_operand:DI 1 "s_register_operand" "")
+ (match_operand:SI 2 "reg_or_int_operand" "")))]
+ "TARGET_ARM"
+ "
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ if ((HOST_WIDE_INT) INTVAL (operands[2]) == 1)
+ {
+ emit_insn (gen_arm_ashrdi3_1bit (operands[0], operands[1]));
+ DONE;
+ }
+ /* Ideally we shouldn't fail here if we could know that operands[1]
+ ends up already living in an iwmmxt register. Otherwise it's
+ cheaper to have the alternate code being generated than moving
+ values to iwmmxt regs and back. */
+ FAIL;
+ }
+ else if (!TARGET_REALLY_IWMMXT)
+ FAIL;
+ "
+)
+
+(define_insn "arm_ashrdi3_1bit"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,r")
+ (ashiftrt:DI (match_operand:DI 1 "s_register_operand" "?r,0")
+ (const_int 1)))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_ARM"
+ "movs\\t%R0, %R1, asr #1\;mov\\t%Q0, %Q1, rrx"
+ [(set_attr "conds" "clob")
+ (set_attr "length" "8")]
+)
+
(define_expand "ashrsi3"
[(set (match_operand:SI 0 "s_register_operand" "")
(ashiftrt:SI (match_operand:SI 1 "s_register_operand" "")
@@ -2582,6 +2757,41 @@
[(set_attr "length" "2")]
)
+(define_expand "lshrdi3"
+ [(set (match_operand:DI 0 "s_register_operand" "")
+ (lshiftrt:DI (match_operand:DI 1 "s_register_operand" "")
+ (match_operand:SI 2 "reg_or_int_operand" "")))]
+ "TARGET_ARM"
+ "
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ if ((HOST_WIDE_INT) INTVAL (operands[2]) == 1)
+ {
+ emit_insn (gen_arm_lshrdi3_1bit (operands[0], operands[1]));
+ DONE;
+ }
+ /* Ideally we shouldn't fail here if we could know that operands[1]
+ ends up already living in an iwmmxt register. Otherwise it's
+ cheaper to have the alternate code being generated than moving
+ values to iwmmxt regs and back. */
+ FAIL;
+ }
+ else if (!TARGET_REALLY_IWMMXT)
+ FAIL;
+ "
+)
+
+(define_insn "arm_lshrdi3_1bit"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,r")
+ (lshiftrt:DI (match_operand:DI 1 "s_register_operand" "?r,0")
+ (const_int 1)))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_ARM"
+ "movs\\t%R0, %R1, lsr #1\;mov\\t%Q0, %Q1, rrx"
+ [(set_attr "conds" "clob")
+ (set_attr "length" "8")]
+)
+
(define_expand "lshrsi3"
[(set (match_operand:SI 0 "s_register_operand" "")
(lshiftrt:SI (match_operand:SI 1 "s_register_operand" "")
@@ -2652,19 +2862,6 @@
[(set_attr "length" "2")]
)
-(define_expand "ashldi3"
- [(set (match_operand:DI 0 "s_register_operand" "")
- (ashift:DI (match_operand:DI 1 "general_operand" "")
- (match_operand:SI 2 "general_operand" "")))]
- "TARGET_ARM && (TARGET_IWMMXT || TARGET_CIRRUS)"
- "
- if (! s_register_operand (operands[1], DImode))
- operands[1] = copy_to_mode_reg (DImode, operands[1]);
- if (! s_register_operand (operands[2], SImode))
- operands[2] = copy_to_mode_reg (SImode, operands[2]);
- "
-)
-
(define_insn "*arm_shiftsi3"
[(set (match_operand:SI 0 "s_register_operand" "=r")
(match_operator:SI 3 "shift_operator"
@@ -2674,7 +2871,9 @@
"mov%?\\t%0, %1%S3"
[(set_attr "predicable" "yes")
(set_attr "shift" "1")
- ]
+ (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
+ (const_string "alu_shift")
+ (const_string "alu_shift_reg")))]
)
(define_insn "*shiftsi3_compare0"
@@ -2689,7 +2888,9 @@
"mov%?s\\t%0, %1%S3"
[(set_attr "conds" "set")
(set_attr "shift" "1")
- ]
+ (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
+ (const_string "alu_shift")
+ (const_string "alu_shift_reg")))]
)
(define_insn "*shiftsi3_compare0_scratch"
@@ -2702,8 +2903,7 @@
"TARGET_ARM"
"mov%?s\\t%0, %1%S3"
[(set_attr "conds" "set")
- (set_attr "shift" "1")
- ]
+ (set_attr "shift" "1")]
)
(define_insn "*notsi_shiftsi"
@@ -2715,7 +2915,9 @@
"mvn%?\\t%0, %1%S3"
[(set_attr "predicable" "yes")
(set_attr "shift" "1")
- ]
+ (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
+ (const_string "alu_shift")
+ (const_string "alu_shift_reg")))]
)
(define_insn "*notsi_shiftsi_compare0"
@@ -2730,7 +2932,9 @@
"mvn%?s\\t%0, %1%S3"
[(set_attr "conds" "set")
(set_attr "shift" "1")
- ]
+ (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
+ (const_string "alu_shift")
+ (const_string "alu_shift_reg")))]
)
(define_insn "*not_shiftsi_compare0_scratch"
@@ -2744,7 +2948,9 @@
"mvn%?s\\t%0, %1%S3"
[(set_attr "conds" "set")
(set_attr "shift" "1")
- ]
+ (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
+ (const_string "alu_shift")
+ (const_string "alu_shift_reg")))]
)
;; We don't really have extzv, but defining this using shifts helps
@@ -2841,14 +3047,14 @@
(define_expand "negsf2"
[(set (match_operand:SF 0 "s_register_operand" "")
(neg:SF (match_operand:SF 1 "s_register_operand" "")))]
- "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
""
)
(define_expand "negdf2"
[(set (match_operand:DF 0 "s_register_operand" "")
(neg:DF (match_operand:DF 1 "s_register_operand" "")))]
- "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"")
;; abssi2 doesn't really clobber the condition codes if a different register
@@ -2895,25 +3101,25 @@
(define_expand "abssf2"
[(set (match_operand:SF 0 "s_register_operand" "")
(abs:SF (match_operand:SF 1 "s_register_operand" "")))]
- "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT"
"")
(define_expand "absdf2"
[(set (match_operand:DF 0 "s_register_operand" "")
(abs:DF (match_operand:DF 1 "s_register_operand" "")))]
- "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT"
"")
(define_expand "sqrtsf2"
[(set (match_operand:SF 0 "s_register_operand" "")
(sqrt:SF (match_operand:SF 1 "s_register_operand" "")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"")
(define_expand "sqrtdf2"
[(set (match_operand:DF 0 "s_register_operand" "")
(sqrt:DF (match_operand:DF 1 "s_register_operand" "")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"")
(define_insn_and_split "one_cmpldi2"
@@ -2984,9 +3190,9 @@
(define_expand "floatsisf2"
[(set (match_operand:SF 0 "s_register_operand" "")
(float:SF (match_operand:SI 1 "s_register_operand" "")))]
- "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT"
"
- if (TARGET_CIRRUS)
+ if (TARGET_MAVERICK)
{
emit_insn (gen_cirrus_floatsisf2 (operands[0], operands[1]));
DONE;
@@ -2996,9 +3202,9 @@
(define_expand "floatsidf2"
[(set (match_operand:DF 0 "s_register_operand" "")
(float:DF (match_operand:SI 1 "s_register_operand" "")))]
- "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT"
"
- if (TARGET_CIRRUS)
+ if (TARGET_MAVERICK)
{
emit_insn (gen_cirrus_floatsidf2 (operands[0], operands[1]));
DONE;
@@ -3008,9 +3214,9 @@
(define_expand "fix_truncsfsi2"
[(set (match_operand:SI 0 "s_register_operand" "")
(fix:SI (fix:SF (match_operand:SF 1 "s_register_operand" ""))))]
- "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT"
"
- if (TARGET_CIRRUS)
+ if (TARGET_MAVERICK)
{
if (!cirrus_fp_register (operands[0], SImode))
operands[0] = force_reg (SImode, operands[0]);
@@ -3024,9 +3230,9 @@
(define_expand "fix_truncdfsi2"
[(set (match_operand:SI 0 "s_register_operand" "")
(fix:SI (fix:DF (match_operand:DF 1 "s_register_operand" ""))))]
- "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT"
"
- if (TARGET_CIRRUS)
+ if (TARGET_MAVERICK)
{
if (!cirrus_fp_register (operands[1], DFmode))
operands[1] = force_reg (DFmode, operands[0]);
@@ -3041,7 +3247,7 @@
[(set (match_operand:SF 0 "s_register_operand" "")
(float_truncate:SF
(match_operand:DF 1 "s_register_operand" "")))]
- "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT"
""
)
@@ -3070,7 +3276,7 @@
ldr%?b\\t%Q0, %1\;mov%?\\t%R0, #0"
[(set_attr "length" "8")
(set_attr "predicable" "yes")
- (set_attr "type" "*,load")
+ (set_attr "type" "*,load_byte")
(set_attr "pool_range" "*,4092")
(set_attr "neg_pool_range" "*,4084")]
)
@@ -3099,72 +3305,38 @@
"TARGET_EITHER"
"
{
- if (TARGET_ARM)
+ if ((TARGET_THUMB || arm_arch4) && GET_CODE (operands[1]) == MEM)
{
- if (arm_arch4 && GET_CODE (operands[1]) == MEM)
- {
- /* Note: We do not have to worry about TARGET_MMU_TRAPS
- here because the insn below will generate an LDRH instruction
- rather than an LDR instruction, so we cannot get an unaligned
- word access. */
- emit_insn (gen_rtx_SET (VOIDmode, operands[0],
- gen_rtx_ZERO_EXTEND (SImode,
- operands[1])));
- DONE;
- }
- if (TARGET_MMU_TRAPS && GET_CODE (operands[1]) == MEM)
- {
- emit_insn (gen_movhi_bytes (operands[0], operands[1]));
- DONE;
- }
- if (!s_register_operand (operands[1], HImode))
- operands[1] = copy_to_mode_reg (HImode, operands[1]);
- operands[1] = gen_lowpart (SImode, operands[1]);
- operands[2] = gen_reg_rtx (SImode);
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+ gen_rtx_ZERO_EXTEND (SImode, operands[1])));
+ DONE;
}
- else /* TARGET_THUMB */
- {
- if (GET_CODE (operands[1]) == MEM)
- {
- rtx tmp;
- tmp = gen_rtx_ZERO_EXTEND (SImode, operands[1]);
- tmp = gen_rtx_SET (VOIDmode, operands[0], tmp);
- emit_insn (tmp);
- }
- else
- {
- rtx ops[3];
-
- if (!s_register_operand (operands[1], HImode))
- operands[1] = copy_to_mode_reg (HImode, operands[1]);
- operands[1] = gen_lowpart (SImode, operands[1]);
- operands[2] = gen_reg_rtx (SImode);
-
- ops[0] = operands[2];
- ops[1] = operands[1];
- ops[2] = GEN_INT (16);
-
- emit_insn (gen_rtx_SET (VOIDmode, ops[0],
- gen_rtx_ASHIFT (SImode, ops[1], ops[2])));
+ if (TARGET_ARM && GET_CODE (operands[1]) == MEM)
+ {
+ emit_insn (gen_movhi_bytes (operands[0], operands[1]));
+ DONE;
+ }
- ops[0] = operands[0];
- ops[1] = operands[2];
- ops[2] = GEN_INT (16);
+ if (!s_register_operand (operands[1], HImode))
+ operands[1] = copy_to_mode_reg (HImode, operands[1]);
- emit_insn (gen_rtx_SET (VOIDmode, ops[0],
- gen_rtx_LSHIFTRT (SImode, ops[1],
- ops[2])));
- }
- DONE;
+ if (arm_arch6)
+ {
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+ gen_rtx_ZERO_EXTEND (SImode, operands[1])));
+ DONE;
}
+
+ operands[1] = gen_lowpart (SImode, operands[1]);
+ operands[2] = gen_reg_rtx (SImode);
}"
)
(define_insn "*thumb_zero_extendhisi2"
- [(set (match_operand:SI 0 "register_operand" "=l")
- (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
- "TARGET_THUMB"
+ [(set (match_operand:SI 0 "register_operand" "=l")
+ (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
+ "TARGET_THUMB && !arm_arch6"
"*
rtx mem = XEXP (operands[1], 0);
@@ -3199,49 +3371,89 @@
return \"ldrh\\t%0, %1\";
"
[(set_attr "length" "4")
- (set_attr "type" "load")
+ (set_attr "type" "load_byte")
(set_attr "pool_range" "60")]
)
+(define_insn "*thumb_zero_extendhisi2_v6"
+ [(set (match_operand:SI 0 "register_operand" "=l,l")
+ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "l,m")))]
+ "TARGET_THUMB && arm_arch6"
+ "*
+ rtx mem;
+
+ if (which_alternative == 0)
+ return \"uxth\\t%0, %1\";
+
+ mem = XEXP (operands[1], 0);
+
+ if (GET_CODE (mem) == CONST)
+ mem = XEXP (mem, 0);
+
+ if (GET_CODE (mem) == LABEL_REF)
+ return \"ldr\\t%0, %1\";
+
+ if (GET_CODE (mem) == PLUS)
+ {
+ rtx a = XEXP (mem, 0);
+ rtx b = XEXP (mem, 1);
+
+ /* This can happen due to bugs in reload. */
+ if (GET_CODE (a) == REG && REGNO (a) == SP_REGNUM)
+ {
+ rtx ops[2];
+ ops[0] = operands[0];
+ ops[1] = a;
+
+ output_asm_insn (\"mov %0, %1\", ops);
+
+ XEXP (mem, 0) = operands[0];
+ }
+
+ else if ( GET_CODE (a) == LABEL_REF
+ && GET_CODE (b) == CONST_INT)
+ return \"ldr\\t%0, %1\";
+ }
+
+ return \"ldrh\\t%0, %1\";
+ "
+ [(set_attr "length" "2,4")
+ (set_attr "type" "alu_shift,load_byte")
+ (set_attr "pool_range" "*,60")]
+)
+
(define_insn "*arm_zero_extendhisi2"
- [(set (match_operand:SI 0 "s_register_operand" "=r")
- (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
- "TARGET_ARM && arm_arch4"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
+ "TARGET_ARM && arm_arch4 && !arm_arch6"
"ldr%?h\\t%0, %1"
- [(set_attr "type" "load")
+ [(set_attr "type" "load_byte")
(set_attr "predicable" "yes")
(set_attr "pool_range" "256")
(set_attr "neg_pool_range" "244")]
)
-(define_split
- [(set (match_operand:SI 0 "s_register_operand" "")
- (zero_extend:SI (match_operand:HI 1 "alignable_memory_operand" "")))
- (clobber (match_operand:SI 2 "s_register_operand" ""))]
- "TARGET_ARM && (!arm_arch4)"
- [(set (match_dup 2) (match_dup 1))
- (set (match_dup 0) (lshiftrt:SI (match_dup 2) (const_int 16)))]
- "
- if ((operands[1] = arm_gen_rotated_half_load (operands[1])) == NULL)
- FAIL;
- "
+(define_insn "*arm_zero_extendhisi2_v6"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
+ "TARGET_ARM && arm_arch6"
+ "@
+ uxth%?\\t%0, %1
+ ldr%?h\\t%0, %1"
+ [(set_attr "type" "alu_shift,load_byte")
+ (set_attr "predicable" "yes")
+ (set_attr "pool_range" "*,256")
+ (set_attr "neg_pool_range" "*,244")]
)
-(define_split
- [(set (match_operand:SI 0 "s_register_operand" "")
- (match_operator:SI 3 "shiftable_operator"
- [(zero_extend:SI (match_operand:HI 1 "alignable_memory_operand" ""))
- (match_operand:SI 4 "s_register_operand" "")]))
- (clobber (match_operand:SI 2 "s_register_operand" ""))]
- "TARGET_ARM && (!arm_arch4)"
- [(set (match_dup 2) (match_dup 1))
- (set (match_dup 0)
- (match_op_dup 3
- [(lshiftrt:SI (match_dup 2) (const_int 16)) (match_dup 4)]))]
- "
- if ((operands[1] = arm_gen_rotated_half_load (operands[1])) == NULL)
- FAIL;
- "
+(define_insn "*arm_zero_extendhisi2addsi"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (zero_extend:SI (match_operand:HI 1 "s_register_operand" "r"))
+ (match_operand:SI 2 "s_register_operand" "r")))]
+ "TARGET_ARM && arm_arch6"
+ "uxtah%?\\t%0, %2, %1"
+ [(set_attr "type" "alu_shift")
+ (set_attr "predicable" "yes")]
)
(define_expand "zero_extendqisi2"
@@ -3249,7 +3461,7 @@
(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
"TARGET_EITHER"
"
- if (GET_CODE (operands[1]) != MEM)
+ if (!arm_arch6 && GET_CODE (operands[1]) != MEM)
{
if (TARGET_ARM)
{
@@ -3285,26 +3497,61 @@
)
(define_insn "*thumb_zero_extendqisi2"
- [(set (match_operand:SI 0 "register_operand" "=l")
- (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
- "TARGET_THUMB"
+ [(set (match_operand:SI 0 "register_operand" "=l")
+ (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
+ "TARGET_THUMB && !arm_arch6"
"ldrb\\t%0, %1"
[(set_attr "length" "2")
- (set_attr "type" "load")
+ (set_attr "type" "load_byte")
(set_attr "pool_range" "32")]
)
+(define_insn "*thumb_zero_extendqisi2_v6"
+ [(set (match_operand:SI 0 "register_operand" "=l,l")
+ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "l,m")))]
+ "TARGET_THUMB && arm_arch6"
+ "@
+ uxtb\\t%0, %1
+ ldrb\\t%0, %1"
+ [(set_attr "length" "2,2")
+ (set_attr "type" "alu_shift,load_byte")
+ (set_attr "pool_range" "*,32")]
+)
+
(define_insn "*arm_zero_extendqisi2"
- [(set (match_operand:SI 0 "s_register_operand" "=r")
- (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
- "TARGET_ARM"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
+ "TARGET_ARM && !arm_arch6"
"ldr%?b\\t%0, %1\\t%@ zero_extendqisi2"
- [(set_attr "type" "load")
+ [(set_attr "type" "load_byte")
(set_attr "predicable" "yes")
(set_attr "pool_range" "4096")
(set_attr "neg_pool_range" "4084")]
)
+(define_insn "*arm_zero_extendqisi2_v6"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
+ "TARGET_ARM && arm_arch6"
+ "@
+ uxtb%?\\t%0, %1
+ ldr%?b\\t%0, %1\\t%@ zero_extendqisi2"
+ [(set_attr "type" "alu_shift,load_byte")
+ (set_attr "predicable" "yes")
+ (set_attr "pool_range" "*,4096")
+ (set_attr "neg_pool_range" "*,4084")]
+)
+
+(define_insn "*arm_zero_extendqisi2addsi"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (zero_extend:SI (match_operand:QI 1 "s_register_operand" "r"))
+ (match_operand:SI 2 "s_register_operand" "r")))]
+ "TARGET_ARM && arm_arch6"
+ "uxtab%?\\t%0, %2, %1"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "alu_shift")]
+)
+
(define_split
[(set (match_operand:SI 0 "s_register_operand" "")
(zero_extend:SI (subreg:QI (match_operand:SI 1 "" "") 0)))
@@ -3315,6 +3562,16 @@
""
)
+(define_split
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (zero_extend:SI (subreg:QI (match_operand:SI 1 "" "") 3)))
+ (clobber (match_operand:SI 2 "s_register_operand" ""))]
+ "TARGET_ARM && (GET_CODE (operands[1]) != MEM) && BYTES_BIG_ENDIAN"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_dup 0) (and:SI (match_dup 2) (const_int 255)))]
+ ""
+)
+
(define_insn "*compareqi_eq0"
[(set (reg:CC_Z CC_REGNUM)
(compare:CC_Z (match_operand:QI 0 "s_register_operand" "r")
@@ -3334,55 +3591,51 @@
"TARGET_EITHER"
"
{
- if (TARGET_ARM && arm_arch4 && GET_CODE (operands[1]) == MEM)
+ if (GET_CODE (operands[1]) == MEM)
{
- /* Note: We do not have to worry about TARGET_MMU_TRAPS
- here because the insn below will generate an LDRH instruction
- rather than an LDR instruction, so we cannot get an unaligned
- word access. */
- emit_insn (gen_rtx_SET (VOIDmode, operands[0],
- gen_rtx_SIGN_EXTEND (SImode, operands[1])));
- DONE;
+ if (TARGET_THUMB)
+ {
+ emit_insn (gen_thumb_extendhisi2 (operands[0], operands[1]));
+ DONE;
+ }
+ else if (arm_arch4)
+ {
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+ gen_rtx_SIGN_EXTEND (SImode, operands[1])));
+ DONE;
+ }
}
- if (TARGET_ARM && TARGET_MMU_TRAPS && GET_CODE (operands[1]) == MEM)
+ if (TARGET_ARM && GET_CODE (operands[1]) == MEM)
{
emit_insn (gen_extendhisi2_mem (operands[0], operands[1]));
DONE;
}
+
if (!s_register_operand (operands[1], HImode))
operands[1] = copy_to_mode_reg (HImode, operands[1]);
- operands[1] = gen_lowpart (SImode, operands[1]);
- operands[2] = gen_reg_rtx (SImode);
- if (TARGET_THUMB)
+ if (arm_arch6)
{
- rtx ops[3];
-
- ops[0] = operands[2];
- ops[1] = operands[1];
- ops[2] = GEN_INT (16);
-
- emit_insn (gen_rtx_SET (VOIDmode, ops[0],
- gen_rtx_ASHIFT (SImode, ops[1], ops[2])));
-
- ops[0] = operands[0];
- ops[1] = operands[2];
- ops[2] = GEN_INT (16);
-
- emit_insn (gen_rtx_SET (VOIDmode, ops[0],
- gen_rtx_ASHIFTRT (SImode, ops[1], ops[2])));
-
+ if (TARGET_THUMB)
+ emit_insn (gen_thumb_extendhisi2 (operands[0], operands[1]));
+ else
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+ gen_rtx_SIGN_EXTEND (SImode, operands[1])));
+
DONE;
}
+
+ operands[1] = gen_lowpart (SImode, operands[1]);
+ operands[2] = gen_reg_rtx (SImode);
}"
)
-(define_insn "*thumb_extendhisi2_insn"
- [(set (match_operand:SI 0 "register_operand" "=l")
- (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))
- (clobber (match_scratch:SI 2 "=&l"))]
- "TARGET_THUMB"
+(define_insn "thumb_extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=l")
+ (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))
+ (clobber (match_scratch:SI 2 "=&l"))]
+ "TARGET_THUMB && !arm_arch6"
"*
{
rtx ops[4];
@@ -3419,12 +3672,8 @@
ops[1] = mem;
ops[2] = const0_rtx;
}
-
- if (GET_CODE (ops[1]) != REG)
- {
- debug_rtx (ops[1]);
- abort ();
- }
+
+ gcc_assert (GET_CODE (ops[1]) == REG);
ops[0] = operands[0];
ops[3] = operands[2];
@@ -3432,10 +3681,79 @@
return \"\";
}"
[(set_attr "length" "4")
- (set_attr "type" "load")
+ (set_attr "type" "load_byte")
(set_attr "pool_range" "1020")]
)
+;; We used to have an early-clobber on the scratch register here.
+;; However, there's a bug somewhere in reload which means that this
+;; can be partially ignored during spill allocation if the memory
+;; address also needs reloading; this causes us to die later on when
+;; we try to verify the operands. Fortunately, we don't really need
+;; the early-clobber: we can always use operand 0 if operand 2
+;; overlaps the address.
+(define_insn "*thumb_extendhisi2_insn_v6"
+ [(set (match_operand:SI 0 "register_operand" "=l,l")
+ (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "l,m")))
+ (clobber (match_scratch:SI 2 "=X,l"))]
+ "TARGET_THUMB && arm_arch6"
+ "*
+ {
+ rtx ops[4];
+ rtx mem;
+
+ if (which_alternative == 0)
+ return \"sxth\\t%0, %1\";
+
+ mem = XEXP (operands[1], 0);
+
+ /* This code used to try to use 'V', and fix the address only if it was
+ offsettable, but this fails for e.g. REG+48 because 48 is outside the
+ range of QImode offsets, and offsettable_address_p does a QImode
+ address check. */
+
+ if (GET_CODE (mem) == CONST)
+ mem = XEXP (mem, 0);
+
+ if (GET_CODE (mem) == LABEL_REF)
+ return \"ldr\\t%0, %1\";
+
+ if (GET_CODE (mem) == PLUS)
+ {
+ rtx a = XEXP (mem, 0);
+ rtx b = XEXP (mem, 1);
+
+ if (GET_CODE (a) == LABEL_REF
+ && GET_CODE (b) == CONST_INT)
+ return \"ldr\\t%0, %1\";
+
+ if (GET_CODE (b) == REG)
+ return \"ldrsh\\t%0, %1\";
+
+ ops[1] = a;
+ ops[2] = b;
+ }
+ else
+ {
+ ops[1] = mem;
+ ops[2] = const0_rtx;
+ }
+
+ gcc_assert (GET_CODE (ops[1]) == REG);
+
+ ops[0] = operands[0];
+ if (reg_mentioned_p (operands[2], ops[1]))
+ ops[3] = ops[0];
+ else
+ ops[3] = operands[2];
+ output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops);
+ return \"\";
+ }"
+ [(set_attr "length" "2,4")
+ (set_attr "type" "alu_shift,load_byte")
+ (set_attr "pool_range" "*,1020")]
+)
+
(define_expand "extendhisi2_mem"
[(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" "")))
(set (match_dup 3)
@@ -3449,10 +3767,8 @@
rtx mem1, mem2;
rtx addr = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
- mem1 = gen_rtx_MEM (QImode, addr);
- MEM_COPY_ATTRIBUTES (mem1, operands[1]);
- mem2 = gen_rtx_MEM (QImode, plus_constant (addr, 1));
- MEM_COPY_ATTRIBUTES (mem2, operands[1]);
+ mem1 = change_address (operands[1], QImode, addr);
+ mem2 = change_address (operands[1], QImode, plus_constant (addr, 1));
operands[0] = gen_lowpart (SImode, operands[0]);
operands[1] = mem1;
operands[2] = gen_reg_rtx (SImode);
@@ -3473,44 +3789,36 @@
}"
)
-(define_insn "*arm_extendhisi_insn"
- [(set (match_operand:SI 0 "s_register_operand" "=r")
- (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
- "TARGET_ARM && arm_arch4"
+(define_insn "*arm_extendhisi2"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
+ "TARGET_ARM && arm_arch4 && !arm_arch6"
"ldr%?sh\\t%0, %1"
- [(set_attr "type" "load")
+ [(set_attr "type" "load_byte")
(set_attr "predicable" "yes")
(set_attr "pool_range" "256")
(set_attr "neg_pool_range" "244")]
)
-(define_split
- [(set (match_operand:SI 0 "s_register_operand" "")
- (sign_extend:SI (match_operand:HI 1 "alignable_memory_operand" "")))
- (clobber (match_operand:SI 2 "s_register_operand" ""))]
- "TARGET_ARM && (!arm_arch4)"
- [(set (match_dup 2) (match_dup 1))
- (set (match_dup 0) (ashiftrt:SI (match_dup 2) (const_int 16)))]
- "
- if ((operands[1] = arm_gen_rotated_half_load (operands[1])) == NULL)
- FAIL;
- "
+(define_insn "*arm_extendhisi2_v6"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
+ "TARGET_ARM && arm_arch6"
+ "@
+ sxth%?\\t%0, %1
+ ldr%?sh\\t%0, %1"
+ [(set_attr "type" "alu_shift,load_byte")
+ (set_attr "predicable" "yes")
+ (set_attr "pool_range" "*,256")
+ (set_attr "neg_pool_range" "*,244")]
)
-(define_split
- [(set (match_operand:SI 0 "s_register_operand" "")
- (match_operator:SI 3 "shiftable_operator"
- [(sign_extend:SI (match_operand:HI 1 "alignable_memory_operand" ""))
- (match_operand:SI 4 "s_register_operand" "")]))
- (clobber (match_operand:SI 2 "s_register_operand" ""))]
- "TARGET_ARM && (!arm_arch4)"
- [(set (match_dup 2) (match_dup 1))
- (set (match_dup 0)
- (match_op_dup 3
- [(ashiftrt:SI (match_dup 2) (const_int 16)) (match_dup 4)]))]
- "if ((operands[1] = arm_gen_rotated_half_load (operands[1])) == NULL)
- FAIL;
- "
+(define_insn "*arm_extendhisi2addsi"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (sign_extend:SI (match_operand:HI 1 "s_register_operand" "r"))
+ (match_operand:SI 2 "s_register_operand" "r")))]
+ "TARGET_ARM && arm_arch6"
+ "sxtah%?\\t%0, %2, %1"
)
(define_expand "extendqihi2"
@@ -3538,59 +3846,17 @@
}"
)
-; Rather than restricting all byte accesses to memory addresses that ldrsb
-; can handle, we fix up the ones that ldrsb can't grok with a split.
(define_insn "*extendqihi_insn"
- [(set (match_operand:HI 0 "s_register_operand" "=r")
- (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))]
+ [(set (match_operand:HI 0 "s_register_operand" "=r")
+ (sign_extend:HI (match_operand:QI 1 "memory_operand" "Uq")))]
"TARGET_ARM && arm_arch4"
- "*
- /* If the address is invalid, this will split the instruction into two. */
- if (bad_signed_byte_operand (operands[1], VOIDmode))
- return \"#\";
- return \"ldr%?sb\\t%0, %1\";
- "
- [(set_attr "type" "load")
+ "ldr%?sb\\t%0, %1"
+ [(set_attr "type" "load_byte")
(set_attr "predicable" "yes")
- (set_attr "length" "8")
(set_attr "pool_range" "256")
(set_attr "neg_pool_range" "244")]
)
-(define_split
- [(set (match_operand:HI 0 "s_register_operand" "")
- (sign_extend:HI (match_operand:QI 1 "bad_signed_byte_operand" "")))]
- "TARGET_ARM && arm_arch4 && reload_completed"
- [(set (match_dup 3) (match_dup 1))
- (set (match_dup 0) (sign_extend:HI (match_dup 2)))]
- "
- {
- HOST_WIDE_INT offset;
-
- operands[3] = gen_rtx_REG (SImode, REGNO (operands[0]));
- operands[2] = gen_rtx_MEM (QImode, operands[3]);
- MEM_COPY_ATTRIBUTES (operands[2], operands[1]);
- operands[1] = XEXP (operands[1], 0);
- if (GET_CODE (operands[1]) == PLUS
- && GET_CODE (XEXP (operands[1], 1)) == CONST_INT
- && !(const_ok_for_arm (offset = INTVAL (XEXP (operands[1], 1)))
- || const_ok_for_arm (-offset)))
- {
- HOST_WIDE_INT low = (offset > 0
- ? (offset & 0xff) : -((-offset) & 0xff));
- XEXP (operands[2], 0) = plus_constant (operands[3], low);
- operands[1] = plus_constant (XEXP (operands[1], 0), offset - low);
- }
- /* Ensure the sum is in correct canonical form. */
- else if (GET_CODE (operands[1]) == PLUS
- && GET_CODE (XEXP (operands[1], 1)) != CONST_INT
- && !s_register_operand (XEXP (operands[1], 1), VOIDmode))
- operands[1] = gen_rtx_PLUS (GET_MODE (operands[1]),
- XEXP (operands[1], 1),
- XEXP (operands[1], 0));
- }"
-)
-
(define_expand "extendqisi2"
[(set (match_dup 2)
(ashift:SI (match_operand:QI 1 "general_operand" "")
@@ -3601,97 +3867,66 @@
"TARGET_EITHER"
"
{
- if (TARGET_ARM && arm_arch4 && GET_CODE (operands[1]) == MEM)
+ if ((TARGET_THUMB || arm_arch4) && GET_CODE (operands[1]) == MEM)
{
- emit_insn (gen_rtx_SET (VOIDmode,
- operands[0],
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0],
gen_rtx_SIGN_EXTEND (SImode, operands[1])));
DONE;
}
+
if (!s_register_operand (operands[1], QImode))
operands[1] = copy_to_mode_reg (QImode, operands[1]);
- operands[1] = gen_lowpart (SImode, operands[1]);
- operands[2] = gen_reg_rtx (SImode);
-
- if (TARGET_THUMB)
- {
- rtx ops[3];
-
- ops[0] = operands[2];
- ops[1] = operands[1];
- ops[2] = GEN_INT (24);
-
- emit_insn (gen_rtx_SET (VOIDmode, ops[0],
- gen_rtx_ASHIFT (SImode, ops[1], ops[2])));
- ops[0] = operands[0];
- ops[1] = operands[2];
- ops[2] = GEN_INT (24);
-
- emit_insn (gen_rtx_SET (VOIDmode, ops[0],
- gen_rtx_ASHIFTRT (SImode, ops[1], ops[2])));
-
- DONE;
+ if (arm_arch6)
+ {
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+ gen_rtx_SIGN_EXTEND (SImode, operands[1])));
+ DONE;
}
+
+ operands[1] = gen_lowpart (SImode, operands[1]);
+ operands[2] = gen_reg_rtx (SImode);
}"
)
-; Rather than restricting all byte accesses to memory addresses that ldrsb
-; can handle, we fix up the ones that ldrsb can't grok with a split.
-(define_insn "*arm_extendqisi_insn"
- [(set (match_operand:SI 0 "s_register_operand" "=r")
- (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
- "TARGET_ARM && arm_arch4"
- "*
- /* If the address is invalid, this will split the instruction into two. */
- if (bad_signed_byte_operand (operands[1], VOIDmode))
- return \"#\";
- return \"ldr%?sb\\t%0, %1\";
- "
- [(set_attr "type" "load")
+(define_insn "*arm_extendqisi"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (sign_extend:SI (match_operand:QI 1 "memory_operand" "Uq")))]
+ "TARGET_ARM && arm_arch4 && !arm_arch6"
+ "ldr%?sb\\t%0, %1"
+ [(set_attr "type" "load_byte")
(set_attr "predicable" "yes")
- (set_attr "length" "8")
(set_attr "pool_range" "256")
(set_attr "neg_pool_range" "244")]
)
-(define_split
- [(set (match_operand:SI 0 "s_register_operand" "")
- (sign_extend:SI (match_operand:QI 1 "bad_signed_byte_operand" "")))]
- "TARGET_ARM && arm_arch4 && reload_completed"
- [(set (match_dup 0) (match_dup 1))
- (set (match_dup 0) (sign_extend:SI (match_dup 2)))]
- "
- {
- HOST_WIDE_INT offset;
-
- operands[2] = gen_rtx_MEM (QImode, operands[0]);
- MEM_COPY_ATTRIBUTES (operands[2], operands[1]);
- operands[1] = XEXP (operands[1], 0);
- if (GET_CODE (operands[1]) == PLUS
- && GET_CODE (XEXP (operands[1], 1)) == CONST_INT
- && !(const_ok_for_arm (offset = INTVAL (XEXP (operands[1], 1)))
- || const_ok_for_arm (-offset)))
- {
- HOST_WIDE_INT low = (offset > 0
- ? (offset & 0xff) : -((-offset) & 0xff));
- XEXP (operands[2], 0) = plus_constant (operands[0], low);
- operands[1] = plus_constant (XEXP (operands[1], 0), offset - low);
- }
- /* Ensure the sum is in correct canonical form. */
- else if (GET_CODE (operands[1]) == PLUS
- && GET_CODE (XEXP (operands[1], 1)) != CONST_INT
- && !s_register_operand (XEXP (operands[1], 1), VOIDmode))
- operands[1] = gen_rtx_PLUS (GET_MODE (operands[1]),
- XEXP (operands[1], 1),
- XEXP (operands[1], 0));
- }"
+(define_insn "*arm_extendqisi_v6"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,Uq")))]
+ "TARGET_ARM && arm_arch6"
+ "@
+ sxtb%?\\t%0, %1
+ ldr%?sb\\t%0, %1"
+ [(set_attr "type" "alu_shift,load_byte")
+ (set_attr "predicable" "yes")
+ (set_attr "pool_range" "*,256")
+ (set_attr "neg_pool_range" "*,244")]
)
-(define_insn "*thumb_extendqisi2_insn"
- [(set (match_operand:SI 0 "register_operand" "=l,l")
- (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))]
- "TARGET_THUMB"
+(define_insn "*arm_extendqisi2addsi"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (sign_extend:SI (match_operand:QI 1 "s_register_operand" "r"))
+ (match_operand:SI 2 "s_register_operand" "r")))]
+ "TARGET_ARM && arm_arch6"
+ "sxtab%?\\t%0, %2, %1"
+ [(set_attr "type" "alu_shift")
+ (set_attr "predicable" "yes")]
+)
+
+(define_insn "*thumb_extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "=l,l")
+ (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))]
+ "TARGET_THUMB && !arm_arch6"
"*
{
rtx ops[3];
@@ -3733,10 +3968,9 @@
else
output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
}
- else if (GET_CODE (b) != REG)
- abort ();
else
{
+ gcc_assert (GET_CODE (b) == REG);
if (REGNO (b) == REGNO (ops[0]))
{
output_asm_insn (\"ldrb\\t%0, [%2, %1]\", ops);
@@ -3763,14 +3997,94 @@
return \"\";
}"
[(set_attr "length" "2,6")
- (set_attr "type" "load,load")
+ (set_attr "type" "load_byte,load_byte")
(set_attr "pool_range" "32,32")]
)
+(define_insn "*thumb_extendqisi2_v6"
+ [(set (match_operand:SI 0 "register_operand" "=l,l,l")
+ (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "l,V,m")))]
+ "TARGET_THUMB && arm_arch6"
+ "*
+ {
+ rtx ops[3];
+ rtx mem;
+
+ if (which_alternative == 0)
+ return \"sxtb\\t%0, %1\";
+
+ mem = XEXP (operands[1], 0);
+
+ if (GET_CODE (mem) == CONST)
+ mem = XEXP (mem, 0);
+
+ if (GET_CODE (mem) == LABEL_REF)
+ return \"ldr\\t%0, %1\";
+
+ if (GET_CODE (mem) == PLUS
+ && GET_CODE (XEXP (mem, 0)) == LABEL_REF)
+ return \"ldr\\t%0, %1\";
+
+ if (which_alternative == 0)
+ return \"ldrsb\\t%0, %1\";
+
+ ops[0] = operands[0];
+
+ if (GET_CODE (mem) == PLUS)
+ {
+ rtx a = XEXP (mem, 0);
+ rtx b = XEXP (mem, 1);
+
+ ops[1] = a;
+ ops[2] = b;
+
+ if (GET_CODE (a) == REG)
+ {
+ if (GET_CODE (b) == REG)
+ output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops);
+ else if (REGNO (a) == REGNO (ops[0]))
+ {
+ output_asm_insn (\"ldrb\\t%0, [%1, %2]\", ops);
+ output_asm_insn (\"sxtb\\t%0, %0\", ops);
+ }
+ else
+ output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
+ }
+ else
+ {
+ gcc_assert (GET_CODE (b) == REG);
+ if (REGNO (b) == REGNO (ops[0]))
+ {
+ output_asm_insn (\"ldrb\\t%0, [%2, %1]\", ops);
+ output_asm_insn (\"sxtb\\t%0, %0\", ops);
+ }
+ else
+ output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
+ }
+ }
+ else if (GET_CODE (mem) == REG && REGNO (ops[0]) == REGNO (mem))
+ {
+ output_asm_insn (\"ldrb\\t%0, [%0, #0]\", ops);
+ output_asm_insn (\"sxtb\\t%0, %0\", ops);
+ }
+ else
+ {
+ ops[1] = mem;
+ ops[2] = const0_rtx;
+
+ output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
+ }
+ return \"\";
+ }"
+ [(set_attr "length" "2,2,4")
+ (set_attr "type" "alu_shift,load_byte,load_byte")
+ (set_attr "pool_range" "*,32,32")]
+)
+
(define_expand "extendsfdf2"
[(set (match_operand:DF 0 "s_register_operand" "")
(float_extend:DF (match_operand:SF 1 "s_register_operand" "")))]
- "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT"
""
)
@@ -3840,28 +4154,128 @@
(match_operand:DI 1 "general_operand" ""))]
"TARGET_EITHER"
"
- if (TARGET_THUMB)
+ if (!no_new_pseudos)
{
- if (!no_new_pseudos)
- {
- if (GET_CODE (operands[0]) != REG)
- operands[1] = force_reg (DImode, operands[1]);
- }
+ if (GET_CODE (operands[0]) != REG)
+ operands[1] = force_reg (DImode, operands[1]);
}
"
)
(define_insn "*arm_movdi"
- [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r, r, o<>")
- (match_operand:DI 1 "di_operand" "rIK,mi,r"))]
- "TARGET_ARM && !TARGET_CIRRUS && ! TARGET_IWMMXT"
+ [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r, r, r, r, m")
+ (match_operand:DI 1 "di_operand" "rDa,Db,Dc,mi,r"))]
+ "TARGET_ARM
+ && !(TARGET_HARD_FLOAT && (TARGET_MAVERICK || TARGET_VFP))
+ && !TARGET_IWMMXT
+ && ( register_operand (operands[0], DImode)
+ || register_operand (operands[1], DImode))"
"*
- return (output_move_double (operands));
+ switch (which_alternative)
+ {
+ case 0:
+ case 1:
+ case 2:
+ return \"#\";
+ default:
+ return output_move_double (operands);
+ }
+ "
+ [(set_attr "length" "8,12,16,8,8")
+ (set_attr "type" "*,*,*,load2,store2")
+ (set_attr "pool_range" "*,*,*,1020,*")
+ (set_attr "neg_pool_range" "*,*,*,1008,*")]
+)
+
+(define_split
+ [(set (match_operand:ANY64 0 "arm_general_register_operand" "")
+ (match_operand:ANY64 1 "const_double_operand" ""))]
+ "TARGET_ARM
+ && reload_completed
+ && (arm_const_double_inline_cost (operands[1])
+ <= ((optimize_size || arm_ld_sched) ? 3 : 4))"
+ [(const_int 0)]
+ "
+ arm_split_constant (SET, SImode, curr_insn,
+ INTVAL (gen_lowpart (SImode, operands[1])),
+ gen_lowpart (SImode, operands[0]), NULL_RTX, 0);
+ arm_split_constant (SET, SImode, curr_insn,
+ INTVAL (gen_highpart_mode (SImode,
+ GET_MODE (operands[0]),
+ operands[1])),
+ gen_highpart (SImode, operands[0]), NULL_RTX, 0);
+ DONE;
+ "
+)
+
+; If optimizing for size, or if we have load delay slots, then
+; we want to split the constant into two separate operations.
+; In both cases this may split a trivial part into a single data op
+; leaving a single complex constant to load. We can also get longer
+; offsets in a LDR which means we get better chances of sharing the pool
+; entries. Finally, we can normally do a better job of scheduling
+; LDR instructions than we can with LDM.
+; This pattern will only match if the one above did not.
+(define_split
+ [(set (match_operand:ANY64 0 "arm_general_register_operand" "")
+ (match_operand:ANY64 1 "const_double_operand" ""))]
+ "TARGET_ARM && reload_completed
+ && arm_const_double_by_parts (operands[1])"
+ [(set (match_dup 0) (match_dup 1))
+ (set (match_dup 2) (match_dup 3))]
+ "
+ operands[2] = gen_highpart (SImode, operands[0]);
+ operands[3] = gen_highpart_mode (SImode, GET_MODE (operands[0]),
+ operands[1]);
+ operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[1] = gen_lowpart (SImode, operands[1]);
+ "
+)
+
+(define_split
+ [(set (match_operand:ANY64 0 "arm_general_register_operand" "")
+ (match_operand:ANY64 1 "arm_general_register_operand" ""))]
+ "TARGET_EITHER && reload_completed"
+ [(set (match_dup 0) (match_dup 1))
+ (set (match_dup 2) (match_dup 3))]
+ "
+ operands[2] = gen_highpart (SImode, operands[0]);
+ operands[3] = gen_highpart (SImode, operands[1]);
+ operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[1] = gen_lowpart (SImode, operands[1]);
+
+ /* Handle a partial overlap. */
+ if (rtx_equal_p (operands[0], operands[3]))
+ {
+ rtx tmp0 = operands[0];
+ rtx tmp1 = operands[1];
+
+ operands[0] = operands[2];
+ operands[1] = operands[3];
+ operands[2] = tmp0;
+ operands[3] = tmp1;
+ }
+ "
+)
+
+;; We can't actually do base+index doubleword loads if the index and
+;; destination overlap. Split here so that we at least have chance to
+;; schedule.
+(define_split
+ [(set (match_operand:DI 0 "s_register_operand" "")
+ (mem:DI (plus:SI (match_operand:SI 1 "s_register_operand" "")
+ (match_operand:SI 2 "s_register_operand" ""))))]
+ "TARGET_LDRD
+ && reg_overlap_mentioned_p (operands[0], operands[1])
+ && reg_overlap_mentioned_p (operands[0], operands[2])"
+ [(set (match_dup 4)
+ (plus:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (mem:DI (match_dup 4)))]
+ "
+ operands[4] = gen_rtx_REG (SImode, REGNO(operands[0]));
"
- [(set_attr "length" "8")
- (set_attr "type" "*,load,store2")
- (set_attr "pool_range" "*,1020,*")
- (set_attr "neg_pool_range" "*,1008,*")]
)
;;; ??? This should have alternatives for constants.
@@ -3872,7 +4286,7 @@
[(set (match_operand:DI 0 "nonimmediate_operand" "=l,l,l,l,>,l, m,*r")
(match_operand:DI 1 "general_operand" "l, I,J,>,l,mi,l,*r"))]
"TARGET_THUMB
- && !TARGET_CIRRUS
+ && !(TARGET_HARD_FLOAT && TARGET_MAVERICK)
&& ( register_operand (operands[0], DImode)
|| register_operand (operands[1], DImode))"
"*
@@ -3896,7 +4310,7 @@
case 5:
return thumb_load_double_from_address (operands);
case 6:
- operands[2] = gen_rtx (MEM, SImode,
+ operands[2] = gen_rtx_MEM (SImode,
plus_constant (XEXP (operands[0], 0), 4));
output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands);
return \"\";
@@ -3907,7 +4321,7 @@
}
}"
[(set_attr "length" "4,4,6,2,2,6,4,4")
- (set_attr "type" "*,*,*,load,store2,load,store2,*")
+ (set_attr "type" "*,*,*,load2,store2,load2,store2,*")
(set_attr "pool_range" "*,*,*,*,*,1020,*,*")]
)
@@ -3921,14 +4335,14 @@
/* Everything except mem = const or mem = mem can be done easily. */
if (GET_CODE (operands[0]) == MEM)
operands[1] = force_reg (SImode, operands[1]);
- if (GET_CODE (operands[1]) == CONST_INT
+ if (arm_general_register_operand (operands[0], SImode)
+ && GET_CODE (operands[1]) == CONST_INT
&& !(const_ok_for_arm (INTVAL (operands[1]))
|| const_ok_for_arm (~INTVAL (operands[1]))))
{
- arm_split_constant (SET, SImode, INTVAL (operands[1]), operands[0],
- NULL_RTX,
- (no_new_pseudos ? 0
- : preserve_subexpressions_p ()));
+ arm_split_constant (SET, SImode, NULL_RTX,
+ INTVAL (operands[1]), operands[0], NULL_RTX,
+ optimize && !no_new_pseudos);
DONE;
}
}
@@ -3940,13 +4354,37 @@
operands[1] = force_reg (SImode, operands[1]);
}
}
-
- if (flag_pic
- && (CONSTANT_P (operands[1])
- || symbol_mentioned_p (operands[1])
- || label_mentioned_p (operands[1])))
- operands[1] = legitimize_pic_address (operands[1], SImode,
- (no_new_pseudos ? operands[0] : 0));
+
+ /* Recognize the case where operand[1] is a reference to thread-local
+ data and load its address to a register. */
+ if (arm_tls_referenced_p (operands[1]))
+ {
+ rtx tmp = operands[1];
+ rtx addend = NULL;
+
+ if (GET_CODE (tmp) == CONST && GET_CODE (XEXP (tmp, 0)) == PLUS)
+ {
+ addend = XEXP (XEXP (tmp, 0), 1);
+ tmp = XEXP (XEXP (tmp, 0), 0);
+ }
+
+ gcc_assert (GET_CODE (tmp) == SYMBOL_REF);
+ gcc_assert (SYMBOL_REF_TLS_MODEL (tmp) != 0);
+
+ tmp = legitimize_tls_address (tmp, no_new_pseudos ? operands[0] : 0);
+ if (addend)
+ {
+ tmp = gen_rtx_PLUS (SImode, tmp, addend);
+ tmp = force_operand (tmp, operands[0]);
+ }
+ operands[1] = tmp;
+ }
+ else if (flag_pic
+ && (CONSTANT_P (operands[1])
+ || symbol_mentioned_p (operands[1])
+ || label_mentioned_p (operands[1])))
+ operands[1] = legitimize_pic_address (operands[1], SImode,
+ (no_new_pseudos ? operands[0] : 0));
"
)
@@ -3954,6 +4392,7 @@
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r, m")
(match_operand:SI 1 "general_operand" "rI,K,mi,r"))]
"TARGET_ARM && ! TARGET_IWMMXT
+ && !(TARGET_HARD_FLOAT && TARGET_VFP)
&& ( register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode))"
"@
@@ -3961,22 +4400,22 @@
mvn%?\\t%0, #%B1
ldr%?\\t%0, %1
str%?\\t%1, %0"
- [(set_attr "type" "*,*,load,store1")
+ [(set_attr "type" "*,*,load1,store1")
(set_attr "predicable" "yes")
(set_attr "pool_range" "*,*,4096,*")
(set_attr "neg_pool_range" "*,*,4084,*")]
)
(define_split
- [(set (match_operand:SI 0 "s_register_operand" "")
+ [(set (match_operand:SI 0 "arm_general_register_operand" "")
(match_operand:SI 1 "const_int_operand" ""))]
"TARGET_ARM
&& (!(const_ok_for_arm (INTVAL (operands[1]))
|| const_ok_for_arm (~INTVAL (operands[1]))))"
[(clobber (const_int 0))]
"
- arm_split_constant (SET, SImode, INTVAL (operands[1]), operands[0],
- NULL_RTX, 0);
+ arm_split_constant (SET, SImode, NULL_RTX,
+ INTVAL (operands[1]), operands[0], NULL_RTX, 0);
DONE;
"
)
@@ -3998,14 +4437,14 @@
str\\t%1, %0
mov\\t%0, %1"
[(set_attr "length" "2,2,4,4,2,2,2,2,2")
- (set_attr "type" "*,*,*,*,load,store1,load,store1,*")
+ (set_attr "type" "*,*,*,*,load1,store1,load1,store1,*")
(set_attr "pool_range" "*,*,*,*,*,*,1020,*,*")]
)
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(match_operand:SI 1 "const_int_operand" ""))]
- "TARGET_THUMB && CONST_OK_FOR_THUMB_LETTER (INTVAL (operands[1]), 'J')"
+ "TARGET_THUMB && satisfies_constraint_J (operands[1])"
[(set (match_dup 0) (match_dup 1))
(set (match_dup 0) (neg:SI (match_dup 0)))]
"operands[1] = GEN_INT (- INTVAL (operands[1]));"
@@ -4014,7 +4453,7 @@
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(match_operand:SI 1 "const_int_operand" ""))]
- "TARGET_THUMB && CONST_OK_FOR_THUMB_LETTER (INTVAL (operands[1]), 'K')"
+ "TARGET_THUMB && satisfies_constraint_K (operands[1])"
[(set (match_dup 0) (match_dup 1))
(set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))]
"
@@ -4050,7 +4489,7 @@
(unspec:SI [(match_operand:SI 1 "" "mX")] UNSPEC_PIC_SYM))]
"TARGET_ARM && flag_pic"
"ldr%?\\t%0, %1"
- [(set_attr "type" "load")
+ [(set_attr "type" "load1")
(set (attr "pool_range") (const_int 4096))
(set (attr "neg_pool_range") (const_int 4084))]
)
@@ -4060,7 +4499,7 @@
(unspec:SI [(match_operand:SI 1 "" "mX")] UNSPEC_PIC_SYM))]
"TARGET_THUMB && flag_pic"
"ldr\\t%0, %1"
- [(set_attr "type" "load")
+ [(set_attr "type" "load1")
(set (attr "pool_range") (const_int 1024))]
)
@@ -4070,7 +4509,7 @@
[(set (match_operand:SI 0 "s_register_operand" "")
(unspec:SI [(match_operand 1 "" "") (match_dup 2)] UNSPEC_PIC_SYM))]
"TARGET_ARM && flag_pic"
- "operands[2] = pic_offset_table_rtx;"
+ "operands[2] = cfun->machine->pic_reg;"
)
(define_insn "*pic_load_addr_based_insn"
@@ -4078,7 +4517,7 @@
(unspec:SI [(match_operand 1 "" "")
(match_operand 2 "s_register_operand" "r")]
UNSPEC_PIC_SYM))]
- "TARGET_EITHER && flag_pic && operands[2] == pic_offset_table_rtx"
+ "TARGET_EITHER && flag_pic && operands[2] == cfun->machine->pic_reg"
"*
#ifdef AOF_ASSEMBLER
operands[1] = aof_pic_entry (operands[1]);
@@ -4086,7 +4525,7 @@
output_asm_insn (\"ldr%?\\t%0, %a1\", operands);
return \"\";
"
- [(set_attr "type" "load")
+ [(set_attr "type" "load1")
(set (attr "pool_range")
(if_then_else (eq_attr "is_thumb" "yes")
(const_int 1024)
@@ -4098,41 +4537,79 @@
)
(define_insn "pic_add_dot_plus_four"
- [(set (match_operand:SI 0 "register_operand" "+r")
- (unspec:SI [(plus:SI (match_dup 0)
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(plus:SI (match_operand:SI 1 "register_operand" "0")
(const (plus:SI (pc) (const_int 4))))]
UNSPEC_PIC_BASE))
- (use (label_ref (match_operand 1 "" "")))]
- "TARGET_THUMB && flag_pic"
+ (use (match_operand 2 "" ""))]
+ "TARGET_THUMB"
"*
- (*targetm.asm_out.internal_label) (asm_out_file, \"L\",
- CODE_LABEL_NUMBER (operands[1]));
+ (*targetm.asm_out.internal_label) (asm_out_file, \"LPIC\",
+ INTVAL (operands[2]));
return \"add\\t%0, %|pc\";
"
[(set_attr "length" "2")]
)
(define_insn "pic_add_dot_plus_eight"
- [(set (match_operand:SI 0 "register_operand" "+r")
- (unspec:SI [(plus:SI (match_dup 0)
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(plus:SI (match_operand:SI 1 "register_operand" "r")
(const (plus:SI (pc) (const_int 8))))]
UNSPEC_PIC_BASE))
- (use (label_ref (match_operand 1 "" "")))]
- "TARGET_ARM && flag_pic"
+ (use (match_operand 2 "" ""))]
+ "TARGET_ARM"
"*
- (*targetm.asm_out.internal_label) (asm_out_file, \"L\",
- CODE_LABEL_NUMBER (operands[1]));
- return \"add%?\\t%0, %|pc, %0\";
+ (*targetm.asm_out.internal_label) (asm_out_file, \"LPIC\",
+ INTVAL (operands[2]));
+ return \"add%?\\t%0, %|pc, %1\";
"
[(set_attr "predicable" "yes")]
)
+(define_insn "tls_load_dot_plus_eight"
+ [(set (match_operand:SI 0 "register_operand" "+r")
+ (mem:SI (unspec:SI [(plus:SI (match_operand:SI 1 "register_operand" "r")
+ (const (plus:SI (pc) (const_int 8))))]
+ UNSPEC_PIC_BASE)))
+ (use (match_operand 2 "" ""))]
+ "TARGET_ARM"
+ "*
+ (*targetm.asm_out.internal_label) (asm_out_file, \"LPIC\",
+ INTVAL (operands[2]));
+ return \"ldr%?\\t%0, [%|pc, %1]\t\t@ tls_load_dot_plus_eight\";
+ "
+ [(set_attr "predicable" "yes")]
+)
+
+;; PIC references to local variables can generate pic_add_dot_plus_eight
+;; followed by a load. These sequences can be crunched down to
+;; tls_load_dot_plus_eight by a peephole.
+
+(define_peephole2
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (unspec:SI [(plus:SI (match_operand:SI 3 "register_operand" "")
+ (const (plus:SI (pc) (const_int 8))))]
+ UNSPEC_PIC_BASE))
+ (use (label_ref (match_operand 1 "" "")))])
+ (set (match_operand:SI 2 "register_operand" "") (mem:SI (match_dup 0)))]
+ "TARGET_ARM && peep2_reg_dead_p (2, operands[0])"
+ [(parallel [(set (match_dup 2)
+ (mem:SI (unspec:SI [(plus:SI (match_dup 3)
+ (const (plus:SI (pc) (const_int 8))))]
+ UNSPEC_PIC_BASE)))
+ (use (label_ref (match_dup 1)))])]
+ ""
+)
+
(define_expand "builtin_setjmp_receiver"
[(label_ref (match_operand 0 "" ""))]
"flag_pic"
"
{
- arm_finalize_pic (0);
+ /* r3 is clobbered by set/longjmp, so we can use it as a scratch
+ register. */
+ if (arm_pic_register != INVALID_REGNUM)
+ arm_load_pic_register (1UL << 3);
DONE;
}")
@@ -4323,7 +4800,7 @@
emit_insn (gen_movsi (reg, GEN_INT (val)));
operands[1] = gen_lowpart (HImode, reg);
}
- else if (arm_arch4 && !no_new_pseudos && optimize > 0
+ else if (arm_arch4 && optimize && !no_new_pseudos
&& GET_CODE (operands[1]) == MEM)
{
rtx reg = gen_reg_rtx (SImode);
@@ -4333,89 +4810,39 @@
}
else if (!arm_arch4)
{
- /* Note: We do not have to worry about TARGET_MMU_TRAPS
- for v4 and up architectures because LDRH instructions will
- be used to access the HI values, and these cannot generate
- unaligned word access faults in the MMU. */
if (GET_CODE (operands[1]) == MEM)
{
- if (TARGET_MMU_TRAPS)
- {
- rtx base;
- rtx offset = const0_rtx;
- rtx reg = gen_reg_rtx (SImode);
-
- if ((GET_CODE (base = XEXP (operands[1], 0)) == REG
- || (GET_CODE (base) == PLUS
- && (GET_CODE (offset = XEXP (base, 1))
- == CONST_INT)
- && ((INTVAL(offset) & 1) != 1)
- && GET_CODE (base = XEXP (base, 0)) == REG))
- && REGNO_POINTER_ALIGN (REGNO (base)) >= 32)
- {
- HOST_WIDE_INT new_offset = INTVAL (offset) & ~3;
- rtx new;
-
- new = gen_rtx_MEM (SImode,
- plus_constant (base, new_offset));
- MEM_COPY_ATTRIBUTES (new, operands[1]);
- emit_insn (gen_movsi (reg, new));
- if (((INTVAL (offset) & 2) != 0)
- ^ (BYTES_BIG_ENDIAN ? 1 : 0))
- {
- rtx reg2 = gen_reg_rtx (SImode);
-
- emit_insn (gen_lshrsi3 (reg2, reg,
- GEN_INT (16)));
- reg = reg2;
- }
- }
- else
- emit_insn (gen_movhi_bytes (reg, operands[1]));
-
- operands[1] = gen_lowpart (HImode, reg);
- }
- else if (BYTES_BIG_ENDIAN)
+ rtx base;
+ rtx offset = const0_rtx;
+ rtx reg = gen_reg_rtx (SImode);
+
+ if ((GET_CODE (base = XEXP (operands[1], 0)) == REG
+ || (GET_CODE (base) == PLUS
+ && (GET_CODE (offset = XEXP (base, 1))
+ == CONST_INT)
+ && ((INTVAL(offset) & 1) != 1)
+ && GET_CODE (base = XEXP (base, 0)) == REG))
+ && REGNO_POINTER_ALIGN (REGNO (base)) >= 32)
{
- rtx base;
- rtx offset = const0_rtx;
-
- if ((GET_CODE (base = XEXP (operands[1], 0)) == REG
- || (GET_CODE (base) == PLUS
- && (GET_CODE (offset = XEXP (base, 1))
- == CONST_INT)
- && GET_CODE (base = XEXP (base, 0)) == REG))
- && REGNO_POINTER_ALIGN (REGNO (base)) >= 32)
- {
- rtx reg = gen_reg_rtx (SImode);
- rtx new;
-
- if ((INTVAL (offset) & 2) == 2)
- {
- HOST_WIDE_INT new_offset = INTVAL (offset) ^ 2;
- new = gen_rtx_MEM (SImode,
- plus_constant (base,
- new_offset));
- MEM_COPY_ATTRIBUTES (new, operands[1]);
- emit_insn (gen_movsi (reg, new));
- }
- else
- {
- new = gen_rtx_MEM (SImode,
- XEXP (operands[1], 0));
- MEM_COPY_ATTRIBUTES (new, operands[1]);
- emit_insn (gen_rotated_loadsi (reg, new));
- }
-
- operands[1] = gen_lowpart (HImode, reg);
- }
- else
- {
- emit_insn (gen_movhi_bigend (operands[0],
- operands[1]));
- DONE;
- }
+ rtx new;
+
+ new = widen_memory_access (operands[1], SImode,
+ ((INTVAL (offset) & ~3)
+ - INTVAL (offset)));
+ emit_insn (gen_movsi (reg, new));
+ if (((INTVAL (offset) & 2) != 0)
+ ^ (BYTES_BIG_ENDIAN ? 1 : 0))
+ {
+ rtx reg2 = gen_reg_rtx (SImode);
+
+ emit_insn (gen_lshrsi3 (reg2, reg, GEN_INT (16)));
+ reg = reg2;
+ }
}
+ else
+ emit_insn (gen_movhi_bytes (reg, operands[1]));
+
+ operands[1] = gen_lowpart (HImode, reg);
}
}
}
@@ -4426,8 +4853,7 @@
{
/* Writing a constant to memory needs a scratch, which should
be handled with SECONDARY_RELOADs. */
- if (GET_CODE (operands[0]) != REG)
- abort ();
+ gcc_assert (GET_CODE (operands[0]) == REG);
operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0);
emit_insn (gen_movsi (operands[0], operands[1]));
@@ -4438,8 +4864,13 @@
{
if (!no_new_pseudos)
{
- if (GET_CODE (operands[0]) != REG)
- operands[1] = force_reg (HImode, operands[1]);
+ if (GET_CODE (operands[1]) == CONST_INT)
+ {
+ rtx reg = gen_reg_rtx (SImode);
+
+ emit_insn (gen_movsi (reg, operands[1]));
+ operands[1] = gen_lowpart (HImode, reg);
+ }
/* ??? We shouldn't really get invalid addresses here, but this can
happen if we are passed a SP (never OK for HImode/QImode) or
@@ -4462,17 +4893,28 @@
operands[1]
= replace_equiv_address (operands[1],
copy_to_reg (XEXP (operands[1], 0)));
+
+ if (GET_CODE (operands[1]) == MEM && optimize > 0)
+ {
+ rtx reg = gen_reg_rtx (SImode);
+
+ emit_insn (gen_zero_extendhisi2 (reg, operands[1]));
+ operands[1] = gen_lowpart (HImode, reg);
+ }
+
+ if (GET_CODE (operands[0]) == MEM)
+ operands[1] = force_reg (HImode, operands[1]);
}
- /* Handle loading a large integer during reload. */
else if (GET_CODE (operands[1]) == CONST_INT
- && !CONST_OK_FOR_THUMB_LETTER (INTVAL (operands[1]), 'I'))
+ && !satisfies_constraint_I (operands[1]))
{
+ /* Handle loading a large integer during reload. */
+
/* Writing a constant to memory needs a scratch, which should
be handled with SECONDARY_RELOADs. */
- if (GET_CODE (operands[0]) != REG)
- abort ();
+ gcc_assert (GET_CODE (operands[0]) == REG);
- operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0);
+ operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0);
emit_insn (gen_movsi (operands[0], operands[1]));
DONE;
}
@@ -4494,7 +4936,7 @@
case 3: return \"mov %0, %1\";
case 4: return \"mov %0, %1\";
case 5: return \"mov %0, %1\";
- default: abort ();
+ default: gcc_unreachable ();
case 1:
/* The stack pointer can end up being taken as an index register.
Catch this case here and deal with it. */
@@ -4514,28 +4956,10 @@
return \"ldrh %0, %1\";
}"
[(set_attr "length" "2,4,2,2,2,2")
- (set_attr "type" "*,load,store1,*,*,*")]
+ (set_attr "type" "*,load1,store1,*,*,*")]
)
-(define_insn "rotated_loadsi"
- [(set (match_operand:SI 0 "s_register_operand" "=r")
- (rotate:SI (match_operand:SI 1 "offsettable_memory_operand" "o")
- (const_int 16)))]
- "TARGET_ARM && (!TARGET_MMU_TRAPS)"
- "*
- {
- rtx ops[2];
-
- ops[0] = operands[0];
- ops[1] = gen_rtx_MEM (SImode, plus_constant (XEXP (operands[1], 0), 2));
- output_asm_insn (\"ldr%?\\t%0, %1\\t%@ load-rotate\", ops);
- return \"\";
- }"
- [(set_attr "type" "load")
- (set_attr "predicable" "yes")]
-)
-
(define_expand "movhi_bytes"
[(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" "")))
(set (match_dup 3)
@@ -4548,10 +4972,8 @@
rtx mem1, mem2;
rtx addr = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
- mem1 = gen_rtx_MEM (QImode, addr);
- MEM_COPY_ATTRIBUTES (mem1, operands[1]);
- mem2 = gen_rtx_MEM (QImode, plus_constant (addr, 1));
- MEM_COPY_ATTRIBUTES (mem2, operands[1]);
+ mem1 = change_address (operands[1], QImode, addr);
+ mem2 = change_address (operands[1], QImode, plus_constant (addr, 1));
operands[0] = gen_lowpart (SImode, operands[0]);
operands[1] = mem1;
operands[2] = gen_reg_rtx (SImode);
@@ -4599,86 +5021,39 @@
"@
mov%?\\t%0, %1\\t%@ movhi
mvn%?\\t%0, #%B1\\t%@ movhi
- str%?h\\t%1, %0\\t%@ movhi
+ str%?h\\t%1, %0\\t%@ movhi
ldr%?h\\t%0, %1\\t%@ movhi"
- [(set_attr "type" "*,*,store1,load")
+ [(set_attr "type" "*,*,store1,load1")
(set_attr "predicable" "yes")
(set_attr "pool_range" "*,*,*,256")
(set_attr "neg_pool_range" "*,*,*,244")]
)
-(define_insn "*movhi_insn_littleend"
- [(set (match_operand:HI 0 "s_register_operand" "=r,r,r")
- (match_operand:HI 1 "general_operand" "rI,K,m"))]
- "TARGET_ARM
- && !arm_arch4
- && !BYTES_BIG_ENDIAN
- && !TARGET_MMU_TRAPS
- && (GET_CODE (operands[1]) != CONST_INT
- || const_ok_for_arm (INTVAL (operands[1]))
- || const_ok_for_arm (~INTVAL (operands[1])))"
- "@
- mov%?\\t%0, %1\\t%@ movhi
- mvn%?\\t%0, #%B1\\t%@ movhi
- ldr%?\\t%0, %1\\t%@ movhi"
- [(set_attr "type" "*,*,load")
- (set_attr "predicable" "yes")
- (set_attr "pool_range" "4096")
- (set_attr "neg_pool_range" "4084")]
-)
-
-(define_insn "*movhi_insn_bigend"
- [(set (match_operand:HI 0 "s_register_operand" "=r,r,r")
- (match_operand:HI 1 "general_operand" "rI,K,m"))]
- "TARGET_ARM
- && !arm_arch4
- && BYTES_BIG_ENDIAN
- && !TARGET_MMU_TRAPS
- && (GET_CODE (operands[1]) != CONST_INT
- || const_ok_for_arm (INTVAL (operands[1]))
- || const_ok_for_arm (~INTVAL (operands[1])))"
- "@
- mov%?\\t%0, %1\\t%@ movhi
- mvn%?\\t%0, #%B1\\t%@ movhi
- ldr%?\\t%0, %1\\t%@ movhi_bigend\;mov%?\\t%0, %0, asr #16"
- [(set_attr "type" "*,*,load")
- (set_attr "predicable" "yes")
- (set_attr "length" "4,4,8")
- (set_attr "pool_range" "*,*,4092")
- (set_attr "neg_pool_range" "*,*,4084")]
-)
-
-(define_insn "*loadhi_si_bigend"
- [(set (match_operand:SI 0 "s_register_operand" "=r")
- (rotate:SI (subreg:SI (match_operand:HI 1 "memory_operand" "m") 0)
- (const_int 16)))]
- "TARGET_ARM
- && BYTES_BIG_ENDIAN
- && !TARGET_MMU_TRAPS"
- "ldr%?\\t%0, %1\\t%@ movhi_bigend"
- [(set_attr "type" "load")
- (set_attr "predicable" "yes")
- (set_attr "pool_range" "4096")
- (set_attr "neg_pool_range" "4084")]
-)
-
(define_insn "*movhi_bytes"
[(set (match_operand:HI 0 "s_register_operand" "=r,r")
(match_operand:HI 1 "arm_rhs_operand" "rI,K"))]
- "TARGET_ARM && TARGET_MMU_TRAPS"
+ "TARGET_ARM"
"@
mov%?\\t%0, %1\\t%@ movhi
mvn%?\\t%0, #%B1\\t%@ movhi"
[(set_attr "predicable" "yes")]
)
-(define_insn "thumb_movhi_clobber"
- [(set (match_operand:HI 0 "memory_operand" "=m")
- (match_operand:HI 1 "register_operand" "l"))
- (clobber (match_operand:SI 2 "register_operand" "=&l"))]
+(define_expand "thumb_movhi_clobber"
+ [(set (match_operand:HI 0 "memory_operand" "")
+ (match_operand:HI 1 "register_operand" ""))
+ (clobber (match_operand:DI 2 "register_operand" ""))]
"TARGET_THUMB"
- "*
- abort ();"
+ "
+ if (strict_memory_address_p (HImode, XEXP (operands[0], 0))
+ && REGNO (operands[1]) <= LAST_LO_REGNUM)
+ {
+ emit_insn (gen_movhi (operands[0], operands[1]));
+ DONE;
+ }
+ /* XXX Fixme, need to handle other cases here as well. */
+ gcc_unreachable ();
+ "
)
;; We use a DImode scratch because we may occasionally need an additional
@@ -4701,7 +5076,7 @@
[(parallel [(match_operand:HI 0 "s_register_operand" "=r")
(match_operand:HI 1 "arm_reload_memory_operand" "o")
(match_operand:DI 2 "s_register_operand" "=&r")])]
- "TARGET_THUMB || (TARGET_ARM && TARGET_MMU_TRAPS)"
+ "TARGET_EITHER"
"
if (TARGET_ARM)
arm_reload_in_hi (operands);
@@ -4715,37 +5090,20 @@
(match_operand:QI 1 "general_operand" ""))]
"TARGET_EITHER"
"
- if (TARGET_ARM)
- {
- /* Everything except mem = const or mem = mem can be done easily */
-
- if (!no_new_pseudos)
- {
- if (GET_CODE (operands[1]) == CONST_INT)
- {
- rtx reg = gen_reg_rtx (SImode);
-
- emit_insn (gen_movsi (reg, operands[1]));
- operands[1] = gen_lowpart (QImode, reg);
- }
- if (GET_CODE (operands[1]) == MEM && optimize > 0)
- {
- rtx reg = gen_reg_rtx (SImode);
+ /* Everything except mem = const or mem = mem can be done easily */
- emit_insn (gen_zero_extendqisi2 (reg, operands[1]));
- operands[1] = gen_lowpart (QImode, reg);
- }
- if (GET_CODE (operands[0]) == MEM)
- operands[1] = force_reg (QImode, operands[1]);
- }
- }
- else /* TARGET_THUMB */
+ if (!no_new_pseudos)
{
- if (!no_new_pseudos)
- {
- if (GET_CODE (operands[0]) != REG)
- operands[1] = force_reg (QImode, operands[1]);
+ if (GET_CODE (operands[1]) == CONST_INT)
+ {
+ rtx reg = gen_reg_rtx (SImode);
+ emit_insn (gen_movsi (reg, operands[1]));
+ operands[1] = gen_lowpart (QImode, reg);
+ }
+
+ if (TARGET_THUMB)
+ {
/* ??? We shouldn't really get invalid addresses here, but this can
happen if we are passed a SP (never OK for HImode/QImode) or
virtual register (rejected by GO_IF_LEGITIMATE_ADDRESS for
@@ -4766,20 +5124,32 @@
operands[1]
= replace_equiv_address (operands[1],
copy_to_reg (XEXP (operands[1], 0)));
- }
+ }
+
+ if (GET_CODE (operands[1]) == MEM && optimize > 0)
+ {
+ rtx reg = gen_reg_rtx (SImode);
+
+ emit_insn (gen_zero_extendqisi2 (reg, operands[1]));
+ operands[1] = gen_lowpart (QImode, reg);
+ }
+
+ if (GET_CODE (operands[0]) == MEM)
+ operands[1] = force_reg (QImode, operands[1]);
+ }
+ else if (TARGET_THUMB
+ && GET_CODE (operands[1]) == CONST_INT
+ && !satisfies_constraint_I (operands[1]))
+ {
/* Handle loading a large integer during reload. */
- else if (GET_CODE (operands[1]) == CONST_INT
- && !CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I'))
- {
- /* Writing a constant to memory needs a scratch, which should
- be handled with SECONDARY_RELOADs. */
- if (GET_CODE (operands[0]) != REG)
- abort ();
- operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0);
- emit_insn (gen_movsi (operands[0], operands[1]));
- DONE;
- }
+ /* Writing a constant to memory needs a scratch, which should
+ be handled with SECONDARY_RELOADs. */
+ gcc_assert (GET_CODE (operands[0]) == REG);
+
+ operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0);
+ emit_insn (gen_movsi (operands[0], operands[1]));
+ DONE;
}
"
)
@@ -4796,7 +5166,7 @@
mvn%?\\t%0, #%B1
ldr%?b\\t%0, %1
str%?b\\t%1, %0"
- [(set_attr "type" "*,*,load,store1")
+ [(set_attr "type" "*,*,load1,store1")
(set_attr "predicable" "yes")]
)
@@ -4814,7 +5184,7 @@
mov\\t%0, %1
mov\\t%0, %1"
[(set_attr "length" "2")
- (set_attr "type" "*,load,store1,*,*,*")
+ (set_attr "type" "*,load1,store1,*,*,*")
(set_attr "pool_range" "*,32,*,*,*,*")]
)
@@ -4839,11 +5209,12 @@
"
)
+;; Transform a floating-point move of a constant into a core register into
+;; an SImode operation.
(define_split
- [(set (match_operand:SF 0 "nonimmediate_operand" "")
+ [(set (match_operand:SF 0 "arm_general_register_operand" "")
(match_operand:SF 1 "immediate_operand" ""))]
"TARGET_ARM
- && !TARGET_HARD_FLOAT
&& reload_completed
&& GET_CODE (operands[1]) == CONST_DOUBLE"
[(set (match_dup 2) (match_dup 3))]
@@ -4859,7 +5230,6 @@
[(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m")
(match_operand:SF 1 "general_operand" "r,mE,r"))]
"TARGET_ARM
- && !TARGET_CIRRUS
&& TARGET_SOFT_FLOAT
&& (GET_CODE (operands[0]) != MEM
|| register_operand (operands[1], SFmode))"
@@ -4869,7 +5239,7 @@
str%?\\t%1, %0\\t%@ float"
[(set_attr "length" "4,4,4")
(set_attr "predicable" "yes")
- (set_attr "type" "*,load,store1")
+ (set_attr "type" "*,load1,store1")
(set_attr "pool_range" "*,4096,*")
(set_attr "neg_pool_range" "*,4084,*")]
)
@@ -4890,7 +5260,7 @@
mov\\t%0, %1
mov\\t%0, %1"
[(set_attr "length" "2")
- (set_attr "type" "*,load,store1,load,store1,*,*")
+ (set_attr "type" "*,load1,store1,load1,store1,*,*")
(set_attr "pool_range" "*,*,*,1020,*,*,*")]
)
@@ -4948,7 +5318,8 @@
emit_insn (gen_addsi3 (operands[2], XEXP (XEXP (operands[0], 0), 0),
XEXP (XEXP (operands[0], 0), 1)));
- emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_MEM (DFmode, operands[2]),
+ emit_insn (gen_rtx_SET (VOIDmode,
+ replace_equiv_address (operands[0], operands[2]),
operands[1]));
if (code == POST_DEC)
@@ -4959,14 +5330,24 @@
)
(define_insn "*movdf_soft_insn"
- [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=r,r,m")
- (match_operand:DF 1 "soft_df_operand" "r,mF,r"))]
+ [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=r,r,r,r,m")
+ (match_operand:DF 1 "soft_df_operand" "rDa,Db,Dc,mF,r"))]
"TARGET_ARM && TARGET_SOFT_FLOAT
- && !TARGET_CIRRUS
+ && ( register_operand (operands[0], DFmode)
+ || register_operand (operands[1], DFmode))"
+ "*
+ switch (which_alternative)
+ {
+ case 0:
+ case 1:
+ case 2:
+ return \"#\";
+ default:
+ return output_move_double (operands);
+ }
"
- "* return output_move_double (operands);"
- [(set_attr "length" "8,8,8")
- (set_attr "type" "*,load,store2")
+ [(set_attr "length" "8,12,16,8,8")
+ (set_attr "type" "*,*,*,load2,store2")
(set_attr "pool_range" "1020")
(set_attr "neg_pool_range" "1008")]
)
@@ -4996,8 +5377,8 @@
case 3:
return thumb_load_double_from_address (operands);
case 4:
- operands[2] = gen_rtx (MEM, SImode,
- plus_constant (XEXP (operands[0], 0), 4));
+ operands[2] = gen_rtx_MEM (SImode,
+ plus_constant (XEXP (operands[0], 0), 4));
output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands);
return \"\";
case 5:
@@ -5007,10 +5388,20 @@
}
"
[(set_attr "length" "4,2,2,6,4,4")
- (set_attr "type" "*,load,store2,load,store2,*")
+ (set_attr "type" "*,load2,store2,load2,store2,*")
(set_attr "pool_range" "*,*,*,1020,*,*")]
)
+(define_expand "movxf"
+ [(set (match_operand:XF 0 "general_operand" "")
+ (match_operand:XF 1 "general_operand" ""))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+ "
+ if (GET_CODE (operands[0]) == MEM)
+ operands[1] = force_reg (XFmode, operands[1]);
+ "
+)
+
;; Vector Moves
(define_expand "movv2si"
[(set (match_operand:V2SI 0 "nonimmediate_operand" "")
@@ -5045,7 +5436,7 @@
"TARGET_ARM"
{
HOST_WIDE_INT offset = 0;
-
+
/* Support only fixed point registers. */
if (GET_CODE (operands[2]) != CONST_INT
|| INTVAL (operands[2]) > 14
@@ -5060,7 +5451,6 @@
= arm_gen_load_multiple (REGNO (operands[0]), INTVAL (operands[2]),
force_reg (SImode, XEXP (operands[1], 0)),
TRUE, FALSE, operands[1], &offset);
-
})
;; Load multiple with write-back
@@ -5080,10 +5470,28 @@
(mem:SI (plus:SI (match_dup 2) (const_int 12))))])]
"TARGET_ARM && XVECLEN (operands[0], 0) == 5"
"ldm%?ia\\t%1!, {%3, %4, %5, %6}"
- [(set_attr "type" "load")
+ [(set_attr "type" "load4")
(set_attr "predicable" "yes")]
)
+(define_insn "*ldmsi_postinc4_thumb"
+ [(match_parallel 0 "load_multiple_operation"
+ [(set (match_operand:SI 1 "s_register_operand" "=l")
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1")
+ (const_int 16)))
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
+ (mem:SI (match_dup 2)))
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
+ (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+ (set (match_operand:SI 5 "arm_hard_register_operand" "")
+ (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+ (set (match_operand:SI 6 "arm_hard_register_operand" "")
+ (mem:SI (plus:SI (match_dup 2) (const_int 12))))])]
+ "TARGET_THUMB && XVECLEN (operands[0], 0) == 5"
+ "ldmia\\t%1!, {%3, %4, %5, %6}"
+ [(set_attr "type" "load4")]
+)
+
(define_insn "*ldmsi_postinc3"
[(match_parallel 0 "load_multiple_operation"
[(set (match_operand:SI 1 "s_register_operand" "=r")
@@ -5097,7 +5505,7 @@
(mem:SI (plus:SI (match_dup 2) (const_int 8))))])]
"TARGET_ARM && XVECLEN (operands[0], 0) == 4"
"ldm%?ia\\t%1!, {%3, %4, %5}"
- [(set_attr "type" "load")
+ [(set_attr "type" "load3")
(set_attr "predicable" "yes")]
)
@@ -5112,7 +5520,7 @@
(mem:SI (plus:SI (match_dup 2) (const_int 4))))])]
"TARGET_ARM && XVECLEN (operands[0], 0) == 3"
"ldm%?ia\\t%1!, {%3, %4}"
- [(set_attr "type" "load")
+ [(set_attr "type" "load2")
(set_attr "predicable" "yes")]
)
@@ -5130,7 +5538,7 @@
(mem:SI (plus:SI (match_dup 1) (const_int 12))))])]
"TARGET_ARM && XVECLEN (operands[0], 0) == 4"
"ldm%?ia\\t%1, {%2, %3, %4, %5}"
- [(set_attr "type" "load")
+ [(set_attr "type" "load4")
(set_attr "predicable" "yes")]
)
@@ -5144,7 +5552,7 @@
(mem:SI (plus:SI (match_dup 1) (const_int 8))))])]
"TARGET_ARM && XVECLEN (operands[0], 0) == 3"
"ldm%?ia\\t%1, {%2, %3, %4}"
- [(set_attr "type" "load")
+ [(set_attr "type" "load3")
(set_attr "predicable" "yes")]
)
@@ -5156,7 +5564,7 @@
(mem:SI (plus:SI (match_dup 1) (const_int 4))))])]
"TARGET_ARM && XVECLEN (operands[0], 0) == 2"
"ldm%?ia\\t%1, {%2, %3}"
- [(set_attr "type" "load")
+ [(set_attr "type" "load2")
(set_attr "predicable" "yes")]
)
@@ -5205,6 +5613,24 @@
(set_attr "type" "store4")]
)
+(define_insn "*stmsi_postinc4_thumb"
+ [(match_parallel 0 "store_multiple_operation"
+ [(set (match_operand:SI 1 "s_register_operand" "=l")
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1")
+ (const_int 16)))
+ (set (mem:SI (match_dup 2))
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
+ (match_operand:SI 4 "arm_hard_register_operand" ""))
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 8)))
+ (match_operand:SI 5 "arm_hard_register_operand" ""))
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 12)))
+ (match_operand:SI 6 "arm_hard_register_operand" ""))])]
+ "TARGET_THUMB && XVECLEN (operands[0], 0) == 5"
+ "stmia\\t%1!, {%3, %4, %5, %6}"
+ [(set_attr "type" "store4")]
+)
+
(define_insn "*stmsi_postinc3"
[(match_parallel 0 "store_multiple_operation"
[(set (match_operand:SI 1 "s_register_operand" "=r")
@@ -5285,7 +5711,7 @@
;; We could let this apply for blocks of less than this, but it clobbers so
;; many registers that there is then probably a better way.
-(define_expand "movstrqi"
+(define_expand "movmemqi"
[(match_operand:BLK 0 "general_operand" "")
(match_operand:BLK 1 "general_operand" "")
(match_operand:SI 2 "const_int_operand" "")
@@ -5294,7 +5720,7 @@
"
if (TARGET_ARM)
{
- if (arm_gen_movstrqi (operands))
+ if (arm_gen_movmemqi (operands))
DONE;
FAIL;
}
@@ -5304,7 +5730,7 @@
|| INTVAL (operands[2]) > 48)
FAIL;
- thumb_expand_movstrqi (operands);
+ thumb_expand_movmemqi (operands);
DONE;
}
"
@@ -5527,7 +5953,7 @@
(define_insn "*negated_cbranchsi4"
[(set (pc)
(if_then_else
- (match_operator 0 "arm_comparison_operator"
+ (match_operator 0 "equality_operator"
[(match_operand:SI 1 "s_register_operand" "l")
(neg:SI (match_operand:SI 2 "s_register_operand" "l"))])
(label_ref (match_operand 3 "" ""))
@@ -5603,6 +6029,50 @@
(const_int 8))))]
)
+(define_insn "*tlobits_cbranch"
+ [(set (pc)
+ (if_then_else
+ (match_operator 0 "equality_operator"
+ [(zero_extract:SI (match_operand:SI 1 "s_register_operand" "l")
+ (match_operand:SI 2 "const_int_operand" "i")
+ (const_int 0))
+ (const_int 0)])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))
+ (clobber (match_scratch:SI 4 "=l"))]
+ "TARGET_THUMB"
+ "*
+ {
+ rtx op[3];
+ op[0] = operands[4];
+ op[1] = operands[1];
+ op[2] = GEN_INT (32 - INTVAL (operands[2]));
+
+ output_asm_insn (\"lsl\\t%0, %1, %2\", op);
+ switch (get_attr_length (insn))
+ {
+ case 4: return \"b%d0\\t%l3\";
+ case 6: return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
+ default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
+ }
+ }"
+ [(set (attr "far_jump")
+ (if_then_else
+ (eq_attr "length" "8")
+ (const_string "yes")
+ (const_string "no")))
+ (set (attr "length")
+ (if_then_else
+ (and (ge (minus (match_dup 3) (pc)) (const_int -250))
+ (le (minus (match_dup 3) (pc)) (const_int 256)))
+ (const_int 4)
+ (if_then_else
+ (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
+ (le (minus (match_dup 3) (pc)) (const_int 2048)))
+ (const_int 6)
+ (const_int 8))))]
+)
+
(define_insn "*tstsi3_cbranch"
[(set (pc)
(if_then_else
@@ -6215,7 +6685,7 @@
(match_operator 3 "comparison_operator"
[(plus:SI
(match_operand:SI 1 "s_register_operand" "%l,l,l,0")
- (match_operand:SI 2 "reg_or_int_operand" "J,l,I,L"))
+ (match_operand:SI 2 "reg_or_int_operand" "J,l,L,IJ"))
(const_int 0)])
(label_ref (match_operand 4 "" ""))
(pc)))
@@ -6236,10 +6706,16 @@
output_asm_insn (\"cmn\t%1, %2\", operands);
break;
case 2:
- output_asm_insn (\"add\t%0, %1, %2\", operands);
+ if (INTVAL (operands[2]) < 0)
+ output_asm_insn (\"sub\t%0, %1, %2\", operands);
+ else
+ output_asm_insn (\"add\t%0, %1, %2\", operands);
break;
case 3:
- output_asm_insn (\"add\t%0, %0, %2\", operands);
+ if (INTVAL (operands[2]) < 0)
+ output_asm_insn (\"sub\t%0, %0, %2\", operands);
+ else
+ output_asm_insn (\"add\t%0, %0, %2\", operands);
break;
}
@@ -6407,12 +6883,9 @@
(define_expand "cmpsf"
[(match_operand:SF 0 "s_register_operand" "")
- (match_operand:SF 1 "fpa_rhs_operand" "")]
- "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
+ (match_operand:SF 1 "arm_float_compare_operand" "")]
+ "TARGET_ARM && TARGET_HARD_FLOAT"
"
- if (TARGET_CIRRUS && !cirrus_fp_register (operands[1], SFmode))
- operands[1] = force_reg (SFmode, operands[1]);
-
arm_compare_op0 = operands[0];
arm_compare_op1 = operands[1];
DONE;
@@ -6421,12 +6894,9 @@
(define_expand "cmpdf"
[(match_operand:DF 0 "s_register_operand" "")
- (match_operand:DF 1 "fpa_rhs_operand" "")]
- "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
+ (match_operand:DF 1 "arm_float_compare_operand" "")]
+ "TARGET_ARM && TARGET_HARD_FLOAT"
"
- if (TARGET_CIRRUS && !cirrus_fp_register (operands[1], DFmode))
- operands[1] = force_reg (DFmode, operands[1]);
-
arm_compare_op0 = operands[0];
arm_compare_op1 = operands[1];
DONE;
@@ -6454,7 +6924,9 @@
"cmp%?\\t%0, %1%S3"
[(set_attr "conds" "set")
(set_attr "shift" "1")
- ]
+ (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
+ (const_string "alu_shift")
+ (const_string "alu_shift_reg")))]
)
(define_insn "*cmpsi_shiftsi_swp"
@@ -6467,20 +6939,24 @@
"cmp%?\\t%0, %1%S3"
[(set_attr "conds" "set")
(set_attr "shift" "1")
- ]
+ (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
+ (const_string "alu_shift")
+ (const_string "alu_shift_reg")))]
)
-(define_insn "*cmpsi_neg_shiftsi"
- [(set (reg:CC CC_REGNUM)
- (compare:CC (match_operand:SI 0 "s_register_operand" "r")
- (neg:SI (match_operator:SI 3 "shift_operator"
- [(match_operand:SI 1 "s_register_operand" "r")
- (match_operand:SI 2 "arm_rhs_operand" "rM")]))))]
+(define_insn "*cmpsi_negshiftsi_si"
+ [(set (reg:CC_Z CC_REGNUM)
+ (compare:CC_Z
+ (neg:SI (match_operator:SI 1 "shift_operator"
+ [(match_operand:SI 2 "s_register_operand" "r")
+ (match_operand:SI 3 "reg_or_int_operand" "rM")]))
+ (match_operand:SI 0 "s_register_operand" "r")))]
"TARGET_ARM"
- "cmn%?\\t%0, %1%S3"
+ "cmn%?\\t%0, %2%S1"
[(set_attr "conds" "set")
- (set_attr "shift" "1")
- ]
+ (set (attr "type") (if_then_else (match_operand 3 "const_int_operand" "")
+ (const_string "alu_shift")
+ (const_string "alu_shift_reg")))]
)
;; Cirrus SF compare instruction
@@ -6488,7 +6964,7 @@
[(set (reg:CCFP CC_REGNUM)
(compare:CCFP (match_operand:SF 0 "cirrus_fp_register" "v")
(match_operand:SF 1 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfcmps%?\\tr15, %V0, %V1"
[(set_attr "type" "mav_farith")
(set_attr "cirrus" "compare")]
@@ -6499,7 +6975,7 @@
[(set (reg:CCFP CC_REGNUM)
(compare:CCFP (match_operand:DF 0 "cirrus_fp_register" "v")
(match_operand:DF 1 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfcmpd%?\\tr15, %V0, %V1"
[(set_attr "type" "mav_farith")
(set_attr "cirrus" "compare")]
@@ -6509,7 +6985,7 @@
(define_expand "cmpdi"
[(match_operand:DI 0 "cirrus_fp_register" "")
(match_operand:DI 1 "cirrus_fp_register" "")]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"{
arm_compare_op0 = operands[0];
arm_compare_op1 = operands[1];
@@ -6520,7 +6996,7 @@
[(set (reg:CC CC_REGNUM)
(compare:CC (match_operand:DI 0 "cirrus_fp_register" "v")
(match_operand:DI 1 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfcmp64%?\\tr15, %V0, %V1"
[(set_attr "type" "mav_farith")
(set_attr "cirrus" "compare")]
@@ -6638,7 +7114,7 @@
(if_then_else (unordered (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (UNORDERED, arm_compare_op0,
arm_compare_op1);"
)
@@ -6648,7 +7124,7 @@
(if_then_else (ordered (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (ORDERED, arm_compare_op0,
arm_compare_op1);"
)
@@ -6658,7 +7134,7 @@
(if_then_else (ungt (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (UNGT, arm_compare_op0, arm_compare_op1);"
)
@@ -6667,7 +7143,7 @@
(if_then_else (unlt (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (UNLT, arm_compare_op0, arm_compare_op1);"
)
@@ -6676,7 +7152,7 @@
(if_then_else (unge (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (UNGE, arm_compare_op0, arm_compare_op1);"
)
@@ -6685,7 +7161,7 @@
(if_then_else (unle (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (UNLE, arm_compare_op0, arm_compare_op1);"
)
@@ -6696,7 +7172,7 @@
(if_then_else (uneq (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (UNEQ, arm_compare_op0, arm_compare_op1);"
)
@@ -6705,7 +7181,7 @@
(if_then_else (ltgt (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (LTGT, arm_compare_op0, arm_compare_op1);"
)
@@ -6719,10 +7195,9 @@
(if_then_else (uneq (match_operand 1 "cc_register" "") (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"*
- if (arm_ccfsm_state != 0)
- abort ();
+ gcc_assert (!arm_ccfsm_state);
return \"bvs\\t%l0\;beq\\t%l0\";
"
@@ -6736,10 +7211,9 @@
(if_then_else (ltgt (match_operand 1 "cc_register" "") (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"*
- if (arm_ccfsm_state != 0)
- abort ();
+ gcc_assert (!arm_ccfsm_state);
return \"bmi\\t%l0\;bgt\\t%l0\";
"
@@ -6762,7 +7236,8 @@
}
return \"b%d1\\t%l0\";
"
- [(set_attr "conds" "use")]
+ [(set_attr "conds" "use")
+ (set_attr "type" "branch")]
)
; Special pattern to match reversed UNEQ.
@@ -6771,10 +7246,9 @@
(if_then_else (uneq (match_operand 1 "cc_register" "") (const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"*
- if (arm_ccfsm_state != 0)
- abort ();
+ gcc_assert (!arm_ccfsm_state);
return \"bmi\\t%l0\;bgt\\t%l0\";
"
@@ -6788,10 +7262,9 @@
(if_then_else (ltgt (match_operand 1 "cc_register" "") (const_int 0))
(pc)
(label_ref (match_operand 0 "" ""))))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"*
- if (arm_ccfsm_state != 0)
- abort ();
+ gcc_assert (!arm_ccfsm_state);
return \"bvs\\t%l0\;beq\\t%l0\";
"
@@ -6814,7 +7287,8 @@
}
return \"b%D1\\t%l0\";
"
- [(set_attr "conds" "use")]
+ [(set_attr "conds" "use")
+ (set_attr "type" "branch")]
)
@@ -6894,7 +7368,7 @@
(define_expand "sunordered"
[(set (match_operand:SI 0 "s_register_operand" "")
(unordered:SI (match_dup 1) (const_int 0)))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (UNORDERED, arm_compare_op0,
arm_compare_op1);"
)
@@ -6902,7 +7376,7 @@
(define_expand "sordered"
[(set (match_operand:SI 0 "s_register_operand" "")
(ordered:SI (match_dup 1) (const_int 0)))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (ORDERED, arm_compare_op0,
arm_compare_op1);"
)
@@ -6910,7 +7384,7 @@
(define_expand "sungt"
[(set (match_operand:SI 0 "s_register_operand" "")
(ungt:SI (match_dup 1) (const_int 0)))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (UNGT, arm_compare_op0,
arm_compare_op1);"
)
@@ -6918,7 +7392,7 @@
(define_expand "sunge"
[(set (match_operand:SI 0 "s_register_operand" "")
(unge:SI (match_dup 1) (const_int 0)))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (UNGE, arm_compare_op0,
arm_compare_op1);"
)
@@ -6926,7 +7400,7 @@
(define_expand "sunlt"
[(set (match_operand:SI 0 "s_register_operand" "")
(unlt:SI (match_dup 1) (const_int 0)))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (UNLT, arm_compare_op0,
arm_compare_op1);"
)
@@ -6934,7 +7408,7 @@
(define_expand "sunle"
[(set (match_operand:SI 0 "s_register_operand" "")
(unle:SI (match_dup 1) (const_int 0)))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"operands[1] = arm_gen_compare_reg (UNLE, arm_compare_op0,
arm_compare_op1);"
)
@@ -6945,15 +7419,15 @@
; (define_expand "suneq"
; [(set (match_operand:SI 0 "s_register_operand" "")
; (uneq:SI (match_dup 1) (const_int 0)))]
-; "TARGET_ARM && TARGET_HARD_FLOAT"
-; "abort ();"
+; "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
+; "gcc_unreachable ();"
; )
;
; (define_expand "sltgt"
; [(set (match_operand:SI 0 "s_register_operand" "")
; (ltgt:SI (match_dup 1) (const_int 0)))]
-; "TARGET_ARM && TARGET_HARD_FLOAT"
-; "abort ();"
+; "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
+; "gcc_unreachable ();"
; )
(define_insn "*mov_scc"
@@ -7004,7 +7478,7 @@
FAIL;
ccreg = arm_gen_compare_reg (code, arm_compare_op0, arm_compare_op1);
- operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx);
+ operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx);
}"
)
@@ -7023,13 +7497,13 @@
FAIL;
/* When compiling for SOFT_FLOAT, ensure both arms are in registers.
- Otherwise, ensure it is a valid FP add operand. */
- if ((!TARGET_HARD_FLOAT)
- || (!fpa_add_operand (operands[3], SFmode)))
+ Otherwise, ensure it is a valid FP add operand */
+ if ((!(TARGET_HARD_FLOAT && TARGET_FPA))
+ || (!arm_float_add_operand (operands[3], SFmode)))
operands[3] = force_reg (SFmode, operands[3]);
ccreg = arm_gen_compare_reg (code, arm_compare_op0, arm_compare_op1);
- operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx);
+ operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx);
}"
)
@@ -7037,8 +7511,8 @@
[(set (match_operand:DF 0 "s_register_operand" "")
(if_then_else:DF (match_operand 1 "arm_comparison_operator" "")
(match_operand:DF 2 "s_register_operand" "")
- (match_operand:DF 3 "fpa_add_operand" "")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (match_operand:DF 3 "arm_float_add_operand" "")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
"
{
enum rtx_code code = GET_CODE (operands[1]);
@@ -7048,7 +7522,7 @@
FAIL;
ccreg = arm_gen_compare_reg (code, arm_compare_op0, arm_compare_op1);
- operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx);
+ operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx);
}"
)
@@ -7161,18 +7635,30 @@
invoked it. */
callee = XEXP (operands[0], 0);
- if (GET_CODE (callee) != REG
- && arm_is_longcall_p (operands[0], INTVAL (operands[2]), 0))
+ if ((GET_CODE (callee) == SYMBOL_REF
+ && arm_is_longcall_p (operands[0], INTVAL (operands[2]), 0))
+ || (GET_CODE (callee) != SYMBOL_REF
+ && GET_CODE (callee) != REG))
XEXP (operands[0], 0) = force_reg (Pmode, callee);
}"
)
-(define_insn "*call_reg"
+(define_insn "*call_reg_armv5"
[(call (mem:SI (match_operand:SI 0 "s_register_operand" "r"))
(match_operand 1 "" ""))
(use (match_operand 2 "" ""))
(clobber (reg:SI LR_REGNUM))]
- "TARGET_ARM"
+ "TARGET_ARM && arm_arch5"
+ "blx%?\\t%0"
+ [(set_attr "type" "call")]
+)
+
+(define_insn "*call_reg_arm"
+ [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r"))
+ (match_operand 1 "" ""))
+ (use (match_operand 2 "" ""))
+ (clobber (reg:SI LR_REGNUM))]
+ "TARGET_ARM && !arm_arch5"
"*
return output_call (operands);
"
@@ -7182,7 +7668,7 @@
)
(define_insn "*call_mem"
- [(call (mem:SI (match_operand:SI 0 "memory_operand" "m"))
+ [(call (mem:SI (match_operand:SI 0 "call_memory_operand" "m"))
(match_operand 1 "" ""))
(use (match_operand 2 "" ""))
(clobber (reg:SI LR_REGNUM))]
@@ -7194,35 +7680,33 @@
(set_attr "type" "call")]
)
-(define_insn "*call_indirect"
+(define_insn "*call_reg_thumb_v5"
[(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
(match_operand 1 "" ""))
(use (match_operand 2 "" ""))
(clobber (reg:SI LR_REGNUM))]
- "TARGET_THUMB"
- "*
- {
- if (TARGET_CALLER_INTERWORKING)
- return \"bl\\t%__interwork_call_via_%0\";
- else
- return \"bl\\t%__call_via_%0\";
- }"
- [(set_attr "type" "call")]
+ "TARGET_THUMB && arm_arch5"
+ "blx\\t%0"
+ [(set_attr "length" "2")
+ (set_attr "type" "call")]
)
-(define_insn "*call_value_indirect"
- [(set (match_operand 0 "" "")
- (call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
- (match_operand 2 "" "")))
- (use (match_operand 3 "" ""))
+(define_insn "*call_reg_thumb"
+ [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
+ (match_operand 1 "" ""))
+ (use (match_operand 2 "" ""))
(clobber (reg:SI LR_REGNUM))]
- "TARGET_THUMB"
+ "TARGET_THUMB && !arm_arch5"
"*
{
- if (TARGET_CALLER_INTERWORKING)
- return \"bl\\t%__interwork_call_via_%1\";
+ if (!TARGET_CALLER_INTERWORKING)
+ return thumb_call_via_reg (operands[0]);
+ else if (operands[1] == const0_rtx)
+ return \"bl\\t%__interwork_call_via_%0\";
+ else if (frame_pointer_needed)
+ return \"bl\\t%__interwork_r7_call_via_%0\";
else
- return \"bl\\t%__call_via_%1\";
+ return \"bl\\t%__interwork_r11_call_via_%0\";
}"
[(set_attr "type" "call")]
)
@@ -7243,19 +7727,32 @@
operands[3] = const0_rtx;
/* See the comment in define_expand \"call\". */
- if (GET_CODE (callee) != REG
- && arm_is_longcall_p (operands[1], INTVAL (operands[3]), 0))
+ if ((GET_CODE (callee) == SYMBOL_REF
+ && arm_is_longcall_p (operands[1], INTVAL (operands[3]), 0))
+ || (GET_CODE (callee) != SYMBOL_REF
+ && GET_CODE (callee) != REG))
XEXP (operands[1], 0) = force_reg (Pmode, callee);
}"
)
-(define_insn "*call_value_reg"
+(define_insn "*call_value_reg_armv5"
[(set (match_operand 0 "" "")
(call (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
(match_operand 2 "" "")))
(use (match_operand 3 "" ""))
(clobber (reg:SI LR_REGNUM))]
- "TARGET_ARM"
+ "TARGET_ARM && arm_arch5"
+ "blx%?\\t%1"
+ [(set_attr "type" "call")]
+)
+
+(define_insn "*call_value_reg_arm"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
+ (match_operand 2 "" "")))
+ (use (match_operand 3 "" ""))
+ (clobber (reg:SI LR_REGNUM))]
+ "TARGET_ARM && !arm_arch5"
"*
return output_call (&operands[1]);
"
@@ -7265,7 +7762,7 @@
(define_insn "*call_value_mem"
[(set (match_operand 0 "" "")
- (call (mem:SI (match_operand:SI 1 "memory_operand" "m"))
+ (call (mem:SI (match_operand:SI 1 "call_memory_operand" "m"))
(match_operand 2 "" "")))
(use (match_operand 3 "" ""))
(clobber (reg:SI LR_REGNUM))]
@@ -7277,6 +7774,39 @@
(set_attr "type" "call")]
)
+(define_insn "*call_value_reg_thumb_v5"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
+ (match_operand 2 "" "")))
+ (use (match_operand 3 "" ""))
+ (clobber (reg:SI LR_REGNUM))]
+ "TARGET_THUMB && arm_arch5"
+ "blx\\t%1"
+ [(set_attr "length" "2")
+ (set_attr "type" "call")]
+)
+
+(define_insn "*call_value_reg_thumb"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
+ (match_operand 2 "" "")))
+ (use (match_operand 3 "" ""))
+ (clobber (reg:SI LR_REGNUM))]
+ "TARGET_THUMB && !arm_arch5"
+ "*
+ {
+ if (!TARGET_CALLER_INTERWORKING)
+ return thumb_call_via_reg (operands[1]);
+ else if (operands[2] == const0_rtx)
+ return \"bl\\t%__interwork_call_via_%1\";
+ else if (frame_pointer_needed)
+ return \"bl\\t%__interwork_r7_call_via_%1\";
+ else
+ return \"bl\\t%__interwork_r11_call_via_%1\";
+ }"
+ [(set_attr "type" "call")]
+)
+
;; Allow calls to SYMBOL_REFs specially as they are not valid general addresses
;; The 'a' causes the operand to be treated as an address, i.e. no '#' output.
@@ -7296,7 +7826,7 @@
)
(define_insn "*call_value_symbol"
- [(set (match_operand 0 "s_register_operand" "")
+ [(set (match_operand 0 "" "")
(call (mem:SI (match_operand:SI 1 "" ""))
(match_operand:SI 2 "" "")))
(use (match_operand 3 "" ""))
@@ -7325,7 +7855,7 @@
)
(define_insn "*call_value_insn"
- [(set (match_operand 0 "register_operand" "")
+ [(set (match_operand 0 "" "")
(call (mem:SI (match_operand 1 "" ""))
(match_operand 2 "" "")))
(use (match_operand 3 "" ""))
@@ -7353,7 +7883,7 @@
)
(define_expand "sibcall_value"
- [(parallel [(set (match_operand 0 "register_operand" "")
+ [(parallel [(set (match_operand 0 "" "")
(call (match_operand 1 "memory_operand" "")
(match_operand 2 "general_operand" "")))
(return)
@@ -7379,7 +7909,7 @@
)
(define_insn "*sibcall_value_insn"
- [(set (match_operand 0 "s_register_operand" "")
+ [(set (match_operand 0 "" "")
(call (mem:SI (match_operand:SI 1 "" "X"))
(match_operand 2 "" "")))
(return)
@@ -7404,7 +7934,7 @@
}
return output_return_instruction (const_true_rtx, TRUE, FALSE);
}"
- [(set_attr "type" "load")
+ [(set_attr "type" "load1")
(set_attr "length" "12")
(set_attr "predicable" "yes")]
)
@@ -7427,7 +7957,7 @@
}"
[(set_attr "conds" "use")
(set_attr "length" "12")
- (set_attr "type" "load")]
+ (set_attr "type" "load1")]
)
(define_insn "*cond_return_inverted"
@@ -7447,7 +7977,8 @@
return output_return_instruction (operands[0], TRUE, TRUE);
}"
[(set_attr "conds" "use")
- (set_attr "type" "load")]
+ (set_attr "length" "12")
+ (set_attr "type" "load1")]
)
;; Generate a sequence of instructions to determine if the processor is
@@ -7484,18 +8015,59 @@
(const_int 0))
(match_operand 1 "" "")
(match_operand 2 "" "")])]
- "TARGET_ARM"
+ "TARGET_EITHER"
"
{
int i;
+ rtx par = gen_rtx_PARALLEL (VOIDmode,
+ rtvec_alloc (XVECLEN (operands[2], 0)));
+ rtx addr = gen_reg_rtx (Pmode);
+ rtx mem;
+ int size = 0;
- emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx));
+ emit_move_insn (addr, XEXP (operands[1], 0));
+ mem = change_address (operands[1], BLKmode, addr);
for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
- rtx set = XVECEXP (operands[2], 0, i);
+ rtx src = SET_SRC (XVECEXP (operands[2], 0, i));
- emit_move_insn (SET_DEST (set), SET_SRC (set));
+ /* Default code only uses r0 as a return value, but we could
+ be using anything up to 4 registers. */
+ if (REGNO (src) == R0_REGNUM)
+ src = gen_rtx_REG (TImode, R0_REGNUM);
+
+ XVECEXP (par, 0, i) = gen_rtx_EXPR_LIST (VOIDmode, src,
+ GEN_INT (size));
+ size += GET_MODE_SIZE (GET_MODE (src));
+ }
+
+ emit_call_insn (GEN_CALL_VALUE (par, operands[0], const0_rtx, NULL,
+ const0_rtx));
+
+ size = 0;
+
+ for (i = 0; i < XVECLEN (par, 0); i++)
+ {
+ HOST_WIDE_INT offset = 0;
+ rtx reg = XEXP (XVECEXP (par, 0, i), 0);
+
+ if (size != 0)
+ emit_move_insn (addr, plus_constant (addr, size));
+
+ mem = change_address (mem, GET_MODE (reg), NULL);
+ if (REGNO (reg) == R0_REGNUM)
+ {
+ /* On thumb we have to use a write-back instruction. */
+ emit_insn (arm_gen_store_multiple (R0_REGNUM, 4, addr, TRUE,
+ TARGET_THUMB ? TRUE : FALSE, mem, &offset));
+ size = TARGET_ARM ? 16 : 0;
+ }
+ else
+ {
+ emit_move_insn (mem, reg);
+ size = GET_MODE_SIZE (GET_MODE (reg));
+ }
}
/* The optimizer does not know that the call sets the function value
@@ -7508,6 +8080,55 @@
}"
)
+(define_expand "untyped_return"
+ [(match_operand:BLK 0 "memory_operand" "")
+ (match_operand 1 "" "")]
+ "TARGET_EITHER"
+ "
+ {
+ int i;
+ rtx addr = gen_reg_rtx (Pmode);
+ rtx mem;
+ int size = 0;
+
+ emit_move_insn (addr, XEXP (operands[0], 0));
+ mem = change_address (operands[0], BLKmode, addr);
+
+ for (i = 0; i < XVECLEN (operands[1], 0); i++)
+ {
+ HOST_WIDE_INT offset = 0;
+ rtx reg = SET_DEST (XVECEXP (operands[1], 0, i));
+
+ if (size != 0)
+ emit_move_insn (addr, plus_constant (addr, size));
+
+ mem = change_address (mem, GET_MODE (reg), NULL);
+ if (REGNO (reg) == R0_REGNUM)
+ {
+ /* On thumb we have to use a write-back instruction. */
+ emit_insn (arm_gen_load_multiple (R0_REGNUM, 4, addr, TRUE,
+ TARGET_THUMB ? TRUE : FALSE, mem, &offset));
+ size = TARGET_ARM ? 16 : 0;
+ }
+ else
+ {
+ emit_move_insn (reg, mem);
+ size = GET_MODE_SIZE (GET_MODE (reg));
+ }
+ }
+
+ /* Emit USE insns before the return. */
+ for (i = 0; i < XVECLEN (operands[1], 0); i++)
+ emit_insn (gen_rtx_USE (VOIDmode,
+ SET_DEST (XVECEXP (operands[1], 0, i))));
+
+ /* Construct the return. */
+ expand_naked_return ();
+
+ DONE;
+ }"
+)
+
;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
;; all of memory. This blocks insns from being moved across this point.
@@ -7576,6 +8197,7 @@
""
)
+;; NB Never uses BX.
(define_insn "*arm_indirect_jump"
[(set (pc)
(match_operand:SI 0 "s_register_operand" "r"))]
@@ -7584,19 +8206,18 @@
[(set_attr "predicable" "yes")]
)
-;; Although not supported by the define_expand above,
-;; cse/combine may generate this form.
(define_insn "*load_indirect_jump"
[(set (pc)
(match_operand:SI 0 "memory_operand" "m"))]
"TARGET_ARM"
"ldr%?\\t%|pc, %0\\t%@ indirect memory jump"
- [(set_attr "type" "load")
+ [(set_attr "type" "load1")
(set_attr "pool_range" "4096")
(set_attr "neg_pool_range" "4084")
(set_attr "predicable" "yes")]
)
+;; NB Never uses BX.
(define_insn "*thumb_indirect_jump"
[(set (pc)
(match_operand:SI 0 "register_operand" "l*r"))]
@@ -7637,7 +8258,9 @@
"%i1%?\\t%0, %2, %4%S3"
[(set_attr "predicable" "yes")
(set_attr "shift" "4")
- ]
+ (set (attr "type") (if_then_else (match_operand 5 "const_int_operand" "")
+ (const_string "alu_shift")
+ (const_string "alu_shift_reg")))]
)
(define_split
@@ -7673,7 +8296,9 @@
"%i1%?s\\t%0, %2, %4%S3"
[(set_attr "conds" "set")
(set_attr "shift" "4")
- ]
+ (set (attr "type") (if_then_else (match_operand 5 "const_int_operand" "")
+ (const_string "alu_shift")
+ (const_string "alu_shift_reg")))]
)
(define_insn "*arith_shiftsi_compare0_scratch"
@@ -7689,7 +8314,9 @@
"%i1%?s\\t%0, %2, %4%S3"
[(set_attr "conds" "set")
(set_attr "shift" "4")
- ]
+ (set (attr "type") (if_then_else (match_operand 5 "const_int_operand" "")
+ (const_string "alu_shift")
+ (const_string "alu_shift_reg")))]
)
(define_insn "*sub_shiftsi"
@@ -7702,7 +8329,9 @@
"sub%?\\t%0, %1, %3%S2"
[(set_attr "predicable" "yes")
(set_attr "shift" "3")
- ]
+ (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "")
+ (const_string "alu_shift")
+ (const_string "alu_shift_reg")))]
)
(define_insn "*sub_shiftsi_compare0"
@@ -7719,8 +8348,10 @@
"TARGET_ARM"
"sub%?s\\t%0, %1, %3%S2"
[(set_attr "conds" "set")
- (set_attr "shift" "3")
- ]
+ (set_attr "shift" "3")
+ (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "")
+ (const_string "alu_shift")
+ (const_string "alu_shift_reg")))]
)
(define_insn "*sub_shiftsi_compare0_scratch"
@@ -7735,8 +8366,10 @@
"TARGET_ARM"
"sub%?s\\t%0, %1, %3%S2"
[(set_attr "conds" "set")
- (set_attr "shift" "3")
- ]
+ (set_attr "shift" "3")
+ (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "")
+ (const_string "alu_shift")
+ (const_string "alu_shift_reg")))]
)
@@ -8609,7 +9242,10 @@
mvn%D5\\t%0, #%B1\;mov%d5\\t%0, %2%S4"
[(set_attr "conds" "use")
(set_attr "shift" "2")
- (set_attr "length" "4,8,8")]
+ (set_attr "length" "4,8,8")
+ (set (attr "type") (if_then_else (match_operand 3 "const_int_operand" "")
+ (const_string "alu_shift")
+ (const_string "alu_shift_reg")))]
)
(define_insn "*ifcompare_move_shift"
@@ -8645,7 +9281,10 @@
mvn%d5\\t%0, #%B1\;mov%D5\\t%0, %2%S4"
[(set_attr "conds" "use")
(set_attr "shift" "2")
- (set_attr "length" "4,8,8")]
+ (set_attr "length" "4,8,8")
+ (set (attr "type") (if_then_else (match_operand 3 "const_int_operand" "")
+ (const_string "alu_shift")
+ (const_string "alu_shift_reg")))]
)
(define_insn "*ifcompare_shift_shift"
@@ -8682,7 +9321,12 @@
"mov%d5\\t%0, %1%S6\;mov%D5\\t%0, %3%S7"
[(set_attr "conds" "use")
(set_attr "shift" "1")
- (set_attr "length" "8")]
+ (set_attr "length" "8")
+ (set (attr "type") (if_then_else
+ (and (match_operand 2 "const_int_operand" "")
+ (match_operand 4 "const_int_operand" ""))
+ (const_string "alu_shift")
+ (const_string "alu_shift_reg")))]
)
(define_insn "*ifcompare_not_arith"
@@ -8822,7 +9466,8 @@
{
rtx ldm[3];
rtx arith[4];
- int val1 = 0, val2 = 0;
+ rtx base_reg;
+ HOST_WIDE_INT val1 = 0, val2 = 0;
if (REGNO (operands[0]) > REGNO (operands[4]))
{
@@ -8834,12 +9479,21 @@
ldm[1] = operands[0];
ldm[2] = operands[4];
}
- if (GET_CODE (XEXP (operands[2], 0)) != REG)
- val1 = INTVAL (XEXP (XEXP (operands[2], 0), 1));
- if (GET_CODE (XEXP (operands[3], 0)) != REG)
+
+ base_reg = XEXP (operands[2], 0);
+
+ if (!REG_P (base_reg))
+ {
+ val1 = INTVAL (XEXP (base_reg, 1));
+ base_reg = XEXP (base_reg, 0);
+ }
+
+ if (!REG_P (XEXP (operands[3], 0)))
val2 = INTVAL (XEXP (XEXP (operands[3], 0), 1));
+
arith[0] = operands[0];
arith[3] = operands[1];
+
if (val1 < val2)
{
arith[1] = ldm[1];
@@ -8850,21 +9504,41 @@
arith[1] = ldm[2];
arith[2] = ldm[1];
}
- if (val1 && val2)
+
+ ldm[0] = base_reg;
+ if (val1 !=0 && val2 != 0)
{
rtx ops[3];
- ldm[0] = ops[0] = operands[4];
- ops[1] = XEXP (XEXP (operands[2], 0), 0);
- ops[2] = XEXP (XEXP (operands[2], 0), 1);
- output_add_immediate (ops);
- if (val1 < val2)
- output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm);
+
+ if (val1 == 4 || val2 == 4)
+ /* Other val must be 8, since we know they are adjacent and neither
+ is zero. */
+ output_asm_insn (\"ldm%?ib\\t%0, {%1, %2}\", ldm);
+ else if (const_ok_for_arm (val1) || const_ok_for_arm (-val1))
+ {
+ ldm[0] = ops[0] = operands[4];
+ ops[1] = base_reg;
+ ops[2] = GEN_INT (val1);
+ output_add_immediate (ops);
+ if (val1 < val2)
+ output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm);
+ else
+ output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm);
+ }
else
- output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm);
+ {
+ /* Offset is out of range for a single add, so use two ldr. */
+ ops[0] = ldm[1];
+ ops[1] = base_reg;
+ ops[2] = GEN_INT (val1);
+ output_asm_insn (\"ldr%?\\t%0, [%1, %2]\", ops);
+ ops[0] = ldm[2];
+ ops[2] = GEN_INT (val2);
+ output_asm_insn (\"ldr%?\\t%0, [%1, %2]\", ops);
+ }
}
- else if (val1)
+ else if (val1 != 0)
{
- ldm[0] = XEXP (operands[3], 0);
if (val1 < val2)
output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm);
else
@@ -8872,7 +9546,6 @@
}
else
{
- ldm[0] = XEXP (operands[2], 0);
if (val1 < val2)
output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm);
else
@@ -8883,516 +9556,17 @@
}"
[(set_attr "length" "12")
(set_attr "predicable" "yes")
- (set_attr "type" "load")]
-)
-
-;; the arm can support extended pre-inc instructions
-
-;; In all these cases, we use operands 0 and 1 for the register being
-;; incremented because those are the operands that local-alloc will
-;; tie and these are the pair most likely to be tieable (and the ones
-;; that will benefit the most).
-
-;; We reject the frame pointer if it occurs anywhere in these patterns since
-;; elimination will cause too many headaches.
-
-(define_insn "*strqi_preinc"
- [(set (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
- (match_operand:SI 2 "index_operand" "rJ")))
- (match_operand:QI 3 "s_register_operand" "r"))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (plus:SI (match_dup 1) (match_dup 2)))]
- "TARGET_ARM
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && (GET_CODE (operands[2]) != REG
- || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
- "str%?b\\t%3, [%0, %2]!"
- [(set_attr "type" "store1")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*strqi_predec"
- [(set (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
- (match_operand:SI 2 "s_register_operand" "r")))
- (match_operand:QI 3 "s_register_operand" "r"))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (minus:SI (match_dup 1) (match_dup 2)))]
- "TARGET_ARM
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && (GET_CODE (operands[2]) != REG
- || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
- "str%?b\\t%3, [%0, -%2]!"
- [(set_attr "type" "store1")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadqi_preinc"
- [(set (match_operand:QI 3 "s_register_operand" "=r")
- (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
- (match_operand:SI 2 "index_operand" "rJ"))))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (plus:SI (match_dup 1) (match_dup 2)))]
- "TARGET_ARM
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && (GET_CODE (operands[2]) != REG
- || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
- "ldr%?b\\t%3, [%0, %2]!"
- [(set_attr "type" "load")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadqi_predec"
- [(set (match_operand:QI 3 "s_register_operand" "=r")
- (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
- (match_operand:SI 2 "s_register_operand" "r"))))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (minus:SI (match_dup 1) (match_dup 2)))]
- "TARGET_ARM
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && (GET_CODE (operands[2]) != REG
- || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
- "ldr%?b\\t%3, [%0, -%2]!"
- [(set_attr "type" "load")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadqisi_preinc"
- [(set (match_operand:SI 3 "s_register_operand" "=r")
- (zero_extend:SI
- (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
- (match_operand:SI 2 "index_operand" "rJ")))))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (plus:SI (match_dup 1) (match_dup 2)))]
- "TARGET_ARM
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && (GET_CODE (operands[2]) != REG
- || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
- "ldr%?b\\t%3, [%0, %2]!\\t%@ z_extendqisi"
- [(set_attr "type" "load")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadqisi_predec"
- [(set (match_operand:SI 3 "s_register_operand" "=r")
- (zero_extend:SI
- (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
- (match_operand:SI 2 "s_register_operand" "r")))))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (minus:SI (match_dup 1) (match_dup 2)))]
- "TARGET_ARM
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && (GET_CODE (operands[2]) != REG
- || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
- "ldr%?b\\t%3, [%0, -%2]!\\t%@ z_extendqisi"
- [(set_attr "type" "load")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*strsi_preinc"
- [(set (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
- (match_operand:SI 2 "index_operand" "rJ")))
- (match_operand:SI 3 "s_register_operand" "r"))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (plus:SI (match_dup 1) (match_dup 2)))]
- "TARGET_ARM
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && (GET_CODE (operands[2]) != REG
- || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
- "str%?\\t%3, [%0, %2]!"
- [(set_attr "type" "store1")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*strsi_predec"
- [(set (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
- (match_operand:SI 2 "s_register_operand" "r")))
- (match_operand:SI 3 "s_register_operand" "r"))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (minus:SI (match_dup 1) (match_dup 2)))]
- "TARGET_ARM
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && (GET_CODE (operands[2]) != REG
- || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
- "str%?\\t%3, [%0, -%2]!"
- [(set_attr "type" "store1")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadsi_preinc"
- [(set (match_operand:SI 3 "s_register_operand" "=r")
- (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
- (match_operand:SI 2 "index_operand" "rJ"))))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (plus:SI (match_dup 1) (match_dup 2)))]
- "TARGET_ARM
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && (GET_CODE (operands[2]) != REG
- || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
- "ldr%?\\t%3, [%0, %2]!"
- [(set_attr "type" "load")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadsi_predec"
- [(set (match_operand:SI 3 "s_register_operand" "=r")
- (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
- (match_operand:SI 2 "s_register_operand" "r"))))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (minus:SI (match_dup 1) (match_dup 2)))]
- "TARGET_ARM
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && (GET_CODE (operands[2]) != REG
- || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
- "ldr%?\\t%3, [%0, -%2]!"
- [(set_attr "type" "load")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadhi_preinc"
- [(set (match_operand:HI 3 "s_register_operand" "=r")
- (mem:HI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
- (match_operand:SI 2 "index_operand" "rJ"))))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (plus:SI (match_dup 1) (match_dup 2)))]
- "TARGET_ARM
- && !BYTES_BIG_ENDIAN
- && !TARGET_MMU_TRAPS
- && !arm_arch4
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && (GET_CODE (operands[2]) != REG
- || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
- "ldr%?\\t%3, [%0, %2]!\\t%@ loadhi"
- [(set_attr "type" "load")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadhi_predec"
- [(set (match_operand:HI 3 "s_register_operand" "=r")
- (mem:HI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
- (match_operand:SI 2 "s_register_operand" "r"))))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (minus:SI (match_dup 1) (match_dup 2)))]
- "TARGET_ARM
- && !BYTES_BIG_ENDIAN
- && !TARGET_MMU_TRAPS
- && !arm_arch4
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && (GET_CODE (operands[2]) != REG
- || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
- "ldr%?\\t%3, [%0, -%2]!\\t%@ loadhi"
- [(set_attr "type" "load")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*strqi_shiftpreinc"
- [(set (mem:QI (plus:SI (match_operator:SI 2 "shift_operator"
- [(match_operand:SI 3 "s_register_operand" "r")
- (match_operand:SI 4 "const_shift_operand" "n")])
- (match_operand:SI 1 "s_register_operand" "0")))
- (match_operand:QI 5 "s_register_operand" "r"))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)])
- (match_dup 1)))]
- "TARGET_ARM
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
- "str%?b\\t%5, [%0, %3%S2]!"
- [(set_attr "type" "store1")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*strqi_shiftpredec"
- [(set (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
- (match_operator:SI 2 "shift_operator"
- [(match_operand:SI 3 "s_register_operand" "r")
- (match_operand:SI 4 "const_shift_operand" "n")])))
- (match_operand:QI 5 "s_register_operand" "r"))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
- (match_dup 4)])))]
- "TARGET_ARM
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
- "str%?b\\t%5, [%0, -%3%S2]!"
- [(set_attr "type" "store1")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadqi_shiftpreinc"
- [(set (match_operand:QI 5 "s_register_operand" "=r")
- (mem:QI (plus:SI (match_operator:SI 2 "shift_operator"
- [(match_operand:SI 3 "s_register_operand" "r")
- (match_operand:SI 4 "const_shift_operand" "n")])
- (match_operand:SI 1 "s_register_operand" "0"))))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)])
- (match_dup 1)))]
- "TARGET_ARM
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
- "ldr%?b\\t%5, [%0, %3%S2]!"
- [(set_attr "type" "load")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadqi_shiftpredec"
- [(set (match_operand:QI 5 "s_register_operand" "=r")
- (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
- (match_operator:SI 2 "shift_operator"
- [(match_operand:SI 3 "s_register_operand" "r")
- (match_operand:SI 4 "const_shift_operand" "n")]))))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
- (match_dup 4)])))]
- "TARGET_ARM
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
- "ldr%?b\\t%5, [%0, -%3%S2]!"
- [(set_attr "type" "load")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*strsi_shiftpreinc"
- [(set (mem:SI (plus:SI (match_operator:SI 2 "shift_operator"
- [(match_operand:SI 3 "s_register_operand" "r")
- (match_operand:SI 4 "const_shift_operand" "n")])
- (match_operand:SI 1 "s_register_operand" "0")))
- (match_operand:SI 5 "s_register_operand" "r"))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)])
- (match_dup 1)))]
- "TARGET_ARM
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
- "str%?\\t%5, [%0, %3%S2]!"
- [(set_attr "type" "store1")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*strsi_shiftpredec"
- [(set (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
- (match_operator:SI 2 "shift_operator"
- [(match_operand:SI 3 "s_register_operand" "r")
- (match_operand:SI 4 "const_shift_operand" "n")])))
- (match_operand:SI 5 "s_register_operand" "r"))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
- (match_dup 4)])))]
- "TARGET_ARM
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
- "str%?\\t%5, [%0, -%3%S2]!"
- [(set_attr "type" "store1")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadsi_shiftpreinc"
- [(set (match_operand:SI 5 "s_register_operand" "=r")
- (mem:SI (plus:SI (match_operator:SI 2 "shift_operator"
- [(match_operand:SI 3 "s_register_operand" "r")
- (match_operand:SI 4 "const_shift_operand" "n")])
- (match_operand:SI 1 "s_register_operand" "0"))))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)])
- (match_dup 1)))]
- "TARGET_ARM
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
- "ldr%?\\t%5, [%0, %3%S2]!"
- [(set_attr "type" "load")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadsi_shiftpredec"
- [(set (match_operand:SI 5 "s_register_operand" "=r")
- (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
- (match_operator:SI 2 "shift_operator"
- [(match_operand:SI 3 "s_register_operand" "r")
- (match_operand:SI 4 "const_shift_operand" "n")]))))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
- (match_dup 4)])))]
- "TARGET_ARM
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
- "ldr%?\\t%5, [%0, -%3%S2]!"
- [(set_attr "type" "load")
- (set_attr "predicable" "yes")])
-
-(define_insn "*loadhi_shiftpreinc"
- [(set (match_operand:HI 5 "s_register_operand" "=r")
- (mem:HI (plus:SI (match_operator:SI 2 "shift_operator"
- [(match_operand:SI 3 "s_register_operand" "r")
- (match_operand:SI 4 "const_shift_operand" "n")])
- (match_operand:SI 1 "s_register_operand" "0"))))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)])
- (match_dup 1)))]
- "TARGET_ARM
- && !BYTES_BIG_ENDIAN
- && !TARGET_MMU_TRAPS
- && !arm_arch4
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
- "ldr%?\\t%5, [%0, %3%S2]!\\t%@ loadhi"
- [(set_attr "type" "load")
- (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadhi_shiftpredec"
- [(set (match_operand:HI 5 "s_register_operand" "=r")
- (mem:HI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
- (match_operator:SI 2 "shift_operator"
- [(match_operand:SI 3 "s_register_operand" "r")
- (match_operand:SI 4 "const_shift_operand" "n")]))))
- (set (match_operand:SI 0 "s_register_operand" "=r")
- (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
- (match_dup 4)])))]
- "TARGET_ARM
- && !BYTES_BIG_ENDIAN
- && !TARGET_MMU_TRAPS
- && !arm_arch4
- && REGNO (operands[0]) != FRAME_POINTER_REGNUM
- && REGNO (operands[1]) != FRAME_POINTER_REGNUM
- && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
- "ldr%?\\t%5, [%0, -%3%S2]!\\t%@ loadhi"
- [(set_attr "type" "load")
- (set_attr "predicable" "yes")]
-)
-
-; It can also support extended post-inc expressions, but combine doesn't
-; try these....
-; It doesn't seem worth adding peepholes for anything but the most common
-; cases since, unlike combine, the increment must immediately follow the load
-; for this pattern to match.
-; We must watch to see that the source/destination register isn't also the
-; same as the base address register, and that if the index is a register,
-; that it is not the same as the base address register. In such cases the
-; instruction that we would generate would have UNPREDICTABLE behavior so
-; we cannot use it.
-
-(define_peephole
- [(set (mem:QI (match_operand:SI 0 "s_register_operand" "+r"))
- (match_operand:QI 2 "s_register_operand" "r"))
- (set (match_dup 0)
- (plus:SI (match_dup 0) (match_operand:SI 1 "index_operand" "rJ")))]
- "TARGET_ARM
- && (REGNO (operands[2]) != REGNO (operands[0]))
- && (GET_CODE (operands[1]) != REG
- || (REGNO (operands[1]) != REGNO (operands[0])))"
- "str%?b\\t%2, [%0], %1"
-)
-
-(define_peephole
- [(set (match_operand:QI 0 "s_register_operand" "=r")
- (mem:QI (match_operand:SI 1 "s_register_operand" "+r")))
- (set (match_dup 1)
- (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))]
- "TARGET_ARM
- && REGNO (operands[0]) != REGNO(operands[1])
- && (GET_CODE (operands[2]) != REG
- || REGNO(operands[0]) != REGNO (operands[2]))"
- "ldr%?b\\t%0, [%1], %2"
-)
-
-(define_peephole
- [(set (mem:SI (match_operand:SI 0 "s_register_operand" "+r"))
- (match_operand:SI 2 "s_register_operand" "r"))
- (set (match_dup 0)
- (plus:SI (match_dup 0) (match_operand:SI 1 "index_operand" "rJ")))]
- "TARGET_ARM
- && (REGNO (operands[2]) != REGNO (operands[0]))
- && (GET_CODE (operands[1]) != REG
- || (REGNO (operands[1]) != REGNO (operands[0])))"
- "str%?\\t%2, [%0], %1"
-)
-
-(define_peephole
- [(set (match_operand:HI 0 "s_register_operand" "=r")
- (mem:HI (match_operand:SI 1 "s_register_operand" "+r")))
- (set (match_dup 1)
- (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))]
- "TARGET_ARM
- && !BYTES_BIG_ENDIAN
- && !TARGET_MMU_TRAPS
- && !arm_arch4
- && REGNO (operands[0]) != REGNO(operands[1])
- && (GET_CODE (operands[2]) != REG
- || REGNO(operands[0]) != REGNO (operands[2]))"
- "ldr%?\\t%0, [%1], %2\\t%@ loadhi"
-)
-
-(define_peephole
- [(set (match_operand:SI 0 "s_register_operand" "=r")
- (mem:SI (match_operand:SI 1 "s_register_operand" "+r")))
- (set (match_dup 1)
- (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))]
- "TARGET_ARM
- && REGNO (operands[0]) != REGNO(operands[1])
- && (GET_CODE (operands[2]) != REG
- || REGNO(operands[0]) != REGNO (operands[2]))"
- "ldr%?\\t%0, [%1], %2"
-)
-
-(define_peephole
- [(set (mem:QI (plus:SI (match_operand:SI 0 "s_register_operand" "+r")
- (match_operand:SI 1 "index_operand" "rJ")))
- (match_operand:QI 2 "s_register_operand" "r"))
- (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))]
- "TARGET_ARM
- && (REGNO (operands[2]) != REGNO (operands[0]))
- && (GET_CODE (operands[1]) != REG
- || (REGNO (operands[1]) != REGNO (operands[0])))"
- "str%?b\\t%2, [%0, %1]!"
-)
-
-(define_peephole
- [(set (mem:QI (plus:SI (match_operator:SI 4 "shift_operator"
- [(match_operand:SI 0 "s_register_operand" "r")
- (match_operand:SI 1 "const_int_operand" "n")])
- (match_operand:SI 2 "s_register_operand" "+r")))
- (match_operand:QI 3 "s_register_operand" "r"))
- (set (match_dup 2) (plus:SI (match_op_dup 4 [(match_dup 0) (match_dup 1)])
- (match_dup 2)))]
- "TARGET_ARM
- && (REGNO (operands[3]) != REGNO (operands[2]))
- && (REGNO (operands[0]) != REGNO (operands[2]))"
- "str%?b\\t%3, [%2, %0%S4]!"
+ (set_attr "type" "load1")]
)
; This pattern is never tried by combine, so do it as a peephole
(define_peephole2
- [(set (match_operand:SI 0 "s_register_operand" "")
- (match_operand:SI 1 "s_register_operand" ""))
+ [(set (match_operand:SI 0 "arm_general_register_operand" "")
+ (match_operand:SI 1 "arm_general_register_operand" ""))
(set (reg:CC CC_REGNUM)
(compare:CC (match_dup 1) (const_int 0)))]
- "TARGET_ARM
- && (!TARGET_CIRRUS
- || (!cirrus_fp_register (operands[0], SImode)
- && !cirrus_fp_register (operands[1], SImode)))
- "
+ "TARGET_ARM"
[(parallel [(set (reg:CC CC_REGNUM) (compare:CC (match_dup 1) (const_int 0)))
(set (match_dup 0) (match_dup 1))])]
""
@@ -9527,9 +9701,11 @@
)
(define_expand "epilogue"
- [(unspec_volatile [(return)] VUNSPEC_EPILOGUE)]
+ [(clobber (const_int 0))]
"TARGET_EITHER"
"
+ if (current_function_calls_eh_return)
+ emit_insn (gen_prologue_use (gen_rtx_REG (Pmode, 2)));
if (TARGET_THUMB)
thumb_expand_epilogue ();
else if (USE_RETURN_INSN (FALSE))
@@ -9715,7 +9891,7 @@
enum rtx_code rc = GET_CODE (operands[1]);
operands[6] = gen_rtx_REG (mode, CC_REGNUM);
- operands[7] = gen_rtx (COMPARE, mode, operands[2], operands[3]);
+ operands[7] = gen_rtx_COMPARE (mode, operands[2], operands[3]);
if (mode == CCFPmode || mode == CCFPEmode)
rc = reverse_condition_maybe_unordered (rc);
else
@@ -9833,7 +10009,7 @@
[(set (match_operand:BLK 0 "memory_operand" "=m")
(unspec:BLK [(match_operand:XF 1 "f_register_operand" "f")]
UNSPEC_PUSH_MULT))])]
- "TARGET_ARM"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"*
{
char pattern[100];
@@ -9858,7 +10034,7 @@
(define_insn "align_8"
[(unspec_volatile [(const_int 0)] VUNSPEC_ALIGN8)]
- "TARGET_REALLY_IWMMXT"
+ "TARGET_EITHER"
"*
assemble_align (64);
return \"\";
@@ -9965,6 +10141,7 @@
"
)
+;; NB never uses BX.
(define_insn "*thumb_tablejump"
[(set (pc) (match_operand:SI 0 "register_operand" "l*r"))
(use (label_ref (match_operand 1 "" "")))]
@@ -10047,9 +10224,81 @@
"%@ %0 needed for prologue"
)
+
+;; Patterns for exception handling
+
+(define_expand "eh_return"
+ [(use (match_operand 0 "general_operand" ""))]
+ "TARGET_EITHER"
+ "
+ {
+ if (TARGET_ARM)
+ emit_insn (gen_arm_eh_return (operands[0]));
+ else
+ emit_insn (gen_thumb_eh_return (operands[0]));
+ DONE;
+ }"
+)
+
+;; We can't expand this before we know where the link register is stored.
+(define_insn_and_split "arm_eh_return"
+ [(unspec_volatile [(match_operand:SI 0 "s_register_operand" "r")]
+ VUNSPEC_EH_RETURN)
+ (clobber (match_scratch:SI 1 "=&r"))]
+ "TARGET_ARM"
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
+ "
+ {
+ arm_set_return_address (operands[0], operands[1]);
+ DONE;
+ }"
+)
+
+(define_insn_and_split "thumb_eh_return"
+ [(unspec_volatile [(match_operand:SI 0 "s_register_operand" "l")]
+ VUNSPEC_EH_RETURN)
+ (clobber (match_scratch:SI 1 "=&l"))]
+ "TARGET_THUMB"
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
+ "
+ {
+ thumb_set_return_address (operands[0], operands[1]);
+ DONE;
+ }"
+)
+
+
+;; TLS support
+
+(define_insn "load_tp_hard"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(const_int 0)] UNSPEC_TLS))]
+ "TARGET_HARD_TP"
+ "mrc%?\\tp15, 0, %0, c13, c0, 3\\t@ load_tp_hard"
+ [(set_attr "predicable" "yes")]
+)
+
+;; Doesn't clobber R1-R3. Must use r0 for the first operand.
+(define_insn "load_tp_soft"
+ [(set (reg:SI 0) (unspec:SI [(const_int 0)] UNSPEC_TLS))
+ (clobber (reg:SI LR_REGNUM))
+ (clobber (reg:SI IP_REGNUM))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_SOFT_TP"
+ "bl\\t__aeabi_read_tp\\t@ load_tp_soft"
+ [(set_attr "conds" "clob")]
+)
+
;; Load the FPA co-processor patterns
(include "fpa.md")
;; Load the Maverick co-processor patterns
(include "cirrus.md")
;; Load the Intel Wireless Multimedia Extension patterns
(include "iwmmxt.md")
+;; Load the VFP co-processor patterns
+(include "vfp.md")
+
diff --git a/contrib/gcc/config/arm/arm.opt b/contrib/gcc/config/arm/arm.opt
new file mode 100644
index 0000000..8f85ffb
--- /dev/null
+++ b/contrib/gcc/config/arm/arm.opt
@@ -0,0 +1,155 @@
+; Options for the ARM port of the compiler.
+
+; Copyright (C) 2005 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.
+;
+; 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.
+
+mabi=
+Target RejectNegative Joined Var(target_abi_name)
+Specify an ABI
+
+mabort-on-noreturn
+Target Report Mask(ABORT_NORETURN)
+Generate a call to abort if a noreturn function returns
+
+mapcs
+Target RejectNegative Mask(APCS_FRAME) MaskExists Undocumented
+
+mapcs-float
+Target Report Mask(APCS_FLOAT)
+Pass FP arguments in FP registers
+
+mapcs-frame
+Target Report Mask(APCS_FRAME)
+Generate APCS conformant stack frames
+
+mapcs-reentrant
+Target Report Mask(APCS_REENT)
+Generate re-entrant, PIC code
+
+mapcs-stack-check
+Target Report Mask(APCS_STACK) Undocumented
+
+march=
+Target RejectNegative Joined
+Specify the name of the target architecture
+
+marm
+Target RejectNegative InverseMask(THUMB) Undocumented
+
+mbig-endian
+Target Report RejectNegative Mask(BIG_END)
+Assume target CPU is configured as big endian
+
+mcallee-super-interworking
+Target Report Mask(CALLEE_INTERWORKING)
+Thumb: Assume non-static functions may be called from ARM code
+
+mcaller-super-interworking
+Target Report Mask(CALLER_INTERWORKING)
+Thumb: Assume function pointers may go to non-Thumb aware code
+
+mcirrus-fix-invalid-insns
+Target Report Mask(CIRRUS_FIX_INVALID_INSNS)
+Cirrus: Place NOPs to avoid invalid instruction combinations
+
+mcpu=
+Target RejectNegative Joined
+Specify the name of the target CPU
+
+mfloat-abi=
+Target RejectNegative Joined Var(target_float_abi_name)
+Specify if floating point hardware should be used
+
+mfp=
+Target RejectNegative Joined Undocumented Var(target_fpe_name)
+
+;; Now ignored.
+mfpe
+Target RejectNegative Mask(FPE) Undocumented
+
+mfpe=
+Target RejectNegative Joined Undocumented Var(target_fpe_name)
+
+mfpu=
+Target RejectNegative Joined Var(target_fpu_name)
+Specify the name of the target floating point hardware/format
+
+mhard-float
+Target RejectNegative
+Alias for -mfloat-abi=hard
+
+mlittle-endian
+Target Report RejectNegative InverseMask(BIG_END)
+Assume target CPU is configured as little endian
+
+mlong-calls
+Target Report Mask(LONG_CALLS)
+Generate call insns as indirect calls, if necessary
+
+mpic-register=
+Target RejectNegative Joined Var(arm_pic_register_string)
+Specify the register to be used for PIC addressing
+
+mpoke-function-name
+Target Report Mask(POKE_FUNCTION_NAME)
+Store function names in object code
+
+msched-prolog
+Target Report Mask(SCHED_PROLOG)
+Permit scheduling of a function's prologue sequence
+
+msingle-pic-base
+Target Report Mask(SINGLE_PIC_BASE)
+Do not load the PIC register in function prologues
+
+msoft-float
+Target RejectNegative
+Alias for -mfloat-abi=soft
+
+mstructure-size-boundary=
+Target RejectNegative Joined Var(structure_size_string)
+Specify the minimum bit alignment of structures
+
+mthumb
+Target Report Mask(THUMB)
+Compile for the Thumb not the ARM
+
+mthumb-interwork
+Target Report Mask(INTERWORK)
+Support calls between Thumb and ARM instruction sets
+
+mtp=
+Target RejectNegative Joined Var(target_thread_switch)
+Specify how to access the thread pointer
+
+mtpcs-frame
+Target Report Mask(TPCS_FRAME)
+Thumb: Generate (non-leaf) stack frames even if not needed
+
+mtpcs-leaf-frame
+Target Report Mask(TPCS_LEAF_FRAME)
+Thumb: Generate (leaf) stack frames even if not needed
+
+mtune=
+Target RejectNegative Joined
+Tune code for the given processor
+
+mwords-little-endian
+Target Report RejectNegative Mask(LITTLE_WORDS)
+Assume big endian bytes, little endian words
diff --git a/contrib/gcc/config/arm/arm1020e.md b/contrib/gcc/config/arm/arm1020e.md
new file mode 100644
index 0000000..32a5d95
--- /dev/null
+++ b/contrib/gcc/config/arm/arm1020e.md
@@ -0,0 +1,388 @@
+;; ARM 1020E & ARM 1022E Pipeline Description
+;; Copyright (C) 2005 Free Software Foundation, Inc.
+;; Contributed by Richard Earnshaw (richard.earnshaw@arm.com)
+;;
+;; 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.
+;;
+;; 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. */
+
+;; These descriptions are based on the information contained in the
+;; ARM1020E Technical Reference Manual, Copyright (c) 2003 ARM
+;; Limited.
+;;
+
+;; This automaton provides a pipeline description for the ARM
+;; 1020E core.
+;;
+;; The model given here assumes that the condition for all conditional
+;; instructions is "true", i.e., that all of the instructions are
+;; actually executed.
+
+(define_automaton "arm1020e")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Pipelines
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; There are two pipelines:
+;;
+;; - An Arithmetic Logic Unit (ALU) pipeline.
+;;
+;; The ALU pipeline has fetch, issue, decode, execute, memory, and
+;; write stages. We only need to model the execute, memory and write
+;; stages.
+;;
+;; - A Load-Store Unit (LSU) pipeline.
+;;
+;; The LSU pipeline has decode, execute, memory, and write stages.
+;; We only model the execute, memory and write stages.
+
+(define_cpu_unit "1020a_e,1020a_m,1020a_w" "arm1020e")
+(define_cpu_unit "1020l_e,1020l_m,1020l_w" "arm1020e")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; ALU Instructions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; ALU instructions require three cycles to execute, and use the ALU
+;; pipeline in each of the three stages. The results are available
+;; after the execute stage stage has finished.
+;;
+;; If the destination register is the PC, the pipelines are stalled
+;; for several cycles. That case is not modeled here.
+
+;; ALU operations with no shifted operand
+(define_insn_reservation "1020alu_op" 1
+ (and (eq_attr "tune" "arm1020e,arm1022e")
+ (eq_attr "type" "alu"))
+ "1020a_e,1020a_m,1020a_w")
+
+;; ALU operations with a shift-by-constant operand
+(define_insn_reservation "1020alu_shift_op" 1
+ (and (eq_attr "tune" "arm1020e,arm1022e")
+ (eq_attr "type" "alu_shift"))
+ "1020a_e,1020a_m,1020a_w")
+
+;; ALU operations with a shift-by-register operand
+;; These really stall in the decoder, in order to read
+;; the shift value in a second cycle. Pretend we take two cycles in
+;; the execute stage.
+(define_insn_reservation "1020alu_shift_reg_op" 2
+ (and (eq_attr "tune" "arm1020e,arm1022e")
+ (eq_attr "type" "alu_shift_reg"))
+ "1020a_e*2,1020a_m,1020a_w")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Multiplication Instructions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Multiplication instructions loop in the execute stage until the
+;; instruction has been passed through the multiplier array enough
+;; times.
+
+;; The result of the "smul" and "smulw" instructions is not available
+;; until after the memory stage.
+(define_insn_reservation "1020mult1" 2
+ (and (eq_attr "tune" "arm1020e,arm1022e")
+ (eq_attr "insn" "smulxy,smulwy"))
+ "1020a_e,1020a_m,1020a_w")
+
+;; The "smlaxy" and "smlawx" instructions require two iterations through
+;; the execute stage; the result is available immediately following
+;; the execute stage.
+(define_insn_reservation "1020mult2" 2
+ (and (eq_attr "tune" "arm1020e,arm1022e")
+ (eq_attr "insn" "smlaxy,smlalxy,smlawx"))
+ "1020a_e*2,1020a_m,1020a_w")
+
+;; The "smlalxy", "mul", and "mla" instructions require two iterations
+;; through the execute stage; the result is not available until after
+;; the memory stage.
+(define_insn_reservation "1020mult3" 3
+ (and (eq_attr "tune" "arm1020e,arm1022e")
+ (eq_attr "insn" "smlalxy,mul,mla"))
+ "1020a_e*2,1020a_m,1020a_w")
+
+;; The "muls" and "mlas" instructions loop in the execute stage for
+;; four iterations in order to set the flags. The value result is
+;; available after three iterations.
+(define_insn_reservation "1020mult4" 3
+ (and (eq_attr "tune" "arm1020e,arm1022e")
+ (eq_attr "insn" "muls,mlas"))
+ "1020a_e*4,1020a_m,1020a_w")
+
+;; Long multiply instructions that produce two registers of
+;; output (such as umull) make their results available in two cycles;
+;; the least significant word is available before the most significant
+;; word. That fact is not modeled; instead, the instructions are
+;; described.as if the entire result was available at the end of the
+;; cycle in which both words are available.
+
+;; The "umull", "umlal", "smull", and "smlal" instructions all take
+;; three iterations through the execute cycle, and make their results
+;; available after the memory cycle.
+(define_insn_reservation "1020mult5" 4
+ (and (eq_attr "tune" "arm1020e,arm1022e")
+ (eq_attr "insn" "umull,umlal,smull,smlal"))
+ "1020a_e*3,1020a_m,1020a_w")
+
+;; The "umulls", "umlals", "smulls", and "smlals" instructions loop in
+;; the execute stage for five iterations in order to set the flags.
+;; The value result is available after four iterations.
+(define_insn_reservation "1020mult6" 4
+ (and (eq_attr "tune" "arm1020e,arm1022e")
+ (eq_attr "insn" "umulls,umlals,smulls,smlals"))
+ "1020a_e*5,1020a_m,1020a_w")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Load/Store Instructions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; The models for load/store instructions do not accurately describe
+;; the difference between operations with a base register writeback
+;; (such as "ldm!"). These models assume that all memory references
+;; hit in dcache.
+
+;; LSU instructions require six cycles to execute. They use the ALU
+;; pipeline in all but the 5th cycle, and the LSU pipeline in cycles
+;; three through six.
+;; Loads and stores which use a scaled register offset or scaled
+;; register pre-indexed addressing mode take three cycles EXCEPT for
+;; those that are base + offset with LSL of 0 or 2, or base - offset
+;; with LSL of zero. The remainder take 1 cycle to execute.
+;; For 4byte loads there is a bypass from the load stage
+
+(define_insn_reservation "1020load1_op" 2
+ (and (eq_attr "tune" "arm1020e,arm1022e")
+ (eq_attr "type" "load_byte,load1"))
+ "1020a_e+1020l_e,1020l_m,1020l_w")
+
+(define_insn_reservation "1020store1_op" 0
+ (and (eq_attr "tune" "arm1020e,arm1022e")
+ (eq_attr "type" "store1"))
+ "1020a_e+1020l_e,1020l_m,1020l_w")
+
+;; A load's result can be stored by an immediately following store
+(define_bypass 1 "1020load1_op" "1020store1_op" "arm_no_early_store_addr_dep")
+
+;; On a LDM/STM operation, the LSU pipeline iterates until all of the
+;; registers have been processed.
+;;
+;; The time it takes to load the data depends on whether or not the
+;; base address is 64-bit aligned; if it is not, an additional cycle
+;; is required. This model assumes that the address is always 64-bit
+;; aligned. Because the processor can load two registers per cycle,
+;; that assumption means that we use the same instruction reservations
+;; for loading 2k and 2k - 1 registers.
+;;
+;; The ALU pipeline is decoupled after the first cycle unless there is
+;; a register dependency; the dependency is cleared as soon as the LDM/STM
+;; has dealt with the corresponding register. So for example,
+;; stmia sp, {r0-r3}
+;; add r0, r0, #4
+;; will have one fewer stalls than
+;; stmia sp, {r0-r3}
+;; add r3, r3, #4
+;;
+;; As with ALU operations, if one of the destination registers is the
+;; PC, there are additional stalls; that is not modeled.
+
+(define_insn_reservation "1020load2_op" 2
+ (and (eq_attr "tune" "arm1020e,arm1022e")
+ (eq_attr "type" "load2"))
+ "1020a_e+1020l_e,1020l_m,1020l_w")
+
+(define_insn_reservation "1020store2_op" 0
+ (and (eq_attr "tune" "arm1020e,arm1022e")
+ (eq_attr "type" "store2"))
+ "1020a_e+1020l_e,1020l_m,1020l_w")
+
+(define_insn_reservation "1020load34_op" 3
+ (and (eq_attr "tune" "arm1020e,arm1022e")
+ (eq_attr "type" "load3,load4"))
+ "1020a_e+1020l_e,1020l_e+1020l_m,1020l_m,1020l_w")
+
+(define_insn_reservation "1020store34_op" 0
+ (and (eq_attr "tune" "arm1020e,arm1022e")
+ (eq_attr "type" "store3,store4"))
+ "1020a_e+1020l_e,1020l_e+1020l_m,1020l_m,1020l_w")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Branch and Call Instructions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Branch instructions are difficult to model accurately. The ARM
+;; core can predict most branches. If the branch is predicted
+;; correctly, and predicted early enough, the branch can be completely
+;; eliminated from the instruction stream. Some branches can
+;; therefore appear to require zero cycles to execute. We assume that
+;; all branches are predicted correctly, and that the latency is
+;; therefore the minimum value.
+
+(define_insn_reservation "1020branch_op" 0
+ (and (eq_attr "tune" "arm1020e,arm1022e")
+ (eq_attr "type" "branch"))
+ "1020a_e")
+
+;; The latency for a call is not predictable. Therefore, we use 32 as
+;; roughly equivalent to positive infinity.
+
+(define_insn_reservation "1020call_op" 32
+ (and (eq_attr "tune" "arm1020e,arm1022e")
+ (eq_attr "type" "call"))
+ "1020a_e*32")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; VFP
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define_cpu_unit "v10_fmac" "arm1020e")
+
+(define_cpu_unit "v10_ds" "arm1020e")
+
+(define_cpu_unit "v10_fmstat" "arm1020e")
+
+(define_cpu_unit "v10_ls1,v10_ls2,v10_ls3" "arm1020e")
+
+;; fmstat is a serializing instruction. It will stall the core until
+;; the mac and ds units have completed.
+(exclusion_set "v10_fmac,v10_ds" "v10_fmstat")
+
+(define_attr "vfp10" "yes,no"
+ (const (if_then_else (and (eq_attr "tune" "arm1020e,arm1022e")
+ (eq_attr "fpu" "vfp"))
+ (const_string "yes") (const_string "no"))))
+
+;; The VFP "type" attributes differ from those used in the FPA model.
+;; ffarith Fast floating point insns, e.g. abs, neg, cpy, cmp.
+;; farith Most arithmetic insns.
+;; fmul Double precision multiply.
+;; fdivs Single precision sqrt or division.
+;; fdivd Double precision sqrt or division.
+;; f_flag fmstat operation
+;; f_load Floating point load from memory.
+;; f_store Floating point store to memory.
+;; f_2_r Transfer vfp to arm reg.
+;; r_2_f Transfer arm to vfp reg.
+
+;; Note, no instruction can issue to the VFP if the core is stalled in the
+;; first execute state. We model this by using 1020a_e in the first cycle.
+(define_insn_reservation "v10_ffarith" 5
+ (and (eq_attr "vfp10" "yes")
+ (eq_attr "type" "ffarith"))
+ "1020a_e+v10_fmac")
+
+(define_insn_reservation "v10_farith" 5
+ (and (eq_attr "vfp10" "yes")
+ (eq_attr "type" "farith"))
+ "1020a_e+v10_fmac")
+
+(define_insn_reservation "v10_cvt" 5
+ (and (eq_attr "vfp10" "yes")
+ (eq_attr "type" "f_cvt"))
+ "1020a_e+v10_fmac")
+
+(define_insn_reservation "v10_fmul" 6
+ (and (eq_attr "vfp10" "yes")
+ (eq_attr "type" "fmul"))
+ "1020a_e+v10_fmac*2")
+
+(define_insn_reservation "v10_fdivs" 18
+ (and (eq_attr "vfp10" "yes")
+ (eq_attr "type" "fdivs"))
+ "1020a_e+v10_ds*14")
+
+(define_insn_reservation "v10_fdivd" 32
+ (and (eq_attr "vfp10" "yes")
+ (eq_attr "type" "fdivd"))
+ "1020a_e+v10_fmac+v10_ds*28")
+
+(define_insn_reservation "v10_floads" 4
+ (and (eq_attr "vfp10" "yes")
+ (eq_attr "type" "f_loads"))
+ "1020a_e+1020l_e+v10_ls1,v10_ls2")
+
+;; We model a load of a double as needing all the vfp ls* stage in cycle 1.
+;; This gives the correct mix between single-and double loads where a flds
+;; followed by and fldd will stall for one cycle, but two back-to-back fldd
+;; insns stall for two cycles.
+(define_insn_reservation "v10_floadd" 5
+ (and (eq_attr "vfp10" "yes")
+ (eq_attr "type" "f_loadd"))
+ "1020a_e+1020l_e+v10_ls1+v10_ls2+v10_ls3,v10_ls2+v10_ls3,v10_ls3")
+
+;; Moves to/from arm regs also use the load/store pipeline.
+
+(define_insn_reservation "v10_c2v" 4
+ (and (eq_attr "vfp10" "yes")
+ (eq_attr "type" "r_2_f"))
+ "1020a_e+1020l_e+v10_ls1,v10_ls2")
+
+(define_insn_reservation "v10_fstores" 1
+ (and (eq_attr "vfp10" "yes")
+ (eq_attr "type" "f_stores"))
+ "1020a_e+1020l_e+v10_ls1,v10_ls2")
+
+(define_insn_reservation "v10_fstored" 1
+ (and (eq_attr "vfp10" "yes")
+ (eq_attr "type" "f_stored"))
+ "1020a_e+1020l_e+v10_ls1+v10_ls2+v10_ls3,v10_ls2+v10_ls3,v10_ls3")
+
+(define_insn_reservation "v10_v2c" 1
+ (and (eq_attr "vfp10" "yes")
+ (eq_attr "type" "f_2_r"))
+ "1020a_e+1020l_e,1020l_m,1020l_w")
+
+(define_insn_reservation "v10_to_cpsr" 2
+ (and (eq_attr "vfp10" "yes")
+ (eq_attr "type" "f_flag"))
+ "1020a_e+v10_fmstat,1020a_e+1020l_e,1020l_m,1020l_w")
+
+;; VFP bypasses
+
+;; There are bypasses for most operations other than store
+
+(define_bypass 3
+ "v10_c2v,v10_floads"
+ "v10_ffarith,v10_farith,v10_fmul,v10_fdivs,v10_fdivd,v10_cvt")
+
+(define_bypass 4
+ "v10_floadd"
+ "v10_ffarith,v10_farith,v10_fmul,v10_fdivs,v10_fdivd")
+
+;; Arithmetic to other arithmetic saves a cycle due to forwarding
+(define_bypass 4
+ "v10_ffarith,v10_farith"
+ "v10_ffarith,v10_farith,v10_fmul,v10_fdivs,v10_fdivd")
+
+(define_bypass 5
+ "v10_fmul"
+ "v10_ffarith,v10_farith,v10_fmul,v10_fdivs,v10_fdivd")
+
+(define_bypass 17
+ "v10_fdivs"
+ "v10_ffarith,v10_farith,v10_fmul,v10_fdivs,v10_fdivd")
+
+(define_bypass 31
+ "v10_fdivd"
+ "v10_ffarith,v10_farith,v10_fmul,v10_fdivs,v10_fdivd")
+
+;; VFP anti-dependencies.
+
+;; There is one anti-dependence in the following case (not yet modelled):
+;; - After a store: one extra cycle for both fsts and fstd
+;; Note, back-to-back fstd instructions will overload the load/store datapath
+;; causing a two-cycle stall.
diff --git a/contrib/gcc/config/arm/arm1026ejs.md b/contrib/gcc/config/arm/arm1026ejs.md
new file mode 100644
index 0000000..a2404ec
--- /dev/null
+++ b/contrib/gcc/config/arm/arm1026ejs.md
@@ -0,0 +1,241 @@
+;; ARM 1026EJ-S Pipeline Description
+;; Copyright (C) 2003 Free Software Foundation, Inc.
+;; Written by CodeSourcery, LLC.
+;;
+;; 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.
+;;
+;; 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. */
+
+;; These descriptions are based on the information contained in the
+;; ARM1026EJ-S Technical Reference Manual, Copyright (c) 2003 ARM
+;; Limited.
+;;
+
+;; This automaton provides a pipeline description for the ARM
+;; 1026EJ-S core.
+;;
+;; The model given here assumes that the condition for all conditional
+;; instructions is "true", i.e., that all of the instructions are
+;; actually executed.
+
+(define_automaton "arm1026ejs")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Pipelines
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; There are two pipelines:
+;;
+;; - An Arithmetic Logic Unit (ALU) pipeline.
+;;
+;; The ALU pipeline has fetch, issue, decode, execute, memory, and
+;; write stages. We only need to model the execute, memory and write
+;; stages.
+;;
+;; - A Load-Store Unit (LSU) pipeline.
+;;
+;; The LSU pipeline has decode, execute, memory, and write stages.
+;; We only model the execute, memory and write stages.
+
+(define_cpu_unit "a_e,a_m,a_w" "arm1026ejs")
+(define_cpu_unit "l_e,l_m,l_w" "arm1026ejs")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; ALU Instructions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; ALU instructions require three cycles to execute, and use the ALU
+;; pipeline in each of the three stages. The results are available
+;; after the execute stage stage has finished.
+;;
+;; If the destination register is the PC, the pipelines are stalled
+;; for several cycles. That case is not modeled here.
+
+;; ALU operations with no shifted operand
+(define_insn_reservation "alu_op" 1
+ (and (eq_attr "tune" "arm1026ejs")
+ (eq_attr "type" "alu"))
+ "a_e,a_m,a_w")
+
+;; ALU operations with a shift-by-constant operand
+(define_insn_reservation "alu_shift_op" 1
+ (and (eq_attr "tune" "arm1026ejs")
+ (eq_attr "type" "alu_shift"))
+ "a_e,a_m,a_w")
+
+;; ALU operations with a shift-by-register operand
+;; These really stall in the decoder, in order to read
+;; the shift value in a second cycle. Pretend we take two cycles in
+;; the execute stage.
+(define_insn_reservation "alu_shift_reg_op" 2
+ (and (eq_attr "tune" "arm1026ejs")
+ (eq_attr "type" "alu_shift_reg"))
+ "a_e*2,a_m,a_w")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Multiplication Instructions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Multiplication instructions loop in the execute stage until the
+;; instruction has been passed through the multiplier array enough
+;; times.
+
+;; The result of the "smul" and "smulw" instructions is not available
+;; until after the memory stage.
+(define_insn_reservation "mult1" 2
+ (and (eq_attr "tune" "arm1026ejs")
+ (eq_attr "insn" "smulxy,smulwy"))
+ "a_e,a_m,a_w")
+
+;; The "smlaxy" and "smlawx" instructions require two iterations through
+;; the execute stage; the result is available immediately following
+;; the execute stage.
+(define_insn_reservation "mult2" 2
+ (and (eq_attr "tune" "arm1026ejs")
+ (eq_attr "insn" "smlaxy,smlalxy,smlawx"))
+ "a_e*2,a_m,a_w")
+
+;; The "smlalxy", "mul", and "mla" instructions require two iterations
+;; through the execute stage; the result is not available until after
+;; the memory stage.
+(define_insn_reservation "mult3" 3
+ (and (eq_attr "tune" "arm1026ejs")
+ (eq_attr "insn" "smlalxy,mul,mla"))
+ "a_e*2,a_m,a_w")
+
+;; The "muls" and "mlas" instructions loop in the execute stage for
+;; four iterations in order to set the flags. The value result is
+;; available after three iterations.
+(define_insn_reservation "mult4" 3
+ (and (eq_attr "tune" "arm1026ejs")
+ (eq_attr "insn" "muls,mlas"))
+ "a_e*4,a_m,a_w")
+
+;; Long multiply instructions that produce two registers of
+;; output (such as umull) make their results available in two cycles;
+;; the least significant word is available before the most significant
+;; word. That fact is not modeled; instead, the instructions are
+;; described.as if the entire result was available at the end of the
+;; cycle in which both words are available.
+
+;; The "umull", "umlal", "smull", and "smlal" instructions all take
+;; three iterations through the execute cycle, and make their results
+;; available after the memory cycle.
+(define_insn_reservation "mult5" 4
+ (and (eq_attr "tune" "arm1026ejs")
+ (eq_attr "insn" "umull,umlal,smull,smlal"))
+ "a_e*3,a_m,a_w")
+
+;; The "umulls", "umlals", "smulls", and "smlals" instructions loop in
+;; the execute stage for five iterations in order to set the flags.
+;; The value result is available after four iterations.
+(define_insn_reservation "mult6" 4
+ (and (eq_attr "tune" "arm1026ejs")
+ (eq_attr "insn" "umulls,umlals,smulls,smlals"))
+ "a_e*5,a_m,a_w")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Load/Store Instructions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; The models for load/store instructions do not accurately describe
+;; the difference between operations with a base register writeback
+;; (such as "ldm!"). These models assume that all memory references
+;; hit in dcache.
+
+;; LSU instructions require six cycles to execute. They use the ALU
+;; pipeline in all but the 5th cycle, and the LSU pipeline in cycles
+;; three through six.
+;; Loads and stores which use a scaled register offset or scaled
+;; register pre-indexed addressing mode take three cycles EXCEPT for
+;; those that are base + offset with LSL of 0 or 2, or base - offset
+;; with LSL of zero. The remainder take 1 cycle to execute.
+;; For 4byte loads there is a bypass from the load stage
+
+(define_insn_reservation "load1_op" 2
+ (and (eq_attr "tune" "arm1026ejs")
+ (eq_attr "type" "load_byte,load1"))
+ "a_e+l_e,l_m,a_w+l_w")
+
+(define_insn_reservation "store1_op" 0
+ (and (eq_attr "tune" "arm1026ejs")
+ (eq_attr "type" "store1"))
+ "a_e+l_e,l_m,a_w+l_w")
+
+;; A load's result can be stored by an immediately following store
+(define_bypass 1 "load1_op" "store1_op" "arm_no_early_store_addr_dep")
+
+;; On a LDM/STM operation, the LSU pipeline iterates until all of the
+;; registers have been processed.
+;;
+;; The time it takes to load the data depends on whether or not the
+;; base address is 64-bit aligned; if it is not, an additional cycle
+;; is required. This model assumes that the address is always 64-bit
+;; aligned. Because the processor can load two registers per cycle,
+;; that assumption means that we use the same instruction reservations
+;; for loading 2k and 2k - 1 registers.
+;;
+;; The ALU pipeline is stalled until the completion of the last memory
+;; stage in the LSU pipeline. That is modeled by keeping the ALU
+;; execute stage busy until that point.
+;;
+;; As with ALU operations, if one of the destination registers is the
+;; PC, there are additional stalls; that is not modeled.
+
+(define_insn_reservation "load2_op" 2
+ (and (eq_attr "tune" "arm1026ejs")
+ (eq_attr "type" "load2"))
+ "a_e+l_e,l_m,a_w+l_w")
+
+(define_insn_reservation "store2_op" 0
+ (and (eq_attr "tune" "arm1026ejs")
+ (eq_attr "type" "store2"))
+ "a_e+l_e,l_m,a_w+l_w")
+
+(define_insn_reservation "load34_op" 3
+ (and (eq_attr "tune" "arm1026ejs")
+ (eq_attr "type" "load3,load4"))
+ "a_e+l_e,a_e+l_e+l_m,a_e+l_m,a_w+l_w")
+
+(define_insn_reservation "store34_op" 0
+ (and (eq_attr "tune" "arm1026ejs")
+ (eq_attr "type" "store3,store4"))
+ "a_e+l_e,a_e+l_e+l_m,a_e+l_m,a_w+l_w")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Branch and Call Instructions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Branch instructions are difficult to model accurately. The ARM
+;; core can predict most branches. If the branch is predicted
+;; correctly, and predicted early enough, the branch can be completely
+;; eliminated from the instruction stream. Some branches can
+;; therefore appear to require zero cycles to execute. We assume that
+;; all branches are predicted correctly, and that the latency is
+;; therefore the minimum value.
+
+(define_insn_reservation "branch_op" 0
+ (and (eq_attr "tune" "arm1026ejs")
+ (eq_attr "type" "branch"))
+ "nothing")
+
+;; The latency for a call is not predictable. Therefore, we use 32 as
+;; roughly equivalent to positive infinity.
+
+(define_insn_reservation "call_op" 32
+ (and (eq_attr "tune" "arm1026ejs")
+ (eq_attr "type" "call"))
+ "nothing")
diff --git a/contrib/gcc/config/arm/arm1136jfs.md b/contrib/gcc/config/arm/arm1136jfs.md
new file mode 100644
index 0000000..3086697
--- /dev/null
+++ b/contrib/gcc/config/arm/arm1136jfs.md
@@ -0,0 +1,377 @@
+;; ARM 1136J[F]-S Pipeline Description
+;; Copyright (C) 2003 Free Software Foundation, Inc.
+;; Written by CodeSourcery, LLC.
+;;
+;; 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.
+;;
+;; 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. */
+
+;; These descriptions are based on the information contained in the
+;; ARM1136JF-S Technical Reference Manual, Copyright (c) 2003 ARM
+;; Limited.
+;;
+
+;; This automaton provides a pipeline description for the ARM
+;; 1136J-S and 1136JF-S cores.
+;;
+;; The model given here assumes that the condition for all conditional
+;; instructions is "true", i.e., that all of the instructions are
+;; actually executed.
+
+(define_automaton "arm1136jfs")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Pipelines
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; There are three distinct pipelines (page 1-26 and following):
+;;
+;; - A 4-stage decode pipeline, shared by all three. It has fetch (1),
+;; fetch (2), decode, and issue stages. Since this is always involved,
+;; we do not model it in the scheduler.
+;;
+;; - A 4-stage ALU pipeline. It has shifter, ALU (main integer operations),
+;; and saturation stages. The fourth stage is writeback; see below.
+;;
+;; - A 4-stage multiply-accumulate pipeline. It has three stages, called
+;; MAC1 through MAC3, and a fourth writeback stage.
+;;
+;; The 4th-stage writeback is shared between the ALU and MAC pipelines,
+;; which operate in lockstep. Results from either pipeline will be
+;; moved into the writeback stage. Because the two pipelines operate
+;; in lockstep, we schedule them as a single "execute" pipeline.
+;;
+;; - A 4-stage LSU pipeline. It has address generation, data cache (1),
+;; data cache (2), and writeback stages. (Note that this pipeline,
+;; including the writeback stage, is independent from the ALU & LSU pipes.)
+
+(define_cpu_unit "e_1,e_2,e_3,e_wb" "arm1136jfs") ; ALU and MAC
+; e_1 = Sh/Mac1, e_2 = ALU/Mac2, e_3 = SAT/Mac3
+(define_cpu_unit "l_a,l_dc1,l_dc2,l_wb" "arm1136jfs") ; Load/Store
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; ALU Instructions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; ALU instructions require eight cycles to execute, and use the ALU
+;; pipeline in each of the eight stages. The results are available
+;; after the alu stage has finished.
+;;
+;; If the destination register is the PC, the pipelines are stalled
+;; for several cycles. That case is not modelled here.
+
+;; ALU operations with no shifted operand
+(define_insn_reservation "11_alu_op" 2
+ (and (eq_attr "tune" "arm1136js,arm1136jfs")
+ (eq_attr "type" "alu"))
+ "e_1,e_2,e_3,e_wb")
+
+;; ALU operations with a shift-by-constant operand
+(define_insn_reservation "11_alu_shift_op" 2
+ (and (eq_attr "tune" "arm1136js,arm1136jfs")
+ (eq_attr "type" "alu_shift"))
+ "e_1,e_2,e_3,e_wb")
+
+;; ALU operations with a shift-by-register operand
+;; These really stall in the decoder, in order to read
+;; the shift value in a second cycle. Pretend we take two cycles in
+;; the shift stage.
+(define_insn_reservation "11_alu_shift_reg_op" 3
+ (and (eq_attr "tune" "arm1136js,arm1136jfs")
+ (eq_attr "type" "alu_shift_reg"))
+ "e_1*2,e_2,e_3,e_wb")
+
+;; alu_ops can start sooner, if there is no shifter dependency
+(define_bypass 1 "11_alu_op,11_alu_shift_op"
+ "11_alu_op")
+(define_bypass 1 "11_alu_op,11_alu_shift_op"
+ "11_alu_shift_op"
+ "arm_no_early_alu_shift_value_dep")
+(define_bypass 1 "11_alu_op,11_alu_shift_op"
+ "11_alu_shift_reg_op"
+ "arm_no_early_alu_shift_dep")
+(define_bypass 2 "11_alu_shift_reg_op"
+ "11_alu_op")
+(define_bypass 2 "11_alu_shift_reg_op"
+ "11_alu_shift_op"
+ "arm_no_early_alu_shift_value_dep")
+(define_bypass 2 "11_alu_shift_reg_op"
+ "11_alu_shift_reg_op"
+ "arm_no_early_alu_shift_dep")
+
+(define_bypass 1 "11_alu_op,11_alu_shift_op"
+ "11_mult1,11_mult2,11_mult3,11_mult4,11_mult5,11_mult6,11_mult7"
+ "arm_no_early_mul_dep")
+(define_bypass 2 "11_alu_shift_reg_op"
+ "11_mult1,11_mult2,11_mult3,11_mult4,11_mult5,11_mult6,11_mult7"
+ "arm_no_early_mul_dep")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Multiplication Instructions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Multiplication instructions loop in the first two execute stages until
+;; the instruction has been passed through the multiplier array enough
+;; times.
+
+;; Multiply and multiply-accumulate results are available after four stages.
+(define_insn_reservation "11_mult1" 4
+ (and (eq_attr "tune" "arm1136js,arm1136jfs")
+ (eq_attr "insn" "mul,mla"))
+ "e_1*2,e_2,e_3,e_wb")
+
+;; The *S variants set the condition flags, which requires three more cycles.
+(define_insn_reservation "11_mult2" 4
+ (and (eq_attr "tune" "arm1136js,arm1136jfs")
+ (eq_attr "insn" "muls,mlas"))
+ "e_1*2,e_2,e_3,e_wb")
+
+(define_bypass 3 "11_mult1,11_mult2"
+ "11_mult1,11_mult2,11_mult3,11_mult4,11_mult5,11_mult6,11_mult7"
+ "arm_no_early_mul_dep")
+(define_bypass 3 "11_mult1,11_mult2"
+ "11_alu_op")
+(define_bypass 3 "11_mult1,11_mult2"
+ "11_alu_shift_op"
+ "arm_no_early_alu_shift_value_dep")
+(define_bypass 3 "11_mult1,11_mult2"
+ "11_alu_shift_reg_op"
+ "arm_no_early_alu_shift_dep")
+(define_bypass 3 "11_mult1,11_mult2"
+ "11_store1"
+ "arm_no_early_store_addr_dep")
+
+;; Signed and unsigned multiply long results are available across two cycles;
+;; the less significant word is available one cycle before the more significant
+;; word. Here we conservatively wait until both are available, which is
+;; after three iterations and the memory cycle. The same is also true of
+;; the two multiply-accumulate instructions.
+(define_insn_reservation "11_mult3" 5
+ (and (eq_attr "tune" "arm1136js,arm1136jfs")
+ (eq_attr "insn" "smull,umull,smlal,umlal"))
+ "e_1*3,e_2,e_3,e_wb*2")
+
+;; The *S variants set the condition flags, which requires three more cycles.
+(define_insn_reservation "11_mult4" 5
+ (and (eq_attr "tune" "arm1136js,arm1136jfs")
+ (eq_attr "insn" "smulls,umulls,smlals,umlals"))
+ "e_1*3,e_2,e_3,e_wb*2")
+
+(define_bypass 4 "11_mult3,11_mult4"
+ "11_mult1,11_mult2,11_mult3,11_mult4,11_mult5,11_mult6,11_mult7"
+ "arm_no_early_mul_dep")
+(define_bypass 4 "11_mult3,11_mult4"
+ "11_alu_op")
+(define_bypass 4 "11_mult3,11_mult4"
+ "11_alu_shift_op"
+ "arm_no_early_alu_shift_value_dep")
+(define_bypass 4 "11_mult3,11_mult4"
+ "11_alu_shift_reg_op"
+ "arm_no_early_alu_shift_dep")
+(define_bypass 4 "11_mult3,11_mult4"
+ "11_store1"
+ "arm_no_early_store_addr_dep")
+
+;; Various 16x16->32 multiplies and multiply-accumulates, using combinations
+;; of high and low halves of the argument registers. They take a single
+;; pass through the pipeline and make the result available after three
+;; cycles.
+(define_insn_reservation "11_mult5" 3
+ (and (eq_attr "tune" "arm1136js,arm1136jfs")
+ (eq_attr "insn" "smulxy,smlaxy,smulwy,smlawy,smuad,smuadx,smlad,smladx,smusd,smusdx,smlsd,smlsdx"))
+ "e_1,e_2,e_3,e_wb")
+
+(define_bypass 2 "11_mult5"
+ "11_mult1,11_mult2,11_mult3,11_mult4,11_mult5,11_mult6,11_mult7"
+ "arm_no_early_mul_dep")
+(define_bypass 2 "11_mult5"
+ "11_alu_op")
+(define_bypass 2 "11_mult5"
+ "11_alu_shift_op"
+ "arm_no_early_alu_shift_value_dep")
+(define_bypass 2 "11_mult5"
+ "11_alu_shift_reg_op"
+ "arm_no_early_alu_shift_dep")
+(define_bypass 2 "11_mult5"
+ "11_store1"
+ "arm_no_early_store_addr_dep")
+
+;; The same idea, then the 32-bit result is added to a 64-bit quantity.
+(define_insn_reservation "11_mult6" 4
+ (and (eq_attr "tune" "arm1136js,arm1136jfs")
+ (eq_attr "insn" "smlalxy"))
+ "e_1*2,e_2,e_3,e_wb*2")
+
+;; Signed 32x32 multiply, then the most significant 32 bits are extracted
+;; and are available after the memory stage.
+(define_insn_reservation "11_mult7" 4
+ (and (eq_attr "tune" "arm1136js,arm1136jfs")
+ (eq_attr "insn" "smmul,smmulr"))
+ "e_1*2,e_2,e_3,e_wb")
+
+(define_bypass 3 "11_mult6,11_mult7"
+ "11_mult1,11_mult2,11_mult3,11_mult4,11_mult5,11_mult6,11_mult7"
+ "arm_no_early_mul_dep")
+(define_bypass 3 "11_mult6,11_mult7"
+ "11_alu_op")
+(define_bypass 3 "11_mult6,11_mult7"
+ "11_alu_shift_op"
+ "arm_no_early_alu_shift_value_dep")
+(define_bypass 3 "11_mult6,11_mult7"
+ "11_alu_shift_reg_op"
+ "arm_no_early_alu_shift_dep")
+(define_bypass 3 "11_mult6,11_mult7"
+ "11_store1"
+ "arm_no_early_store_addr_dep")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Branch Instructions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; These vary greatly depending on their arguments and the results of
+;; stat prediction. Cycle count ranges from zero (unconditional branch,
+;; folded dynamic prediction) to seven (incorrect predictions, etc). We
+;; assume an optimal case for now, because the cost of a cache miss
+;; overwhelms the cost of everything else anyhow.
+
+(define_insn_reservation "11_branches" 0
+ (and (eq_attr "tune" "arm1136js,arm1136jfs")
+ (eq_attr "type" "branch"))
+ "nothing")
+
+;; Call latencies are not predictable. A semi-arbitrary very large
+;; number is used as "positive infinity" so that everything should be
+;; finished by the time of return.
+(define_insn_reservation "11_call" 32
+ (and (eq_attr "tune" "arm1136js,arm1136jfs")
+ (eq_attr "type" "call"))
+ "nothing")
+
+;; Branches are predicted. A correctly predicted branch will be no
+;; cost, but we're conservative here, and use the timings a
+;; late-register would give us.
+(define_bypass 1 "11_alu_op,11_alu_shift_op"
+ "11_branches")
+(define_bypass 2 "11_alu_shift_reg_op"
+ "11_branches")
+(define_bypass 2 "11_load1,11_load2"
+ "11_branches")
+(define_bypass 3 "11_load34"
+ "11_branches")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Load/Store Instructions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; The models for load/store instructions do not accurately describe
+;; the difference between operations with a base register writeback.
+;; These models assume that all memory references hit in dcache. Also,
+;; if the PC is one of the registers involved, there are additional stalls
+;; not modelled here. Addressing modes are also not modelled.
+
+(define_insn_reservation "11_load1" 3
+ (and (eq_attr "tune" "arm1136js,arm1136jfs")
+ (eq_attr "type" "load1"))
+ "l_a+e_1,l_dc1,l_dc2,l_wb")
+
+;; Load byte results are not available until the writeback stage, where
+;; the correct byte is extracted.
+
+(define_insn_reservation "11_loadb" 4
+ (and (eq_attr "tune" "arm1136js,arm1136jfs")
+ (eq_attr "type" "load_byte"))
+ "l_a+e_1,l_dc1,l_dc2,l_wb")
+
+(define_insn_reservation "11_store1" 0
+ (and (eq_attr "tune" "arm1136js,arm1136jfs")
+ (eq_attr "type" "store1"))
+ "l_a+e_1,l_dc1,l_dc2,l_wb")
+
+;; Load/store double words into adjacent registers. The timing and
+;; latencies are different depending on whether the address is 64-bit
+;; aligned. This model assumes that it is.
+(define_insn_reservation "11_load2" 3
+ (and (eq_attr "tune" "arm1136js,arm1136jfs")
+ (eq_attr "type" "load2"))
+ "l_a+e_1,l_dc1,l_dc2,l_wb")
+
+(define_insn_reservation "11_store2" 0
+ (and (eq_attr "tune" "arm1136js,arm1136jfs")
+ (eq_attr "type" "store2"))
+ "l_a+e_1,l_dc1,l_dc2,l_wb")
+
+;; Load/store multiple registers. Two registers are stored per cycle.
+;; Actual timing depends on how many registers are affected, so we
+;; optimistically schedule a low latency.
+(define_insn_reservation "11_load34" 4
+ (and (eq_attr "tune" "arm1136js,arm1136jfs")
+ (eq_attr "type" "load3,load4"))
+ "l_a+e_1,l_dc1*2,l_dc2,l_wb")
+
+(define_insn_reservation "11_store34" 0
+ (and (eq_attr "tune" "arm1136js,arm1136jfs")
+ (eq_attr "type" "store3,store4"))
+ "l_a+e_1,l_dc1*2,l_dc2,l_wb")
+
+;; A store can start immediately after an alu op, if that alu op does
+;; not provide part of the address to access.
+(define_bypass 1 "11_alu_op,11_alu_shift_op"
+ "11_store1"
+ "arm_no_early_store_addr_dep")
+(define_bypass 2 "11_alu_shift_reg_op"
+ "11_store1"
+ "arm_no_early_store_addr_dep")
+
+;; An alu op can start sooner after a load, if that alu op does not
+;; have an early register dependency on the load
+(define_bypass 2 "11_load1"
+ "11_alu_op")
+(define_bypass 2 "11_load1"
+ "11_alu_shift_op"
+ "arm_no_early_alu_shift_value_dep")
+(define_bypass 2 "11_load1"
+ "11_alu_shift_reg_op"
+ "arm_no_early_alu_shift_dep")
+
+(define_bypass 3 "11_loadb"
+ "11_alu_op")
+(define_bypass 3 "11_loadb"
+ "11_alu_shift_op"
+ "arm_no_early_alu_shift_value_dep")
+(define_bypass 3 "11_loadb"
+ "11_alu_shift_reg_op"
+ "arm_no_early_alu_shift_dep")
+
+;; A mul op can start sooner after a load, if that mul op does not
+;; have an early multiply dependency
+(define_bypass 2 "11_load1"
+ "11_mult1,11_mult2,11_mult3,11_mult4,11_mult5,11_mult6,11_mult7"
+ "arm_no_early_mul_dep")
+(define_bypass 3 "11_load34"
+ "11_mult1,11_mult2,11_mult3,11_mult4,11_mult5,11_mult6,11_mult7"
+ "arm_no_early_mul_dep")
+(define_bypass 3 "11_loadb"
+ "11_mult1,11_mult2,11_mult3,11_mult4,11_mult5,11_mult6,11_mult7"
+ "arm_no_early_mul_dep")
+
+;; A store can start sooner after a load, if that load does not
+;; produce part of the address to access
+(define_bypass 2 "11_load1"
+ "11_store1"
+ "arm_no_early_store_addr_dep")
+(define_bypass 3 "11_loadb"
+ "11_store1"
+ "arm_no_early_store_addr_dep")
diff --git a/contrib/gcc/config/arm/arm926ejs.md b/contrib/gcc/config/arm/arm926ejs.md
new file mode 100644
index 0000000..244e3a9
--- /dev/null
+++ b/contrib/gcc/config/arm/arm926ejs.md
@@ -0,0 +1,188 @@
+;; ARM 926EJ-S Pipeline Description
+;; Copyright (C) 2003 Free Software Foundation, Inc.
+;; Written by CodeSourcery, LLC.
+;;
+;; 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.
+;;
+;; 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. */
+
+;; These descriptions are based on the information contained in the
+;; ARM926EJ-S Technical Reference Manual, Copyright (c) 2002 ARM
+;; Limited.
+;;
+
+;; This automaton provides a pipeline description for the ARM
+;; 926EJ-S core.
+;;
+;; The model given here assumes that the condition for all conditional
+;; instructions is "true", i.e., that all of the instructions are
+;; actually executed.
+
+(define_automaton "arm926ejs")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Pipelines
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; There is a single pipeline
+;;
+;; The ALU pipeline has fetch, decode, execute, memory, and
+;; write stages. We only need to model the execute, memory and write
+;; stages.
+
+(define_cpu_unit "e,m,w" "arm926ejs")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; ALU Instructions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; ALU instructions require three cycles to execute, and use the ALU
+;; pipeline in each of the three stages. The results are available
+;; after the execute stage stage has finished.
+;;
+;; If the destination register is the PC, the pipelines are stalled
+;; for several cycles. That case is not modeled here.
+
+;; ALU operations with no shifted operand
+(define_insn_reservation "9_alu_op" 1
+ (and (eq_attr "tune" "arm926ejs")
+ (eq_attr "type" "alu,alu_shift"))
+ "e,m,w")
+
+;; ALU operations with a shift-by-register operand
+;; These really stall in the decoder, in order to read
+;; the shift value in a second cycle. Pretend we take two cycles in
+;; the execute stage.
+(define_insn_reservation "9_alu_shift_reg_op" 2
+ (and (eq_attr "tune" "arm926ejs")
+ (eq_attr "type" "alu_shift_reg"))
+ "e*2,m,w")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Multiplication Instructions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Multiplication instructions loop in the execute stage until the
+;; instruction has been passed through the multiplier array enough
+;; times. Multiply operations occur in both the execute and memory
+;; stages of the pipeline
+
+(define_insn_reservation "9_mult1" 3
+ (and (eq_attr "tune" "arm926ejs")
+ (eq_attr "insn" "smlalxy,mul,mla"))
+ "e*2,m,w")
+
+(define_insn_reservation "9_mult2" 4
+ (and (eq_attr "tune" "arm926ejs")
+ (eq_attr "insn" "muls,mlas"))
+ "e*3,m,w")
+
+(define_insn_reservation "9_mult3" 4
+ (and (eq_attr "tune" "arm926ejs")
+ (eq_attr "insn" "umull,umlal,smull,smlal"))
+ "e*3,m,w")
+
+(define_insn_reservation "9_mult4" 5
+ (and (eq_attr "tune" "arm926ejs")
+ (eq_attr "insn" "umulls,umlals,smulls,smlals"))
+ "e*4,m,w")
+
+(define_insn_reservation "9_mult5" 2
+ (and (eq_attr "tune" "arm926ejs")
+ (eq_attr "insn" "smulxy,smlaxy,smlawx"))
+ "e,m,w")
+
+(define_insn_reservation "9_mult6" 3
+ (and (eq_attr "tune" "arm926ejs")
+ (eq_attr "insn" "smlalxy"))
+ "e*2,m,w")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Load/Store Instructions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; The models for load/store instructions do not accurately describe
+;; the difference between operations with a base register writeback
+;; (such as "ldm!"). These models assume that all memory references
+;; hit in dcache.
+
+;; Loads with a shifted offset take 3 cycles, and are (a) probably the
+;; most common and (b) the pessimistic assumption will lead to fewer stalls.
+(define_insn_reservation "9_load1_op" 3
+ (and (eq_attr "tune" "arm926ejs")
+ (eq_attr "type" "load1,load_byte"))
+ "e*2,m,w")
+
+(define_insn_reservation "9_store1_op" 0
+ (and (eq_attr "tune" "arm926ejs")
+ (eq_attr "type" "store1"))
+ "e,m,w")
+
+;; multiple word loads and stores
+(define_insn_reservation "9_load2_op" 3
+ (and (eq_attr "tune" "arm926ejs")
+ (eq_attr "type" "load2"))
+ "e,m*2,w")
+
+(define_insn_reservation "9_load3_op" 4
+ (and (eq_attr "tune" "arm926ejs")
+ (eq_attr "type" "load3"))
+ "e,m*3,w")
+
+(define_insn_reservation "9_load4_op" 5
+ (and (eq_attr "tune" "arm926ejs")
+ (eq_attr "type" "load4"))
+ "e,m*4,w")
+
+(define_insn_reservation "9_store2_op" 0
+ (and (eq_attr "tune" "arm926ejs")
+ (eq_attr "type" "store2"))
+ "e,m*2,w")
+
+(define_insn_reservation "9_store3_op" 0
+ (and (eq_attr "tune" "arm926ejs")
+ (eq_attr "type" "store3"))
+ "e,m*3,w")
+
+(define_insn_reservation "9_store4_op" 0
+ (and (eq_attr "tune" "arm926ejs")
+ (eq_attr "type" "store4"))
+ "e,m*4,w")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Branch and Call Instructions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Branch instructions are difficult to model accurately. The ARM
+;; core can predict most branches. If the branch is predicted
+;; correctly, and predicted early enough, the branch can be completely
+;; eliminated from the instruction stream. Some branches can
+;; therefore appear to require zero cycles to execute. We assume that
+;; all branches are predicted correctly, and that the latency is
+;; therefore the minimum value.
+
+(define_insn_reservation "9_branch_op" 0
+ (and (eq_attr "tune" "arm926ejs")
+ (eq_attr "type" "branch"))
+ "nothing")
+
+;; The latency for a call is not predictable. Therefore, we use 32 as
+;; roughly equivalent to positive infinity.
+
+(define_insn_reservation "9_call_op" 32
+ (and (eq_attr "tune" "arm926ejs")
+ (eq_attr "type" "call"))
+ "nothing")
diff --git a/contrib/gcc/config/arm/bpabi.S b/contrib/gcc/config/arm/bpabi.S
new file mode 100644
index 0000000..e492d4b
--- /dev/null
+++ b/contrib/gcc/config/arm/bpabi.S
@@ -0,0 +1,95 @@
+/* Miscellaneous BPABI functions.
+
+ Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+ Contributed by CodeSourcery, LLC.
+
+ 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, 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.)
+
+ 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 program; see the file COPYING. If not, write to
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#ifdef __ARMEB__
+#define xxh r0
+#define xxl r1
+#define yyh r2
+#define yyl r3
+#else
+#define xxh r1
+#define xxl r0
+#define yyh r3
+#define yyl r2
+#endif
+
+#ifdef L_aeabi_lcmp
+
+ARM_FUNC_START aeabi_lcmp
+ subs ip, xxl, yyl
+ sbcs ip, xxh, yyh
+ subeqs ip, xxl, yyl
+ mov r0, ip
+ RET
+ FUNC_END aeabi_lcmp
+
+#endif /* L_aeabi_lcmp */
+
+#ifdef L_aeabi_ulcmp
+
+ARM_FUNC_START aeabi_ulcmp
+ cmp xxh, yyh
+ movlo r0, #-1
+ movhi r0, #1
+ RETc(ne)
+ cmp xxl, yyl
+ movlo r0, #-1
+ movhi r0, #1
+ moveq r0, #0
+ RET
+ FUNC_END aeabi_ulcmp
+
+#endif /* L_aeabi_ulcmp */
+
+#ifdef L_aeabi_ldivmod
+
+ARM_FUNC_START aeabi_ldivmod
+ sub sp, sp, #8
+ stmfd sp!, {sp, lr}
+ bl SYM(__gnu_ldivmod_helper) __PLT__
+ ldr lr, [sp, #4]
+ add sp, sp, #8
+ ldmfd sp!, {r2, r3}
+ RET
+
+#endif /* L_aeabi_ldivmod */
+
+#ifdef L_aeabi_uldivmod
+
+ARM_FUNC_START aeabi_uldivmod
+ sub sp, sp, #8
+ stmfd sp!, {sp, lr}
+ bl SYM(__gnu_uldivmod_helper) __PLT__
+ ldr lr, [sp, #4]
+ add sp, sp, #8
+ ldmfd sp!, {r2, r3}
+ RET
+
+#endif /* L_aeabi_divmod */
+
diff --git a/contrib/gcc/config/arm/bpabi.c b/contrib/gcc/config/arm/bpabi.c
new file mode 100644
index 0000000..69f6e4e
--- /dev/null
+++ b/contrib/gcc/config/arm/bpabi.c
@@ -0,0 +1,61 @@
+/* Miscellaneous BPABI functions.
+
+ Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+ Contributed by CodeSourcery, LLC.
+
+ 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, 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.)
+
+ 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 program; see the file COPYING. If not, write to
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+extern long long __divdi3 (long long, long long);
+extern unsigned long long __udivdi3 (unsigned long long,
+ unsigned long long);
+extern long long __gnu_ldivmod_helper (long long, long long, long long *);
+extern unsigned long long __gnu_uldivmod_helper (unsigned long long,
+ unsigned long long,
+ unsigned long long *);
+
+
+long long
+__gnu_ldivmod_helper (long long a,
+ long long b,
+ long long *remainder)
+{
+ long long quotient;
+
+ quotient = __divdi3 (a, b);
+ *remainder = a - b * quotient;
+ return quotient;
+}
+
+unsigned long long
+__gnu_uldivmod_helper (unsigned long long a,
+ unsigned long long b,
+ unsigned long long *remainder)
+{
+ unsigned long long quotient;
+
+ quotient = __udivdi3 (a, b);
+ *remainder = a - b * quotient;
+ return quotient;
+}
diff --git a/contrib/gcc/config/arm/bpabi.h b/contrib/gcc/config/arm/bpabi.h
new file mode 100644
index 0000000..4c73088
--- /dev/null
+++ b/contrib/gcc/config/arm/bpabi.h
@@ -0,0 +1,118 @@
+/* Configuration file for ARM BPABI targets.
+ Copyright (C) 2004, 2005
+ Free Software Foundation, Inc.
+ Contributed by CodeSourcery, LLC
+
+ 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.
+
+ 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. */
+
+/* Use the AAPCS ABI by default. */
+#define ARM_DEFAULT_ABI ARM_ABI_AAPCS
+
+/* Assume that AAPCS ABIs should adhere to the full BPABI. */
+#define TARGET_BPABI (TARGET_AAPCS_BASED)
+
+/* BPABI targets use EABI frame unwinding tables. */
+#define TARGET_UNWIND_INFO 1
+
+/* Section 4.1 of the AAPCS requires the use of VFP format. */
+#undef FPUTYPE_DEFAULT
+#define FPUTYPE_DEFAULT FPUTYPE_VFP
+
+/* EABI targets should enable interworking by default. */
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT MASK_INTERWORK
+
+/* The ARM BPABI functions return a boolean; they use no special
+ calling convention. */
+#define FLOAT_LIB_COMPARE_RETURNS_BOOL(MODE, COMPARISON) TARGET_BPABI
+
+/* The BPABI integer comparison routines return { -1, 0, 1 }. */
+#define TARGET_LIB_INT_CMP_BIASED !TARGET_BPABI
+
+/* Tell the assembler to build BPABI binaries. */
+#undef SUBTARGET_EXTRA_ASM_SPEC
+#define SUBTARGET_EXTRA_ASM_SPEC "%{mabi=apcs-gnu|mabi=atpcs:-meabi=gnu;:-meabi=4}"
+
+/* The generic link spec in elf.h does not support shared libraries. */
+#undef LINK_SPEC
+#define LINK_SPEC "%{mbig-endian:-EB} %{mlittle-endian:-EL} " \
+ "%{static:-Bstatic} %{shared:-shared} %{symbolic:-Bsymbolic} " \
+ "-X"
+
+#if defined (__thumb__)
+#define RENAME_LIBRARY_SET ".thumb_set"
+#else
+#define RENAME_LIBRARY_SET ".set"
+#endif
+
+/* Make __aeabi_AEABI_NAME an alias for __GCC_NAME. */
+#define RENAME_LIBRARY(GCC_NAME, AEABI_NAME) \
+ __asm__ (".globl\t__aeabi_" #AEABI_NAME "\n" \
+ RENAME_LIBRARY_SET "\t__aeabi_" #AEABI_NAME \
+ ", __" #GCC_NAME "\n");
+
+/* Give some libgcc functions an additional __aeabi name. */
+#ifdef L_muldi3
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (muldi3, lmul)
+#endif
+#ifdef L_muldi3
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (muldi3, lmul)
+#endif
+#ifdef L_fixdfdi
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixdfdi, d2lz)
+#endif
+#ifdef L_fixunsdfdi
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixunsdfdi, d2ulz)
+#endif
+#ifdef L_fixsfdi
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixsfdi, f2lz)
+#endif
+#ifdef L_fixunssfdi
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixunssfdi, f2ulz)
+#endif
+#ifdef L_floatdidf
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatdidf, l2d)
+#endif
+#ifdef L_floatdisf
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatdisf, l2f)
+#endif
+
+/* The BPABI requires that we always use an out-of-line implementation
+ of RTTI comparison, even if the target supports weak symbols,
+ because the same object file might be used on a target that does
+ not support merging symbols across DLL boundaries. This macro is
+ broken out separately so that it can be used within
+ TARGET_OS_CPP_BUILTINS in configuration files for systems based on
+ the BPABI. */
+#define TARGET_BPABI_CPP_BUILTINS() \
+ do \
+ { \
+ builtin_define ("__GXX_MERGED_TYPEINFO_NAMES=0"); \
+ } \
+ while (false)
+
+#undef TARGET_OS_CPP_BUILTINS
+#define TARGET_OS_CPP_BUILTINS() \
+ TARGET_BPABI_CPP_BUILTINS()
+
+/* The BPABI specifies the use of .{init,fini}_array. Therefore, we
+ do not want GCC to put anything into the .{init,fini} sections. */
+#undef INIT_SECTION_ASM_OP
+#undef FINI_SECTION_ASM_OP
+#define INIT_ARRAY_SECTION_ASM_OP ARM_EABI_CTORS_SECTION_OP
+#define FINI_ARRAY_SECTION_ASM_OP ARM_EABI_DTORS_SECTION_OP
diff --git a/contrib/gcc/config/arm/cirrus.md b/contrib/gcc/config/arm/cirrus.md
index 0da8469..b857cbb 100644
--- a/contrib/gcc/config/arm/cirrus.md
+++ b/contrib/gcc/config/arm/cirrus.md
@@ -1,5 +1,5 @@
;; Cirrus EP9312 "Maverick" ARM floating point co-processor description.
-;; Copyright (C) 2003 Free Software Foundation, Inc.
+;; Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
;; Contributed by Red Hat.
;; Written by Aldy Hernandez (aldyh@redhat.com)
@@ -17,8 +17,8 @@
;; 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, 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
; Cirrus types for invalid insn combinations
@@ -34,7 +34,7 @@
[(set (match_operand:DI 0 "cirrus_fp_register" "=v")
(plus:DI (match_operand:DI 1 "cirrus_fp_register" "v")
(match_operand:DI 2 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfadd64%?\\t%V0, %V1, %V2"
[(set_attr "type" "mav_farith")
(set_attr "cirrus" "normal")]
@@ -44,7 +44,7 @@
[(set (match_operand:SI 0 "cirrus_fp_register" "=v")
(plus:SI (match_operand:SI 1 "cirrus_fp_register" "v")
(match_operand:SI 2 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS && 0"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK && 0"
"cfadd32%?\\t%V0, %V1, %V2"
[(set_attr "type" "mav_farith")
(set_attr "cirrus" "normal")]
@@ -54,7 +54,7 @@
[(set (match_operand:SF 0 "cirrus_fp_register" "=v")
(plus:SF (match_operand:SF 1 "cirrus_fp_register" "v")
(match_operand:SF 2 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfadds%?\\t%V0, %V1, %V2"
[(set_attr "type" "mav_farith")
(set_attr "cirrus" "normal")]
@@ -64,7 +64,7 @@
[(set (match_operand:DF 0 "cirrus_fp_register" "=v")
(plus:DF (match_operand:DF 1 "cirrus_fp_register" "v")
(match_operand:DF 2 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfaddd%?\\t%V0, %V1, %V2"
[(set_attr "type" "mav_farith")
(set_attr "cirrus" "normal")]
@@ -74,7 +74,7 @@
[(set (match_operand:DI 0 "cirrus_fp_register" "=v")
(minus:DI (match_operand:DI 1 "cirrus_fp_register" "v")
(match_operand:DI 2 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfsub64%?\\t%V0, %V1, %V2"
[(set_attr "type" "mav_farith")
(set_attr "cirrus" "normal")]
@@ -84,7 +84,7 @@
[(set (match_operand:SI 0 "cirrus_fp_register" "=v")
(minus:SI (match_operand:SI 1 "cirrus_fp_register" "v")
(match_operand:SI 2 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS && 0"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK && 0"
"cfsub32%?\\t%V0, %V1, %V2"
[(set_attr "type" "mav_farith")
(set_attr "cirrus" "normal")]
@@ -94,7 +94,7 @@
[(set (match_operand:SF 0 "cirrus_fp_register" "=v")
(minus:SF (match_operand:SF 1 "cirrus_fp_register" "v")
(match_operand:SF 2 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfsubs%?\\t%V0, %V1, %V2"
[(set_attr "type" "mav_farith")
(set_attr "cirrus" "normal")]
@@ -104,7 +104,7 @@
[(set (match_operand:DF 0 "cirrus_fp_register" "=v")
(minus:DF (match_operand:DF 1 "cirrus_fp_register" "v")
(match_operand:DF 2 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfsubd%?\\t%V0, %V1, %V2"
[(set_attr "type" "mav_farith")
(set_attr "cirrus" "normal")]
@@ -114,7 +114,7 @@
[(set (match_operand:SI 0 "cirrus_fp_register" "=v")
(mult:SI (match_operand:SI 2 "cirrus_fp_register" "v")
(match_operand:SI 1 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS && 0"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK && 0"
"cfmul32%?\\t%V0, %V1, %V2"
[(set_attr "type" "mav_farith")
(set_attr "cirrus" "normal")]
@@ -124,7 +124,7 @@
[(set (match_operand:DI 0 "cirrus_fp_register" "=v")
(mult:DI (match_operand:DI 2 "cirrus_fp_register" "v")
(match_operand:DI 1 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfmul64%?\\t%V0, %V1, %V2"
[(set_attr "type" "mav_dmult")
(set_attr "cirrus" "normal")]
@@ -136,7 +136,7 @@
(mult:SI (match_operand:SI 1 "cirrus_fp_register" "v")
(match_operand:SI 2 "cirrus_fp_register" "v"))
(match_operand:SI 3 "cirrus_fp_register" "0")))]
- "TARGET_ARM && TARGET_CIRRUS && 0"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK && 0"
"cfmac32%?\\t%V0, %V1, %V2"
[(set_attr "type" "mav_farith")
(set_attr "cirrus" "normal")]
@@ -149,7 +149,7 @@
(match_operand:SI 1 "cirrus_fp_register" "0")
(mult:SI (match_operand:SI 2 "cirrus_fp_register" "v")
(match_operand:SI 3 "cirrus_fp_register" "v"))))]
- "0 && TARGET_ARM && TARGET_CIRRUS"
+ "0 && TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfmsc32%?\\t%V0, %V2, %V3"
[(set_attr "type" "mav_farith")
(set_attr "cirrus" "normal")]
@@ -159,7 +159,7 @@
[(set (match_operand:SF 0 "cirrus_fp_register" "=v")
(mult:SF (match_operand:SF 1 "cirrus_fp_register" "v")
(match_operand:SF 2 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfmuls%?\\t%V0, %V1, %V2"
[(set_attr "type" "mav_farith")
(set_attr "cirrus" "normal")]
@@ -169,7 +169,7 @@
[(set (match_operand:DF 0 "cirrus_fp_register" "=v")
(mult:DF (match_operand:DF 1 "cirrus_fp_register" "v")
(match_operand:DF 2 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfmuld%?\\t%V0, %V1, %V2"
[(set_attr "type" "mav_dmult")
(set_attr "cirrus" "normal")]
@@ -179,7 +179,7 @@
[(set (match_operand:SI 0 "cirrus_fp_register" "=v")
(ashift:SI (match_operand:SI 1 "cirrus_fp_register" "v")
(match_operand:SI 2 "cirrus_shift_const" "")))]
- "TARGET_ARM && TARGET_CIRRUS && 0"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK && 0"
"cfsh32%?\\t%V0, %V1, #%s2"
[(set_attr "cirrus" "normal")]
)
@@ -188,7 +188,7 @@
[(set (match_operand:SI 0 "cirrus_fp_register" "=v")
(ashiftrt:SI (match_operand:SI 1 "cirrus_fp_register" "v")
(match_operand:SI 2 "cirrus_shift_const" "")))]
- "TARGET_ARM && TARGET_CIRRUS && 0"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK && 0"
"cfsh32%?\\t%V0, %V1, #-%s2"
[(set_attr "cirrus" "normal")]
)
@@ -197,7 +197,7 @@
[(set (match_operand:SI 0 "cirrus_fp_register" "=v")
(ashift:SI (match_operand:SI 1 "cirrus_fp_register" "v")
(match_operand:SI 2 "register_operand" "r")))]
- "TARGET_ARM && TARGET_CIRRUS && 0"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK && 0"
"cfrshl32%?\\t%V1, %V0, %s2"
[(set_attr "cirrus" "normal")]
)
@@ -206,7 +206,7 @@
[(set (match_operand:DI 0 "cirrus_fp_register" "=v")
(ashift:DI (match_operand:DI 1 "cirrus_fp_register" "v")
(match_operand:SI 2 "register_operand" "r")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfrshl64%?\\t%V1, %V0, %s2"
[(set_attr "cirrus" "normal")]
)
@@ -215,7 +215,7 @@
[(set (match_operand:DI 0 "cirrus_fp_register" "=v")
(ashift:DI (match_operand:DI 1 "cirrus_fp_register" "v")
(match_operand:SI 2 "cirrus_shift_const" "")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfsh64%?\\t%V0, %V1, #%s2"
[(set_attr "cirrus" "normal")]
)
@@ -224,7 +224,7 @@
[(set (match_operand:DI 0 "cirrus_fp_register" "=v")
(ashiftrt:DI (match_operand:DI 1 "cirrus_fp_register" "v")
(match_operand:SI 2 "cirrus_shift_const" "")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfsh64%?\\t%V0, %V1, #-%s2"
[(set_attr "cirrus" "normal")]
)
@@ -232,7 +232,7 @@
(define_insn "*cirrus_absdi2"
[(set (match_operand:DI 0 "cirrus_fp_register" "=v")
(abs:DI (match_operand:DI 1 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfabs64%?\\t%V0, %V1"
[(set_attr "cirrus" "normal")]
)
@@ -242,7 +242,7 @@
[(set (match_operand:DI 0 "cirrus_fp_register" "=v")
(neg:DI (match_operand:DI 1 "cirrus_fp_register" "v")))
(clobber (reg:CC CC_REGNUM))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfneg64%?\\t%V0, %V1"
[(set_attr "cirrus" "normal")]
)
@@ -250,7 +250,7 @@
(define_insn "*cirrus_negsi2"
[(set (match_operand:SI 0 "cirrus_fp_register" "=v")
(neg:SI (match_operand:SI 1 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS && 0"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK && 0"
"cfneg32%?\\t%V0, %V1"
[(set_attr "cirrus" "normal")]
)
@@ -258,7 +258,7 @@
(define_insn "*cirrus_negsf2"
[(set (match_operand:SF 0 "cirrus_fp_register" "=v")
(neg:SF (match_operand:SF 1 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfnegs%?\\t%V0, %V1"
[(set_attr "cirrus" "normal")]
)
@@ -266,7 +266,7 @@
(define_insn "*cirrus_negdf2"
[(set (match_operand:DF 0 "cirrus_fp_register" "=v")
(neg:DF (match_operand:DF 1 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfnegd%?\\t%V0, %V1"
[(set_attr "cirrus" "normal")]
)
@@ -276,7 +276,7 @@
[(set (match_operand:SI 0 "cirrus_fp_register" "=v")
(abs:SI (match_operand:SI 1 "cirrus_fp_register" "v")))
(clobber (reg:CC CC_REGNUM))]
- "TARGET_ARM && TARGET_CIRRUS && 0"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK && 0"
"cfabs32%?\\t%V0, %V1"
[(set_attr "cirrus" "normal")]
)
@@ -284,7 +284,7 @@
(define_insn "*cirrus_abssf2"
[(set (match_operand:SF 0 "cirrus_fp_register" "=v")
(abs:SF (match_operand:SF 1 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfabss%?\\t%V0, %V1"
[(set_attr "cirrus" "normal")]
)
@@ -292,7 +292,7 @@
(define_insn "*cirrus_absdf2"
[(set (match_operand:DF 0 "cirrus_fp_register" "=v")
(abs:DF (match_operand:DF 1 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfabsd%?\\t%V0, %V1"
[(set_attr "cirrus" "normal")]
)
@@ -302,7 +302,7 @@
[(set (match_operand:SF 0 "cirrus_fp_register" "=v")
(float:SF (match_operand:SI 1 "s_register_operand" "r")))
(clobber (match_scratch:DF 2 "=v"))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfmv64lr%?\\t%Z2, %1\;cfcvt32s%?\\t%V0, %Y2"
[(set_attr "length" "8")
(set_attr "cirrus" "move")]
@@ -312,7 +312,7 @@
[(set (match_operand:DF 0 "cirrus_fp_register" "=v")
(float:DF (match_operand:SI 1 "s_register_operand" "r")))
(clobber (match_scratch:DF 2 "=v"))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfmv64lr%?\\t%Z2, %1\;cfcvt32d%?\\t%V0, %Y2"
[(set_attr "length" "8")
(set_attr "cirrus" "move")]
@@ -321,14 +321,14 @@
(define_insn "floatdisf2"
[(set (match_operand:SF 0 "cirrus_fp_register" "=v")
(float:SF (match_operand:DI 1 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfcvt64s%?\\t%V0, %V1"
[(set_attr "cirrus" "normal")])
(define_insn "floatdidf2"
[(set (match_operand:DF 0 "cirrus_fp_register" "=v")
(float:DF (match_operand:DI 1 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfcvt64d%?\\t%V0, %V1"
[(set_attr "cirrus" "normal")])
@@ -336,7 +336,7 @@
[(set (match_operand:SI 0 "s_register_operand" "=r")
(fix:SI (fix:SF (match_operand:SF 1 "cirrus_fp_register" "v"))))
(clobber (match_scratch:DF 2 "=v"))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cftruncs32%?\\t%Y2, %V1\;cfmvr64l%?\\t%0, %Z2"
[(set_attr "length" "8")
(set_attr "cirrus" "normal")]
@@ -346,7 +346,7 @@
[(set (match_operand:SI 0 "s_register_operand" "=r")
(fix:SI (fix:DF (match_operand:DF 1 "cirrus_fp_register" "v"))))
(clobber (match_scratch:DF 2 "=v"))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cftruncd32%?\\t%Y2, %V1\;cfmvr64l%?\\t%0, %Z2"
[(set_attr "length" "8")]
)
@@ -355,7 +355,7 @@
[(set (match_operand:SF 0 "cirrus_fp_register" "=v")
(float_truncate:SF
(match_operand:DF 1 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfcvtds%?\\t%V0, %V1"
[(set_attr "cirrus" "normal")]
)
@@ -363,23 +363,24 @@
(define_insn "*cirrus_extendsfdf2"
[(set (match_operand:DF 0 "cirrus_fp_register" "=v")
(float_extend:DF (match_operand:SF 1 "cirrus_fp_register" "v")))]
- "TARGET_ARM && TARGET_CIRRUS"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"cfcvtsd%?\\t%V0, %V1"
[(set_attr "cirrus" "normal")]
)
(define_insn "*cirrus_arm_movdi"
[(set (match_operand:DI 0 "nonimmediate_di_operand" "=r,r,o<>,v,r,v,m,v")
- (match_operand:DI 1 "di_operand" "rIK,mi,r,r,v,m,v,v"))]
- "TARGET_ARM && TARGET_CIRRUS"
+ (match_operand:DI 1 "di_operand" "rIK,mi,r,r,v,mi,v,v"))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
"*
{
switch (which_alternative)
{
case 0:
+ return \"#\";
case 1:
case 2:
- return (output_move_double (operands));
+ return output_move_double (operands);
case 3: return \"cfmv64lr%?\\t%V0, %Q1\;cfmv64hr%?\\t%V0, %R1\";
case 4: return \"cfmvr64l%?\\t%Q0, %V1\;cfmvr64h%?\\t%R0, %V1\";
@@ -390,13 +391,13 @@
/* Shifting by 0 will just copy %1 into %0. */
case 7: return \"cfsh64%?\\t%V0, %V1, #0\";
- default: abort ();
+ default: gcc_unreachable ();
}
}"
[(set_attr "length" " 8, 8, 8, 8, 8, 4, 4, 4")
- (set_attr "type" " *,load,store2, *, *, load,store2, *")
- (set_attr "pool_range" " *,1020, *, *, *, *, *, *")
- (set_attr "neg_pool_range" " *,1012, *, *, *, *, *, *")
+ (set_attr "type" " *,load2,store2, *, *, load2,store2, *")
+ (set_attr "pool_range" " *,1020, *, *, *, 1020, *, *")
+ (set_attr "neg_pool_range" " *,1012, *, *, *, 1008, *, *")
(set_attr "cirrus" "not, not, not,move,normal,double,double,normal")]
)
@@ -406,7 +407,7 @@
(define_insn "*cirrus_arm_movsi_insn"
[(set (match_operand:SI 0 "general_operand" "=r,r,r,m,*v,r,*v,T,*v")
(match_operand:SI 1 "general_operand" "rI,K,mi,r,r,*v,T,*v,*v"))]
- "TARGET_ARM && TARGET_CIRRUS && 0
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK && 0
&& (register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode))"
"@
@@ -419,7 +420,7 @@
cfldr32%?\\t%V0, %1
cfstr32%?\\t%V1, %0
cfsh32%?\\t%V0, %V1, #0"
- [(set_attr "type" "*, *, load,store1, *, *, load,store1, *")
+ [(set_attr "type" "*, *, load1,store1, *, *, load1,store1, *")
(set_attr "pool_range" "*, *, 4096, *, *, *, 1024, *, *")
(set_attr "neg_pool_range" "*, *, 4084, *, *, *, 1012, *, *")
(set_attr "cirrus" "not,not, not, not,move,normal,normal,normal,normal")]
@@ -427,8 +428,8 @@
(define_insn "*cirrus_movsf_hard_insn"
[(set (match_operand:SF 0 "nonimmediate_operand" "=v,v,v,r,m,r,r,m")
- (match_operand:SF 1 "general_operand" "v,m,r,v,v,r,mE,r"))]
- "TARGET_ARM && TARGET_CIRRUS
+ (match_operand:SF 1 "general_operand" "v,mE,r,v,v,r,mE,r"))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK
&& (GET_CODE (operands[0]) != MEM
|| register_operand (operands[1], SFmode))"
"@
@@ -441,17 +442,17 @@
ldr%?\\t%0, %1\\t%@ float
str%?\\t%1, %0\\t%@ float"
[(set_attr "length" " *, *, *, *, *, 4, 4, 4")
- (set_attr "type" " *, load, *, *,store1, *,load,store1")
- (set_attr "pool_range" " *, *, *, *, *, *,4096, *")
- (set_attr "neg_pool_range" " *, *, *, *, *, *,4084, *")
+ (set_attr "type" " *, load1, *, *,store1, *,load1,store1")
+ (set_attr "pool_range" " *, 1020, *, *, *, *,4096, *")
+ (set_attr "neg_pool_range" " *, 1008, *, *, *, *,4084, *")
(set_attr "cirrus" "normal,normal,move,normal,normal,not, not, not")]
)
(define_insn "*cirrus_movdf_hard_insn"
[(set (match_operand:DF 0 "nonimmediate_operand" "=r,Q,r,m,r,v,v,v,r,m")
- (match_operand:DF 1 "general_operand" "Q,r,r,r,mF,v,m,r,v,v"))]
+ (match_operand:DF 1 "general_operand" "Q,r,r,r,mF,v,mF,r,v,v"))]
"TARGET_ARM
- && TARGET_CIRRUS
+ && TARGET_HARD_FLOAT && TARGET_MAVERICK
&& (GET_CODE (operands[0]) != MEM
|| register_operand (operands[1], DFmode))"
"*
@@ -460,19 +461,20 @@
{
case 0: return \"ldm%?ia\\t%m1, %M0\\t%@ double\";
case 1: return \"stm%?ia\\t%m0, %M1\\t%@ double\";
- case 2: case 3: case 4: return output_move_double (operands);
+ case 2: return \"#\";
+ case 3: case 4: return output_move_double (operands);
case 5: return \"cfcpyd%?\\t%V0, %V1\";
case 6: return \"cfldrd%?\\t%V0, %1\";
case 7: return \"cfmvdlr\\t%V0, %Q1\;cfmvdhr%?\\t%V0, %R1\";
case 8: return \"cfmvrdl%?\\t%Q0, %V1\;cfmvrdh%?\\t%R0, %V1\";
case 9: return \"cfstrd%?\\t%V1, %0\";
- default: abort ();
+ default: gcc_unreachable ();
}
}"
- [(set_attr "type" "load,store2, *,store2,load, *, load, *, *,store2")
+ [(set_attr "type" "load1,store2, *,store2,load1, *, load1, *, *,store2")
(set_attr "length" " 4, 4, 8, 8, 8, 4, 4, 8, 8, 4")
- (set_attr "pool_range" " *, *, *, *, 252, *, *, *, *, *")
- (set_attr "neg_pool_range" " *, *, *, *, 244, *, *, *, *, *")
+ (set_attr "pool_range" " *, *, *, *, 252, *, 1020, *, *, *")
+ (set_attr "neg_pool_range" " *, *, *, *, 244, *, 1008, *, *, *")
(set_attr "cirrus" " not, not,not, not, not,normal,double,move,normal,double")]
)
diff --git a/contrib/gcc/config/arm/coff.h b/contrib/gcc/config/arm/coff.h
index d6a6651..f4ad416 100644
--- a/contrib/gcc/config/arm/coff.h
+++ b/contrib/gcc/config/arm/coff.h
@@ -1,6 +1,6 @@
/* Definitions of target machine for GNU compiler.
For ARM with COFF object format.
- Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003
+ Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005
Free Software Foundation, Inc.
Contributed by Doug Evans (devans@cygnus.com).
@@ -18,8 +18,8 @@
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, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* Note - it is important that this definition matches the one in tcoff.h. */
#undef USER_LABEL_PREFIX
@@ -30,12 +30,15 @@
#undef TARGET_VERSION
#define TARGET_VERSION fputs (" (ARM/coff)", stderr)
+#undef TARGET_DEFAULT_FLOAT_ABI
+#define TARGET_DEFAULT_FLOAT_ABI ARM_FLOAT_ABI_SOFT
+
#undef TARGET_DEFAULT
-#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME | ARM_FLAG_MMU_TRAPS)
+#define TARGET_DEFAULT (MASK_APCS_FRAME)
#ifndef MULTILIB_DEFAULTS
#define MULTILIB_DEFAULTS \
- { "marm", "mlittle-endian", "msoft-float", "mapcs-32", "mno-thumb-interwork" }
+ { "marm", "mlittle-endian", "msoft-float", "mno-thumb-interwork" }
#endif
/* This is COFF, but prefer stabs. */
diff --git a/contrib/gcc/config/arm/constraints.md b/contrib/gcc/config/arm/constraints.md
new file mode 100644
index 0000000..790b7de
--- /dev/null
+++ b/contrib/gcc/config/arm/constraints.md
@@ -0,0 +1,186 @@
+;; Constraint definitions for ARM and Thumb
+;; Copyright (C) 2006 Free Software Foundation, Inc.
+;; Contributed by ARM Ltd.
+
+;; 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.
+
+;; 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.
+
+;; The following register constraints have been used:
+;; - in ARM state: f, v, w, y, z
+;; - in Thumb state: h, k, b
+;; - in both states: l, c
+;; In ARM state, 'l' is an alias for 'r'
+
+;; The following normal constraints have been used:
+;; in ARM state: G, H, I, J, K, L, M
+;; in Thumb state: I, J, K, L, M, N, O
+
+;; The following multi-letter normal constraints have been used:
+;; in ARM state: Da, Db, Dc
+
+;; The following memory constraints have been used:
+;; in ARM state: Q, Uq, Uv, Uy
+
+
+(define_register_constraint "f" "TARGET_ARM ? FPA_REGS : NO_REGS"
+ "Legacy FPA registers @code{f0}-@code{f7}.")
+
+(define_register_constraint "v" "TARGET_ARM ? CIRRUS_REGS : NO_REGS"
+ "The Cirrus Maverick co-processor registers.")
+
+(define_register_constraint "w" "TARGET_ARM ? VFP_REGS : NO_REGS"
+ "The VFP registers @code{s0}-@code{s31}.")
+
+(define_register_constraint "y" "TARGET_REALLY_IWMMXT ? IWMMXT_REGS : NO_REGS"
+ "The Intel iWMMX co-processor registers.")
+
+(define_register_constraint "z"
+ "TARGET_REALLY_IWMMXT ? IWMMXT_GR_REGS : NO_REGS"
+ "The Intel iWMMX GR registers.")
+
+(define_register_constraint "l" "TARGET_THUMB ? LO_REGS : GENERAL_REGS"
+ "In Thumb state the core registers @code{r0}-@code{r7}.")
+
+(define_register_constraint "h" "TARGET_THUMB ? HI_REGS : NO_REGS"
+ "In Thumb state the core registers @code{r8}-@code{r15}.")
+
+(define_register_constraint "k" "TARGET_THUMB ? STACK_REG : NO_REGS"
+ "@internal
+ Thumb only. The stack register.")
+
+(define_register_constraint "b" "TARGET_THUMB ? BASE_REGS : NO_REGS"
+ "@internal
+ Thumb only. The union of the low registers and the stack register.")
+
+(define_register_constraint "c" "CC_REG"
+ "@internal The condition code register.")
+
+(define_constraint "I"
+ "In ARM state a constant that can be used as an immediate value in a Data
+ Processing instruction. In Thumb state a constant in the range 0-255."
+ (and (match_code "const_int")
+ (match_test "TARGET_ARM ? const_ok_for_arm (ival)
+ : ival >= 0 && ival <= 255")))
+
+(define_constraint "J"
+ "In ARM state a constant in the range @minus{}4095-4095. In Thumb state
+ a constant in the range @minus{}255-@minus{}1."
+ (and (match_code "const_int")
+ (match_test "TARGET_ARM ? (ival >= -4095 && ival <= 4095)
+ : (ival >= -255 && ival <= -1)")))
+
+(define_constraint "K"
+ "In ARM state a constant that satisfies the @code{I} constraint if inverted.
+ In Thumb state a constant that satisfies the @code{I} constraint multiplied
+ by any power of 2."
+ (and (match_code "const_int")
+ (match_test "TARGET_ARM ? const_ok_for_arm (~ival)
+ : thumb_shiftable_const (ival)")))
+
+(define_constraint "L"
+ "In ARM state a constant that satisfies the @code{I} constraint if negated.
+ In Thumb state a constant in the range @minus{}7-7."
+ (and (match_code "const_int")
+ (match_test "TARGET_ARM ? const_ok_for_arm (-ival)
+ : (ival >= -7 && ival <= 7)")))
+
+;; The ARM state version is internal...
+;; @internal In ARM state a constant in the range 0-32 or any power of 2.
+(define_constraint "M"
+ "In Thumb state a constant that is a multiple of 4 in the range 0-1020."
+ (and (match_code "const_int")
+ (match_test "TARGET_ARM ? ((ival >= 0 && ival <= 32)
+ || ((ival & (ival - 1)) == 0))
+ : ((ival >= 0 && ival <= 1020) && ((ival & 3) == 0))")))
+
+(define_constraint "N"
+ "In Thumb state a constant in the range 0-31."
+ (and (match_code "const_int")
+ (match_test "TARGET_THUMB && ival >= 0 && ival <= 31")))
+
+(define_constraint "O"
+ "In Thumb state a constant that is a multiple of 4 in the range
+ @minus{}508-508."
+ (and (match_code "const_int")
+ (match_test "TARGET_THUMB && ival >= -508 && ival <= 508
+ && ((ival & 3) == 0)")))
+
+(define_constraint "G"
+ "In ARM state a valid FPA immediate constant."
+ (and (match_code "const_double")
+ (match_test "TARGET_ARM && arm_const_double_rtx (op)")))
+
+(define_constraint "H"
+ "In ARM state a valid FPA immediate constant when negated."
+ (and (match_code "const_double")
+ (match_test "TARGET_ARM && neg_const_double_rtx_ok_for_fpa (op)")))
+
+(define_constraint "Da"
+ "@internal
+ In ARM state a const_int, const_double or const_vector that can
+ be generated with two Data Processing insns."
+ (and (match_code "const_double,const_int,const_vector")
+ (match_test "TARGET_ARM && arm_const_double_inline_cost (op) == 2")))
+
+(define_constraint "Db"
+ "@internal
+ In ARM state a const_int, const_double or const_vector that can
+ be generated with three Data Processing insns."
+ (and (match_code "const_double,const_int,const_vector")
+ (match_test "TARGET_ARM && arm_const_double_inline_cost (op) == 3")))
+
+(define_constraint "Dc"
+ "@internal
+ In ARM state a const_int, const_double or const_vector that can
+ be generated with four Data Processing insns. This pattern is disabled
+ if optimizing for space or when we have load-delay slots to fill."
+ (and (match_code "const_double,const_int,const_vector")
+ (match_test "TARGET_ARM && arm_const_double_inline_cost (op) == 4
+ && !(optimize_size || arm_ld_sched)")))
+
+(define_memory_constraint "Uv"
+ "@internal
+ In ARM state a valid VFP load/store address."
+ (and (match_code "mem")
+ (match_test "TARGET_ARM && arm_coproc_mem_operand (op, FALSE)")))
+
+(define_memory_constraint "Uy"
+ "@internal
+ In ARM state a valid iWMMX load/store address."
+ (and (match_code "mem")
+ (match_test "TARGET_ARM && arm_coproc_mem_operand (op, TRUE)")))
+
+(define_memory_constraint "Uq"
+ "@internal
+ In ARM state an address valid in ldrsb instructions."
+ (and (match_code "mem")
+ (match_test "TARGET_ARM
+ && arm_legitimate_address_p (GET_MODE (op), XEXP (op, 0),
+ SIGN_EXTEND, 0)")))
+
+(define_memory_constraint "Q"
+ "@internal
+ In ARM state an address that is a single base register."
+ (and (match_code "mem")
+ (match_test "REG_P (XEXP (op, 0))")))
+
+;; We used to have constraint letters for S and R in ARM state, but
+;; all uses of these now appear to have been removed.
+
+;; Additionally, we used to have a Q constraint in Thumb state, but
+;; this wasn't really a valid memory constraint. Again, all uses of
+;; this now seem to have been removed.
diff --git a/contrib/gcc/config/arm/crti.asm b/contrib/gcc/config/arm/crti.asm
index ac58e44..166a3ce 100644
--- a/contrib/gcc/config/arm/crti.asm
+++ b/contrib/gcc/config/arm/crti.asm
@@ -21,8 +21,8 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not, write to
-# the Free Software Foundation, 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
+# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
#
# As a special exception, if you link this library with files
# compiled with GCC to produce an executable, this does not cause
@@ -35,6 +35,12 @@
# .init sections. Users may put any desired instructions in those
# sections.
+#ifdef __ELF__
+#define TYPE(x) .type x,function
+#else
+#define TYPE(x)
+#endif
+
# Note - this macro is complemented by the FUNC_END macro
# in crtn.asm. If you change this macro you must also change
# that macro match.
@@ -42,12 +48,12 @@
#ifdef __thumb__
.thumb
- push {r4, r5, r6, r7, lr}
+ push {r3, r4, r5, r6, r7, lr}
#else
.arm
# Create a stack frame and save any call-preserved registers
mov ip, sp
- stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, lr, pc}
+ stmdb sp!, {r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, lr, pc}
sub fp, ip, #4
#endif
.endm
@@ -60,6 +66,7 @@
#ifdef __thumb__
.thumb_func
#endif
+ TYPE(_init)
_init:
FUNC_START
@@ -70,6 +77,7 @@ _init:
#ifdef __thumb__
.thumb_func
#endif
+ TYPE(_fini)
_fini:
FUNC_START
diff --git a/contrib/gcc/config/arm/crtn.asm b/contrib/gcc/config/arm/crtn.asm
index 9ad75e3..360afae 100644
--- a/contrib/gcc/config/arm/crtn.asm
+++ b/contrib/gcc/config/arm/crtn.asm
@@ -1,4 +1,4 @@
-# Copyright (C) 2001 Free Software Foundation, Inc.
+# Copyright (C) 2001, 2004 Free Software Foundation, Inc.
# Written By Nick Clifton
#
# This file is free software; you can redistribute it and/or modify it
@@ -21,8 +21,8 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not, write to
-# the Free Software Foundation, 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
+# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
#
# As a special exception, if you link this library with files
# compiled with GCC to produce an executable, this does not cause
@@ -43,28 +43,26 @@
# sequences here, it is just not worth it. Instead keep things
# simple. Restore all the save resgisters, including the link
# register and then perform the correct function return instruction.
+ # We also save/restore r3 to ensure stack alignment.
.macro FUNC_END
#ifdef __thumb__
.thumb
- pop {r4, r5, r6, r7}
+ pop {r3, r4, r5, r6, r7}
pop {r3}
mov lr, r3
#else
.arm
- ldmdb fp, {r4, r5, r6, r7, r8, r9, sl, fp, sp, lr}
+ sub sp, fp, #40
+ ldmfd sp, {r4, r5, r6, r7, r8, r9, sl, fp, sp, lr}
#endif
#if defined __THUMB_INTERWORK__ || defined __thumb__
bx lr
#else
-#ifdef __APCS_26__
- movs pc, lr
-#else
mov pc, lr
#endif
-#endif
.endm
diff --git a/contrib/gcc/config/arm/ecos-elf.h b/contrib/gcc/config/arm/ecos-elf.h
index d57fe8b..22eefe4 100644
--- a/contrib/gcc/config/arm/ecos-elf.h
+++ b/contrib/gcc/config/arm/ecos-elf.h
@@ -15,8 +15,8 @@
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* Run-time Target Specification. */
#undef TARGET_VERSION
diff --git a/contrib/gcc/config/arm/elf.h b/contrib/gcc/config/arm/elf.h
index cb38264..ae3d533 100644
--- a/contrib/gcc/config/arm/elf.h
+++ b/contrib/gcc/config/arm/elf.h
@@ -1,6 +1,6 @@
/* Definitions of target machine for GNU compiler.
For ARM with ELF obj format.
- Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001
+ Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2004, 2005
Free Software Foundation, Inc.
Contributed by Philip Blundell <philb@gnu.org> and
Catherine Moore <clm@cygnus.com>
@@ -19,8 +19,8 @@
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, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#ifndef OBJECT_FORMAT_ELF
#error elf.h included before elfos.h
@@ -46,7 +46,7 @@
#ifndef SUBTARGET_ASM_FLOAT_SPEC
#define SUBTARGET_ASM_FLOAT_SPEC "\
-%{mapcs-float:-mfloat} %{msoft-float:-mfpu=softfpa}"
+%{mapcs-float:-mfloat}"
#endif
#ifndef ASM_SPEC
@@ -58,6 +58,8 @@
%{mapcs-*:-mapcs-%*} \
%(subtarget_asm_float_spec) \
%{mthumb-interwork:-mthumb-interwork} \
+%{msoft-float:-mfloat-abi=soft} %{mhard-float:-mfloat-abi=hard} \
+%{mfloat-abi=*} %{mfpu=*} \
%(subtarget_extra_asm_spec)"
#endif
@@ -75,6 +77,7 @@
ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "function"); \
ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL)); \
ASM_OUTPUT_LABEL(FILE, NAME); \
+ ARM_OUTPUT_FN_UNWIND (FILE, TRUE); \
} \
while (0)
@@ -83,6 +86,7 @@
#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \
do \
{ \
+ ARM_OUTPUT_FN_UNWIND (FILE, FALSE); \
ARM_DECLARE_FUNCTION_SIZE (FILE, FNAME, DECL); \
if (!flag_inhibit_size_directive) \
ASM_OUTPUT_MEASURED_SIZE (FILE, FNAME); \
@@ -106,20 +110,21 @@
#endif
#ifndef TARGET_DEFAULT
-#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME | ARM_FLAG_MMU_TRAPS)
+#define TARGET_DEFAULT (MASK_APCS_FRAME)
#endif
#ifndef MULTILIB_DEFAULTS
#define MULTILIB_DEFAULTS \
- { "marm", "mlittle-endian", "msoft-float", "mapcs-32", "mno-thumb-interwork", "fno-leading-underscore" }
+ { "marm", "mlittle-endian", "msoft-float", "mno-thumb-interwork", "fno-leading-underscore" }
#endif
#define TARGET_ASM_FILE_START_APP_OFF true
#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
-#undef TARGET_ASM_NAMED_SECTION
-#define TARGET_ASM_NAMED_SECTION arm_elf_asm_named_section
-
+
+/* Output an element in the static constructor array. */
+#undef TARGET_ASM_CONSTRUCTOR
+#define TARGET_ASM_CONSTRUCTOR arm_elf_asm_constructor
/* For PIC code we need to explicitly specify (PLT) and (GOT) relocs. */
#define NEED_PLT_RELOC flag_pic
@@ -144,4 +149,5 @@
} \
while (0)
-#define SUPPORTS_INIT_PRIORITY 1
+/* The EABI doesn't provide a way of implementing init_priority. */
+#define SUPPORTS_INIT_PRIORITY (!TARGET_AAPCS_BASED)
diff --git a/contrib/gcc/config/arm/fpa.md b/contrib/gcc/config/arm/fpa.md
index 3b6efbf..b801f5a 100644
--- a/contrib/gcc/config/arm/fpa.md
+++ b/contrib/gcc/config/arm/fpa.md
@@ -1,6 +1,6 @@
;;- Machine description for FPA co-processor for ARM cpus.
;; Copyright 1991, 1993, 1994, 1995, 1996, 1996, 1997, 1998, 1999, 2000,
-;; 2001, 2002, 2003 Free Software Foundation, Inc.
+;; 2001, 2002, 2003, 2004, 2005 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).
@@ -19,8 +19,8 @@
;; 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, 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
;; FPA automaton.
(define_automaton "armfp")
@@ -100,8 +100,8 @@
(define_insn "*addsf3_fpa"
[(set (match_operand:SF 0 "s_register_operand" "=f,f")
(plus:SF (match_operand:SF 1 "s_register_operand" "%f,f")
- (match_operand:SF 2 "fpa_add_operand" "fG,H")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (match_operand:SF 2 "arm_float_add_operand" "fG,H")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"@
adf%?s\\t%0, %1, %2
suf%?s\\t%0, %1, #%N2"
@@ -112,8 +112,8 @@
(define_insn "*adddf3_fpa"
[(set (match_operand:DF 0 "s_register_operand" "=f,f")
(plus:DF (match_operand:DF 1 "s_register_operand" "%f,f")
- (match_operand:DF 2 "fpa_add_operand" "fG,H")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (match_operand:DF 2 "arm_float_add_operand" "fG,H")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"@
adf%?d\\t%0, %1, %2
suf%?d\\t%0, %1, #%N2"
@@ -125,8 +125,8 @@
[(set (match_operand:DF 0 "s_register_operand" "=f,f")
(plus:DF (float_extend:DF
(match_operand:SF 1 "s_register_operand" "f,f"))
- (match_operand:DF 2 "fpa_add_operand" "fG,H")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (match_operand:DF 2 "arm_float_add_operand" "fG,H")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"@
adf%?d\\t%0, %1, %2
suf%?d\\t%0, %1, #%N2"
@@ -139,7 +139,7 @@
(plus:DF (match_operand:DF 1 "s_register_operand" "f")
(float_extend:DF
(match_operand:SF 2 "s_register_operand" "f"))))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"adf%?d\\t%0, %1, %2"
[(set_attr "type" "farith")
(set_attr "predicable" "yes")]
@@ -151,7 +151,7 @@
(match_operand:SF 1 "s_register_operand" "f"))
(float_extend:DF
(match_operand:SF 2 "s_register_operand" "f"))))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"adf%?d\\t%0, %1, %2"
[(set_attr "type" "farith")
(set_attr "predicable" "yes")]
@@ -159,9 +159,9 @@
(define_insn "*subsf3_fpa"
[(set (match_operand:SF 0 "s_register_operand" "=f,f")
- (minus:SF (match_operand:SF 1 "fpa_rhs_operand" "f,G")
- (match_operand:SF 2 "fpa_rhs_operand" "fG,f")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (minus:SF (match_operand:SF 1 "arm_float_rhs_operand" "f,G")
+ (match_operand:SF 2 "arm_float_rhs_operand" "fG,f")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"@
suf%?s\\t%0, %1, %2
rsf%?s\\t%0, %2, %1"
@@ -170,9 +170,9 @@
(define_insn "*subdf3_fpa"
[(set (match_operand:DF 0 "s_register_operand" "=f,f")
- (minus:DF (match_operand:DF 1 "fpa_rhs_operand" "f,G")
- (match_operand:DF 2 "fpa_rhs_operand" "fG,f")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (minus:DF (match_operand:DF 1 "arm_float_rhs_operand" "f,G")
+ (match_operand:DF 2 "arm_float_rhs_operand" "fG,f")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"@
suf%?d\\t%0, %1, %2
rsf%?d\\t%0, %2, %1"
@@ -184,8 +184,8 @@
[(set (match_operand:DF 0 "s_register_operand" "=f")
(minus:DF (float_extend:DF
(match_operand:SF 1 "s_register_operand" "f"))
- (match_operand:DF 2 "fpa_rhs_operand" "fG")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (match_operand:DF 2 "arm_float_rhs_operand" "fG")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"suf%?d\\t%0, %1, %2"
[(set_attr "type" "farith")
(set_attr "predicable" "yes")]
@@ -193,10 +193,10 @@
(define_insn "*subdf_df_esfdf_fpa"
[(set (match_operand:DF 0 "s_register_operand" "=f,f")
- (minus:DF (match_operand:DF 1 "fpa_rhs_operand" "f,G")
+ (minus:DF (match_operand:DF 1 "arm_float_rhs_operand" "f,G")
(float_extend:DF
(match_operand:SF 2 "s_register_operand" "f,f"))))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"@
suf%?d\\t%0, %1, %2
rsf%?d\\t%0, %2, %1"
@@ -210,7 +210,7 @@
(match_operand:SF 1 "s_register_operand" "f"))
(float_extend:DF
(match_operand:SF 2 "s_register_operand" "f"))))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"suf%?d\\t%0, %1, %2"
[(set_attr "type" "farith")
(set_attr "predicable" "yes")]
@@ -219,8 +219,8 @@
(define_insn "*mulsf3_fpa"
[(set (match_operand:SF 0 "s_register_operand" "=f")
(mult:SF (match_operand:SF 1 "s_register_operand" "f")
- (match_operand:SF 2 "fpa_rhs_operand" "fG")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (match_operand:SF 2 "arm_float_rhs_operand" "fG")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"fml%?s\\t%0, %1, %2"
[(set_attr "type" "ffmul")
(set_attr "predicable" "yes")]
@@ -229,8 +229,8 @@
(define_insn "*muldf3_fpa"
[(set (match_operand:DF 0 "s_register_operand" "=f")
(mult:DF (match_operand:DF 1 "s_register_operand" "f")
- (match_operand:DF 2 "fpa_rhs_operand" "fG")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (match_operand:DF 2 "arm_float_rhs_operand" "fG")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"muf%?d\\t%0, %1, %2"
[(set_attr "type" "fmul")
(set_attr "predicable" "yes")]
@@ -240,8 +240,8 @@
[(set (match_operand:DF 0 "s_register_operand" "=f")
(mult:DF (float_extend:DF
(match_operand:SF 1 "s_register_operand" "f"))
- (match_operand:DF 2 "fpa_rhs_operand" "fG")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (match_operand:DF 2 "arm_float_rhs_operand" "fG")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"muf%?d\\t%0, %1, %2"
[(set_attr "type" "fmul")
(set_attr "predicable" "yes")]
@@ -252,7 +252,7 @@
(mult:DF (match_operand:DF 1 "s_register_operand" "f")
(float_extend:DF
(match_operand:SF 2 "s_register_operand" "f"))))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"muf%?d\\t%0, %1, %2"
[(set_attr "type" "fmul")
(set_attr "predicable" "yes")]
@@ -263,7 +263,7 @@
(mult:DF
(float_extend:DF (match_operand:SF 1 "s_register_operand" "f"))
(float_extend:DF (match_operand:SF 2 "s_register_operand" "f"))))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"muf%?d\\t%0, %1, %2"
[(set_attr "type" "fmul")
(set_attr "predicable" "yes")]
@@ -273,9 +273,9 @@
(define_insn "*divsf3_fpa"
[(set (match_operand:SF 0 "s_register_operand" "=f,f")
- (div:SF (match_operand:SF 1 "fpa_rhs_operand" "f,G")
- (match_operand:SF 2 "fpa_rhs_operand" "fG,f")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (div:SF (match_operand:SF 1 "arm_float_rhs_operand" "f,G")
+ (match_operand:SF 2 "arm_float_rhs_operand" "fG,f")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"@
fdv%?s\\t%0, %1, %2
frd%?s\\t%0, %2, %1"
@@ -285,9 +285,9 @@
(define_insn "*divdf3_fpa"
[(set (match_operand:DF 0 "s_register_operand" "=f,f")
- (div:DF (match_operand:DF 1 "fpa_rhs_operand" "f,G")
- (match_operand:DF 2 "fpa_rhs_operand" "fG,f")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (div:DF (match_operand:DF 1 "arm_float_rhs_operand" "f,G")
+ (match_operand:DF 2 "arm_float_rhs_operand" "fG,f")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"@
dvf%?d\\t%0, %1, %2
rdf%?d\\t%0, %2, %1"
@@ -299,8 +299,8 @@
[(set (match_operand:DF 0 "s_register_operand" "=f")
(div:DF (float_extend:DF
(match_operand:SF 1 "s_register_operand" "f"))
- (match_operand:DF 2 "fpa_rhs_operand" "fG")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (match_operand:DF 2 "arm_float_rhs_operand" "fG")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"dvf%?d\\t%0, %1, %2"
[(set_attr "type" "fdivd")
(set_attr "predicable" "yes")]
@@ -308,10 +308,10 @@
(define_insn "*divdf_df_esfdf_fpa"
[(set (match_operand:DF 0 "s_register_operand" "=f")
- (div:DF (match_operand:DF 1 "fpa_rhs_operand" "fG")
+ (div:DF (match_operand:DF 1 "arm_float_rhs_operand" "fG")
(float_extend:DF
(match_operand:SF 2 "s_register_operand" "f"))))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"rdf%?d\\t%0, %2, %1"
[(set_attr "type" "fdivd")
(set_attr "predicable" "yes")]
@@ -323,7 +323,7 @@
(match_operand:SF 1 "s_register_operand" "f"))
(float_extend:DF
(match_operand:SF 2 "s_register_operand" "f"))))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"dvf%?d\\t%0, %1, %2"
[(set_attr "type" "fdivd")
(set_attr "predicable" "yes")]
@@ -332,8 +332,8 @@
(define_insn "*modsf3_fpa"
[(set (match_operand:SF 0 "s_register_operand" "=f")
(mod:SF (match_operand:SF 1 "s_register_operand" "f")
- (match_operand:SF 2 "fpa_rhs_operand" "fG")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (match_operand:SF 2 "arm_float_rhs_operand" "fG")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"rmf%?s\\t%0, %1, %2"
[(set_attr "type" "fdivs")
(set_attr "predicable" "yes")]
@@ -342,8 +342,8 @@
(define_insn "*moddf3_fpa"
[(set (match_operand:DF 0 "s_register_operand" "=f")
(mod:DF (match_operand:DF 1 "s_register_operand" "f")
- (match_operand:DF 2 "fpa_rhs_operand" "fG")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (match_operand:DF 2 "arm_float_rhs_operand" "fG")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"rmf%?d\\t%0, %1, %2"
[(set_attr "type" "fdivd")
(set_attr "predicable" "yes")]
@@ -353,8 +353,8 @@
[(set (match_operand:DF 0 "s_register_operand" "=f")
(mod:DF (float_extend:DF
(match_operand:SF 1 "s_register_operand" "f"))
- (match_operand:DF 2 "fpa_rhs_operand" "fG")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (match_operand:DF 2 "arm_float_rhs_operand" "fG")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"rmf%?d\\t%0, %1, %2"
[(set_attr "type" "fdivd")
(set_attr "predicable" "yes")]
@@ -365,7 +365,7 @@
(mod:DF (match_operand:DF 1 "s_register_operand" "f")
(float_extend:DF
(match_operand:SF 2 "s_register_operand" "f"))))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"rmf%?d\\t%0, %1, %2"
[(set_attr "type" "fdivd")
(set_attr "predicable" "yes")]
@@ -377,7 +377,7 @@
(match_operand:SF 1 "s_register_operand" "f"))
(float_extend:DF
(match_operand:SF 2 "s_register_operand" "f"))))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"rmf%?d\\t%0, %1, %2"
[(set_attr "type" "fdivd")
(set_attr "predicable" "yes")]
@@ -386,7 +386,7 @@
(define_insn "*negsf2_fpa"
[(set (match_operand:SF 0 "s_register_operand" "=f")
(neg:SF (match_operand:SF 1 "s_register_operand" "f")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"mnf%?s\\t%0, %1"
[(set_attr "type" "ffarith")
(set_attr "predicable" "yes")]
@@ -395,7 +395,7 @@
(define_insn "*negdf2_fpa"
[(set (match_operand:DF 0 "s_register_operand" "=f")
(neg:DF (match_operand:DF 1 "s_register_operand" "f")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"mnf%?d\\t%0, %1"
[(set_attr "type" "ffarith")
(set_attr "predicable" "yes")]
@@ -405,7 +405,7 @@
[(set (match_operand:DF 0 "s_register_operand" "=f")
(neg:DF (float_extend:DF
(match_operand:SF 1 "s_register_operand" "f"))))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"mnf%?d\\t%0, %1"
[(set_attr "type" "ffarith")
(set_attr "predicable" "yes")]
@@ -414,7 +414,7 @@
(define_insn "*abssf2_fpa"
[(set (match_operand:SF 0 "s_register_operand" "=f")
(abs:SF (match_operand:SF 1 "s_register_operand" "f")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"abs%?s\\t%0, %1"
[(set_attr "type" "ffarith")
(set_attr "predicable" "yes")]
@@ -423,7 +423,7 @@
(define_insn "*absdf2_fpa"
[(set (match_operand:DF 0 "s_register_operand" "=f")
(abs:DF (match_operand:DF 1 "s_register_operand" "f")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"abs%?d\\t%0, %1"
[(set_attr "type" "ffarith")
(set_attr "predicable" "yes")]
@@ -433,7 +433,7 @@
[(set (match_operand:DF 0 "s_register_operand" "=f")
(abs:DF (float_extend:DF
(match_operand:SF 1 "s_register_operand" "f"))))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"abs%?d\\t%0, %1"
[(set_attr "type" "ffarith")
(set_attr "predicable" "yes")]
@@ -442,7 +442,7 @@
(define_insn "*sqrtsf2_fpa"
[(set (match_operand:SF 0 "s_register_operand" "=f")
(sqrt:SF (match_operand:SF 1 "s_register_operand" "f")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"sqt%?s\\t%0, %1"
[(set_attr "type" "float_em")
(set_attr "predicable" "yes")]
@@ -451,7 +451,7 @@
(define_insn "*sqrtdf2_fpa"
[(set (match_operand:DF 0 "s_register_operand" "=f")
(sqrt:DF (match_operand:DF 1 "s_register_operand" "f")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"sqt%?d\\t%0, %1"
[(set_attr "type" "float_em")
(set_attr "predicable" "yes")]
@@ -461,7 +461,7 @@
[(set (match_operand:DF 0 "s_register_operand" "=f")
(sqrt:DF (float_extend:DF
(match_operand:SF 1 "s_register_operand" "f"))))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"sqt%?d\\t%0, %1"
[(set_attr "type" "float_em")
(set_attr "predicable" "yes")]
@@ -470,7 +470,7 @@
(define_insn "*floatsisf2_fpa"
[(set (match_operand:SF 0 "s_register_operand" "=f")
(float:SF (match_operand:SI 1 "s_register_operand" "r")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"flt%?s\\t%0, %1"
[(set_attr "type" "r_2_f")
(set_attr "predicable" "yes")]
@@ -479,7 +479,7 @@
(define_insn "*floatsidf2_fpa"
[(set (match_operand:DF 0 "s_register_operand" "=f")
(float:DF (match_operand:SI 1 "s_register_operand" "r")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"flt%?d\\t%0, %1"
[(set_attr "type" "r_2_f")
(set_attr "predicable" "yes")]
@@ -488,7 +488,7 @@
(define_insn "*fix_truncsfsi2_fpa"
[(set (match_operand:SI 0 "s_register_operand" "=r")
(fix:SI (fix:SF (match_operand:SF 1 "s_register_operand" "f"))))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"fix%?z\\t%0, %1"
[(set_attr "type" "f_2_r")
(set_attr "predicable" "yes")]
@@ -497,7 +497,7 @@
(define_insn "*fix_truncdfsi2_fpa"
[(set (match_operand:SI 0 "s_register_operand" "=r")
(fix:SI (fix:DF (match_operand:DF 1 "s_register_operand" "f"))))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"fix%?z\\t%0, %1"
[(set_attr "type" "f_2_r")
(set_attr "predicable" "yes")]
@@ -507,7 +507,7 @@
[(set (match_operand:SF 0 "s_register_operand" "=f")
(float_truncate:SF
(match_operand:DF 1 "s_register_operand" "f")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"mvf%?s\\t%0, %1"
[(set_attr "type" "ffarith")
(set_attr "predicable" "yes")]
@@ -516,7 +516,7 @@
(define_insn "*extendsfdf2_fpa"
[(set (match_operand:DF 0 "s_register_operand" "=f")
(float_extend:DF (match_operand:SF 1 "s_register_operand" "f")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"mvf%?d\\t%0, %1"
[(set_attr "type" "ffarith")
(set_attr "predicable" "yes")]
@@ -526,7 +526,7 @@
[(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f, m,f,r,r,r, m")
(match_operand:SF 1 "general_operand" "fG,H,mE,f,r,f,r,mE,r"))]
"TARGET_ARM
- && TARGET_HARD_FLOAT
+ && TARGET_HARD_FLOAT && TARGET_FPA
&& (GET_CODE (operands[0]) != MEM
|| register_operand (operands[1], SFmode))"
"@
@@ -542,7 +542,7 @@
[(set_attr "length" "4,4,4,4,8,8,4,4,4")
(set_attr "predicable" "yes")
(set_attr "type"
- "ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r,*,load,store1")
+ "ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r,*,load1,store1")
(set_attr "pool_range" "*,*,1024,*,*,*,*,4096,*")
(set_attr "neg_pool_range" "*,*,1012,*,*,*,*,4084,*")]
)
@@ -553,7 +553,7 @@
(match_operand:DF 1 "general_operand"
"Q, r,r,r,mF,fG,H,mF,f,r, f"))]
"TARGET_ARM
- && TARGET_HARD_FLOAT
+ && TARGET_HARD_FLOAT && TARGET_FPA
&& (GET_CODE (operands[0]) != MEM
|| register_operand (operands[1], DFmode))"
"*
@@ -563,7 +563,8 @@
default:
case 0: return \"ldm%?ia\\t%m1, %M0\\t%@ double\";
case 1: return \"stm%?ia\\t%m0, %M1\\t%@ double\";
- case 2: case 3: case 4: return output_move_double (operands);
+ case 2: return \"#\";
+ case 3: case 4: return output_move_double (operands);
case 5: return \"mvf%?d\\t%0, %1\";
case 6: return \"mnf%?d\\t%0, #%N1\";
case 7: return \"ldf%?d\\t%0, %1\";
@@ -576,45 +577,43 @@
[(set_attr "length" "4,4,8,8,8,4,4,4,4,8,8")
(set_attr "predicable" "yes")
(set_attr "type"
- "load,store2,*,store2,load,ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r")
+ "load1,store2,*,store2,load1,ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r")
(set_attr "pool_range" "*,*,*,*,1020,*,*,1024,*,*,*")
(set_attr "neg_pool_range" "*,*,*,*,1008,*,*,1008,*,*,*")]
)
-;; Saving and restoring the floating point registers in the prologue should
-;; be done in XFmode, even though we don't support that for anything else
-;; (Well, strictly it's 'internal representation', but that's effectively
-;; XFmode).
-
+;; We treat XFmode as meaning 'internal format'. It's the right size and we
+;; don't use it for anything else. We only support moving between FPA
+;; registers and moving an FPA register to/from memory.
(define_insn "*movxf_fpa"
- [(set (match_operand:XF 0 "nonimmediate_operand" "=f,f,f,m,f,r,r")
- (match_operand:XF 1 "general_operand" "fG,H,m,f,r,f,r"))]
- "TARGET_ARM && TARGET_HARD_FLOAT && reload_completed"
+ [(set (match_operand:XF 0 "nonimmediate_operand" "=f,f,m")
+ (match_operand:XF 1 "general_operand" "f,m,f"))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA
+ && (register_operand (operands[0], XFmode)
+ || register_operand (operands[1], XFmode))"
"*
switch (which_alternative)
{
default:
case 0: return \"mvf%?e\\t%0, %1\";
- case 1: return \"mnf%?e\\t%0, #%N1\";
- case 2: return \"ldf%?e\\t%0, %1\";
- case 3: return \"stf%?e\\t%1, %0\";
- case 4: return output_mov_long_double_fpa_from_arm (operands);
- case 5: return output_mov_long_double_arm_from_fpa (operands);
- case 6: return output_mov_long_double_arm_from_arm (operands);
+ case 1: if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
+ return \"ldf%?e\\t%0, %1\";
+ return \"lfm%?\\t%0, 1, %1\";
+ case 2: if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
+ return \"stf%?e\\t%1, %0\";
+ return \"sfm%?\\t%1, 1, %0\";
}
"
- [(set_attr "length" "4,4,4,4,8,8,12")
+ [(set_attr "length" "4,4,4")
(set_attr "predicable" "yes")
- (set_attr "type" "ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r,*")
- (set_attr "pool_range" "*,*,1024,*,*,*,*")
- (set_attr "neg_pool_range" "*,*,1004,*,*,*,*")]
+ (set_attr "type" "ffarith,f_load,f_store")]
)
(define_insn "*cmpsf_fpa"
[(set (reg:CCFP CC_REGNUM)
(compare:CCFP (match_operand:SF 0 "s_register_operand" "f,f")
- (match_operand:SF 1 "fpa_add_operand" "fG,H")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (match_operand:SF 1 "arm_float_add_operand" "fG,H")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"@
cmf%?\\t%0, %1
cnf%?\\t%0, #%N1"
@@ -625,8 +624,8 @@
(define_insn "*cmpdf_fpa"
[(set (reg:CCFP CC_REGNUM)
(compare:CCFP (match_operand:DF 0 "s_register_operand" "f,f")
- (match_operand:DF 1 "fpa_add_operand" "fG,H")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (match_operand:DF 1 "arm_float_add_operand" "fG,H")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"@
cmf%?\\t%0, %1
cnf%?\\t%0, #%N1"
@@ -638,8 +637,8 @@
[(set (reg:CCFP CC_REGNUM)
(compare:CCFP (float_extend:DF
(match_operand:SF 0 "s_register_operand" "f,f"))
- (match_operand:DF 1 "fpa_add_operand" "fG,H")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (match_operand:DF 1 "arm_float_add_operand" "fG,H")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"@
cmf%?\\t%0, %1
cnf%?\\t%0, #%N1"
@@ -652,7 +651,7 @@
(compare:CCFP (match_operand:DF 0 "s_register_operand" "f")
(float_extend:DF
(match_operand:SF 1 "s_register_operand" "f"))))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"cmf%?\\t%0, %1"
[(set_attr "conds" "set")
(set_attr "type" "f_2_r")]
@@ -661,8 +660,8 @@
(define_insn "*cmpsf_trap_fpa"
[(set (reg:CCFPE CC_REGNUM)
(compare:CCFPE (match_operand:SF 0 "s_register_operand" "f,f")
- (match_operand:SF 1 "fpa_add_operand" "fG,H")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (match_operand:SF 1 "arm_float_add_operand" "fG,H")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"@
cmf%?e\\t%0, %1
cnf%?e\\t%0, #%N1"
@@ -673,8 +672,8 @@
(define_insn "*cmpdf_trap_fpa"
[(set (reg:CCFPE CC_REGNUM)
(compare:CCFPE (match_operand:DF 0 "s_register_operand" "f,f")
- (match_operand:DF 1 "fpa_add_operand" "fG,H")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (match_operand:DF 1 "arm_float_add_operand" "fG,H")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"@
cmf%?e\\t%0, %1
cnf%?e\\t%0, #%N1"
@@ -686,8 +685,8 @@
[(set (reg:CCFPE CC_REGNUM)
(compare:CCFPE (float_extend:DF
(match_operand:SF 0 "s_register_operand" "f,f"))
- (match_operand:DF 1 "fpa_add_operand" "fG,H")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (match_operand:DF 1 "arm_float_add_operand" "fG,H")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"@
cmf%?e\\t%0, %1
cnf%?e\\t%0, #%N1"
@@ -700,7 +699,7 @@
(compare:CCFPE (match_operand:DF 0 "s_register_operand" "f")
(float_extend:DF
(match_operand:SF 1 "s_register_operand" "f"))))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"cmf%?e\\t%0, %1"
[(set_attr "conds" "set")
(set_attr "type" "f_2_r")]
@@ -711,9 +710,9 @@
(if_then_else:SF
(match_operator 3 "arm_comparison_operator"
[(match_operand 4 "cc_register" "") (const_int 0)])
- (match_operand:SF 1 "fpa_add_operand" "0,0,fG,H,fG,fG,H,H")
- (match_operand:SF 2 "fpa_add_operand" "fG,H,0,0,fG,H,fG,H")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (match_operand:SF 1 "arm_float_add_operand" "0,0,fG,H,fG,fG,H,H")
+ (match_operand:SF 2 "arm_float_add_operand" "fG,H,0,0,fG,H,fG,H")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"@
mvf%D3s\\t%0, %2
mnf%D3s\\t%0, #%N2
@@ -733,9 +732,9 @@
(if_then_else:DF
(match_operator 3 "arm_comparison_operator"
[(match_operand 4 "cc_register" "") (const_int 0)])
- (match_operand:DF 1 "fpa_add_operand" "0,0,fG,H,fG,fG,H,H")
- (match_operand:DF 2 "fpa_add_operand" "fG,H,0,0,fG,H,fG,H")))]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ (match_operand:DF 1 "arm_float_add_operand" "0,0,fG,H,fG,fG,H,H")
+ (match_operand:DF 2 "arm_float_add_operand" "fG,H,0,0,fG,H,fG,H")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
"@
mvf%D3d\\t%0, %2
mnf%D3d\\t%0, #%N2
@@ -749,4 +748,3 @@
(set_attr "type" "ffarith")
(set_attr "conds" "use")]
)
-
diff --git a/contrib/gcc/config/arm/freebsd.h b/contrib/gcc/config/arm/freebsd.h
index cc3f727..6bae83d 100644
--- a/contrib/gcc/config/arm/freebsd.h
+++ b/contrib/gcc/config/arm/freebsd.h
@@ -16,8 +16,8 @@
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, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#undef SUBTARGET_EXTRA_SPECS
@@ -30,7 +30,6 @@
#undef LINK_SPEC
#define LINK_SPEC " \
%{p:%nconsider using `-pg' instead of `-p' with gprof(1) } \
- %{Wl,*:%*} \
%{v:-V} \
%{assert*} %{R*} %{rpath*} %{defsym*} \
%{shared:-Bshareable %{h*} %{soname*}} \
diff --git a/contrib/gcc/config/arm/gentune.sh b/contrib/gcc/config/arm/gentune.sh
new file mode 100755
index 0000000..40c0541
--- /dev/null
+++ b/contrib/gcc/config/arm/gentune.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+# Generate arm-tune.md, a file containing the tune attribute from the list of
+# CPUs in arm-cores.def
+
+echo ";; -*- buffer-read-only: t -*-"
+echo ";; Generated automatically by gentune.sh from arm-cores.def"
+
+allcores=`awk -F'[(, ]+' '/^ARM_CORE/ { cores = cores$3"," } END { print cores } ' $1`
+
+echo "(define_attr \"tune\""
+echo " \"$allcores\"" | sed -e 's/,"$/"/'
+echo " (const (symbol_ref \"arm_tune\")))"
diff --git a/contrib/gcc/config/arm/ieee754-df.S b/contrib/gcc/config/arm/ieee754-df.S
index 6a7aab8..74d9f0d 100644
--- a/contrib/gcc/config/arm/ieee754-df.S
+++ b/contrib/gcc/config/arm/ieee754-df.S
@@ -1,6 +1,6 @@
/* ieee754-df.S double-precision floating point support for ARM
- Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
Contributed by Nicolas Pitre (nico@cam.org)
This file is free software; you can redistribute it and/or modify it
@@ -24,8 +24,8 @@
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/*
* Notes:
@@ -59,55 +59,52 @@
#ifdef L_negdf2
ARM_FUNC_START negdf2
+ARM_FUNC_ALIAS aeabi_dneg negdf2
+
@ flip sign bit
eor xh, xh, #0x80000000
RET
+ FUNC_END aeabi_dneg
FUNC_END negdf2
#endif
#ifdef L_addsubdf3
+ARM_FUNC_START aeabi_drsub
+
+ eor xh, xh, #0x80000000 @ flip sign bit of first arg
+ b 1f
+
ARM_FUNC_START subdf3
- @ flip sign bit of second arg
- eor yh, yh, #0x80000000
-#if defined(__thumb__) && !defined(__THUMB_INTERWORK__)
+ARM_FUNC_ALIAS aeabi_dsub subdf3
+
+ eor yh, yh, #0x80000000 @ flip sign bit of second arg
+#if defined(__INTERWORKING_STUBS__)
b 1f @ Skip Thumb-code prologue
#endif
ARM_FUNC_START adddf3
+ARM_FUNC_ALIAS aeabi_dadd adddf3
-1: @ Compare both args, return zero if equal but the sign.
- teq xl, yl
- eoreq ip, xh, yh
- teqeq ip, #0x80000000
- beq LSYM(Lad_z)
-
- @ If first arg is 0 or -0, return second arg.
- @ If second arg is 0 or -0, return first arg.
- orrs ip, xl, xh, lsl #1
- moveq xl, yl
- moveq xh, yh
- orrnes ip, yl, yh, lsl #1
- RETc(eq)
-
- stmfd sp!, {r4, r5, lr}
-
- @ Mask out exponents.
- mov ip, #0x7f000000
- orr ip, ip, #0x00f00000
- and r4, xh, ip
- and r5, yh, ip
+1: stmfd sp!, {r4, r5, lr}
- @ If either of them is 0x7ff, result will be INF or NAN
- teq r4, ip
- teqne r5, ip
- beq LSYM(Lad_i)
+ @ Look for zeroes, equal values, INF, or NAN.
+ mov r4, xh, lsl #1
+ mov r5, yh, lsl #1
+ teq r4, r5
+ teqeq xl, yl
+ orrnes ip, r4, xl
+ orrnes ip, r5, yl
+ mvnnes ip, r4, asr #21
+ mvnnes ip, r5, asr #21
+ beq LSYM(Lad_s)
@ Compute exponent difference. Make largest exponent in r4,
@ corresponding arg in xh-xl, and positive exponent difference in r5.
- subs r5, r5, r4
+ mov r4, r4, lsr #21
+ rsbs r5, r4, r5, lsr #21
rsblt r5, r5, #0
ble 1f
add r4, r4, r5
@@ -118,24 +115,24 @@ ARM_FUNC_START adddf3
eor yl, xl, yl
eor yh, xh, yh
1:
-
@ If exponent difference is too large, return largest argument
@ already in xh-xl. We need up to 54 bit to handle proper rounding
@ of 0x1p54 - 1.1.
- cmp r5, #(54 << 20)
+ cmp r5, #54
RETLDM "r4, r5" hi
@ Convert mantissa to signed integer.
tst xh, #0x80000000
- bic xh, xh, ip, lsl #1
- orr xh, xh, #0x00100000
+ mov xh, xh, lsl #12
+ mov ip, #0x00100000
+ orr xh, ip, xh, lsr #12
beq 1f
rsbs xl, xl, #0
rsc xh, xh, #0
1:
tst yh, #0x80000000
- bic yh, yh, ip, lsl #1
- orr yh, yh, #0x00100000
+ mov yh, yh, lsl #12
+ orr yh, ip, yh, lsr #12
beq 1f
rsbs yl, yl, #0
rsc yh, yh, #0
@@ -145,42 +142,30 @@ ARM_FUNC_START adddf3
teq r4, r5
beq LSYM(Lad_d)
LSYM(Lad_x):
- @ Scale down second arg with exponent difference.
- @ Apply shift one bit left to first arg and the rest to second arg
- @ to simplify things later, but only if exponent does not become 0.
- mov ip, #0
- movs r5, r5, lsr #20
- beq 3f
- teq r4, #(1 << 20)
- beq 1f
- movs xl, xl, lsl #1
- adc xh, ip, xh, lsl #1
- sub r4, r4, #(1 << 20)
- subs r5, r5, #1
- beq 3f
- @ Shift yh-yl right per r5, keep leftover bits into ip.
-1: rsbs lr, r5, #32
- blt 2f
+ @ Compensate for the exponent overlapping the mantissa MSB added later
+ sub r4, r4, #1
+
+ @ Shift yh-yl right per r5, add to xh-xl, keep leftover bits into ip.
+ rsbs lr, r5, #32
+ blt 1f
mov ip, yl, lsl lr
- mov yl, yl, lsr r5
- orr yl, yl, yh, lsl lr
- mov yh, yh, asr r5
- b 3f
-2: sub r5, r5, #32
+ adds xl, xl, yl, lsr r5
+ adc xh, xh, #0
+ adds xl, xl, yh, lsl lr
+ adcs xh, xh, yh, asr r5
+ b 2f
+1: sub r5, r5, #32
add lr, lr, #32
cmp yl, #1
- adc ip, ip, yh, lsl lr
- mov yl, yh, asr r5
- mov yh, yh, asr #32
-3:
- @ the actual addition
- adds xl, xl, yl
- adc xh, xh, yh
-
+ mov ip, yh, lsl lr
+ orrcs ip, ip, #2 @ 2 not 1, to allow lsr #1 later
+ adds xl, xl, yh, asr r5
+ adcs xh, xh, yh, asr #31
+2:
@ We now have a result in xh-xl-ip.
- @ Keep absolute value in xh-xl-ip, sign in r5.
- ands r5, xh, #0x80000000
+ @ Keep absolute value in xh-xl-ip, sign in r5 (the n bit was set above)
+ and r5, xh, #0x80000000
bpl LSYM(Lad_p)
rsbs ip, ip, #0
rscs xl, xl, #0
@@ -189,75 +174,66 @@ LSYM(Lad_x):
@ Determine how to normalize the result.
LSYM(Lad_p):
cmp xh, #0x00100000
- bcc LSYM(Lad_l)
+ bcc LSYM(Lad_a)
cmp xh, #0x00200000
- bcc LSYM(Lad_r0)
- cmp xh, #0x00400000
- bcc LSYM(Lad_r1)
+ bcc LSYM(Lad_e)
@ Result needs to be shifted right.
movs xh, xh, lsr #1
movs xl, xl, rrx
- movs ip, ip, rrx
- orrcs ip, ip, #1
- add r4, r4, #(1 << 20)
-LSYM(Lad_r1):
- movs xh, xh, lsr #1
- movs xl, xl, rrx
- movs ip, ip, rrx
- orrcs ip, ip, #1
- add r4, r4, #(1 << 20)
+ mov ip, ip, rrx
+ add r4, r4, #1
+
+ @ Make sure we did not bust our exponent.
+ mov r2, r4, lsl #21
+ cmn r2, #(2 << 21)
+ bcs LSYM(Lad_o)
@ Our result is now properly aligned into xh-xl, remaining bits in ip.
@ Round with MSB of ip. If halfway between two numbers, round towards
@ LSB of xl = 0.
-LSYM(Lad_r0):
- adds xl, xl, ip, lsr #31
- adc xh, xh, #0
- teq ip, #0x80000000
- biceq xl, xl, #1
-
- @ One extreme rounding case may add a new MSB. Adjust exponent.
- @ That MSB will be cleared when exponent is merged below.
- tst xh, #0x00200000
- addne r4, r4, #(1 << 20)
-
- @ Make sure we did not bust our exponent.
- adds ip, r4, #(1 << 20)
- bmi LSYM(Lad_o)
-
@ Pack final result together.
LSYM(Lad_e):
- bic xh, xh, #0x00300000
- orr xh, xh, r4
+ cmp ip, #0x80000000
+ moveqs ip, xl, lsr #1
+ adcs xl, xl, #0
+ adc xh, xh, r4, lsl #20
orr xh, xh, r5
RETLDM "r4, r5"
-LSYM(Lad_l):
@ Result must be shifted left and exponent adjusted.
- @ No rounding necessary since ip will always be 0.
+LSYM(Lad_a):
+ movs ip, ip, lsl #1
+ adcs xl, xl, xl
+ adc xh, xh, xh
+ tst xh, #0x00100000
+ sub r4, r4, #1
+ bne LSYM(Lad_e)
+
+ @ No rounding necessary since ip will always be 0 at this point.
+LSYM(Lad_l):
+
#if __ARM_ARCH__ < 5
teq xh, #0
- movne r3, #-11
- moveq r3, #21
+ movne r3, #20
+ moveq r3, #52
moveq xh, xl
moveq xl, #0
mov r2, xh
- movs ip, xh, lsr #16
- moveq r2, r2, lsl #16
- addeq r3, r3, #16
- tst r2, #0xff000000
- moveq r2, r2, lsl #8
- addeq r3, r3, #8
- tst r2, #0xf0000000
- moveq r2, r2, lsl #4
- addeq r3, r3, #4
- tst r2, #0xc0000000
- moveq r2, r2, lsl #2
- addeq r3, r3, #2
- tst r2, #0x80000000
- addeq r3, r3, #1
+ cmp r2, #(1 << 16)
+ movhs r2, r2, lsr #16
+ subhs r3, r3, #16
+ cmp r2, #(1 << 8)
+ movhs r2, r2, lsr #8
+ subhs r3, r3, #8
+ cmp r2, #(1 << 4)
+ movhs r2, r2, lsr #4
+ subhs r3, r3, #4
+ cmp r2, #(1 << 2)
+ subhs r3, r3, #2
+ sublo r3, r3, r2, lsr #1
+ sub r3, r3, r2, lsr #3
#else
@@ -293,13 +269,15 @@ LSYM(Lad_l):
movle xl, xl, lsl r2
@ adjust exponent accordingly.
-3: subs r4, r4, r3, lsl #20
- bgt LSYM(Lad_e)
+3: subs r4, r4, r3
+ addge xh, xh, r4, lsl #20
+ orrge xh, xh, r5
+ RETLDM "r4, r5" ge
@ Exponent too small, denormalize result.
@ Find out proper shift value.
- mvn r4, r4, asr #20
- subs r4, r4, #30
+ mvn r4, r4
+ subs r4, r4, #31
bge 2f
adds r4, r4, #12
bgt 1f
@@ -328,23 +306,49 @@ LSYM(Lad_l):
RETLDM "r4, r5"
@ Adjust exponents for denormalized arguments.
+ @ Note that r4 must not remain equal to 0.
LSYM(Lad_d):
teq r4, #0
- eoreq xh, xh, #0x00100000
- addeq r4, r4, #(1 << 20)
eor yh, yh, #0x00100000
- subne r5, r5, #(1 << 20)
+ eoreq xh, xh, #0x00100000
+ addeq r4, r4, #1
+ subne r5, r5, #1
b LSYM(Lad_x)
- @ Result is x - x = 0, unless x = INF or NAN.
-LSYM(Lad_z):
- sub ip, ip, #0x00100000 @ ip becomes 0x7ff00000
- and r2, xh, ip
- teq r2, ip
- orreq xh, ip, #0x00080000
+
+LSYM(Lad_s):
+ mvns ip, r4, asr #21
+ mvnnes ip, r5, asr #21
+ beq LSYM(Lad_i)
+
+ teq r4, r5
+ teqeq xl, yl
+ beq 1f
+
+ @ Result is x + 0.0 = x or 0.0 + y = y.
+ orrs ip, r4, xl
+ moveq xh, yh
+ moveq xl, yl
+ RETLDM "r4, r5"
+
+1: teq xh, yh
+
+ @ Result is x - x = 0.
movne xh, #0
- mov xl, #0
- RET
+ movne xl, #0
+ RETLDM "r4, r5" ne
+
+ @ Result is x + x = 2x.
+ movs ip, r4, lsr #21
+ bne 2f
+ movs xl, xl, lsl #1
+ adcs xh, xh, xh
+ orrcs xh, xh, #0x80000000
+ RETLDM "r4, r5"
+2: adds r4, r4, #(2 << 21)
+ addcc xh, xh, #(1 << 20)
+ RETLDM "r4, r5" cc
+ and r5, xh, #0x80000000
@ Overflow: return INF.
LSYM(Lad_o):
@@ -358,127 +362,221 @@ LSYM(Lad_o):
@ if yh-yl != INF/NAN: return xh-xl (which is INF/NAN)
@ if either is NAN: return NAN
@ if opposite sign: return NAN
- @ return xh-xl (which is INF or -INF)
+ @ otherwise return xh-xl (which is INF or -INF)
LSYM(Lad_i):
- teq r4, ip
+ mvns ip, r4, asr #21
movne xh, yh
movne xl, yl
- teqeq r5, ip
- RETLDM "r4, r5" ne
-
+ mvneqs ip, r5, asr #21
+ movne yh, xh
+ movne yl, xl
orrs r4, xl, xh, lsl #12
- orreqs r4, yl, yh, lsl #12
+ orreqs r5, yl, yh, lsl #12
teqeq xh, yh
- orrne xh, r5, #0x00080000
- movne xl, #0
+ orrne xh, xh, #0x00080000 @ quiet NAN
RETLDM "r4, r5"
+ FUNC_END aeabi_dsub
FUNC_END subdf3
+ FUNC_END aeabi_dadd
FUNC_END adddf3
ARM_FUNC_START floatunsidf
+ARM_FUNC_ALIAS aeabi_ui2d floatunsidf
+
teq r0, #0
moveq r1, #0
RETc(eq)
stmfd sp!, {r4, r5, lr}
- mov r4, #(0x400 << 20) @ initial exponent
- add r4, r4, #((52-1) << 20)
+ mov r4, #0x400 @ initial exponent
+ add r4, r4, #(52-1 - 1)
mov r5, #0 @ sign bit is 0
+ .ifnc xl, r0
mov xl, r0
+ .endif
mov xh, #0
b LSYM(Lad_l)
+ FUNC_END aeabi_ui2d
FUNC_END floatunsidf
ARM_FUNC_START floatsidf
+ARM_FUNC_ALIAS aeabi_i2d floatsidf
+
teq r0, #0
moveq r1, #0
RETc(eq)
stmfd sp!, {r4, r5, lr}
- mov r4, #(0x400 << 20) @ initial exponent
- add r4, r4, #((52-1) << 20)
+ mov r4, #0x400 @ initial exponent
+ add r4, r4, #(52-1 - 1)
ands r5, r0, #0x80000000 @ sign bit in r5
rsbmi r0, r0, #0 @ absolute value
+ .ifnc xl, r0
mov xl, r0
+ .endif
mov xh, #0
b LSYM(Lad_l)
+ FUNC_END aeabi_i2d
FUNC_END floatsidf
ARM_FUNC_START extendsfdf2
- movs r2, r0, lsl #1
- beq 1f @ value is 0.0 or -0.0
+ARM_FUNC_ALIAS aeabi_f2d extendsfdf2
+
+ movs r2, r0, lsl #1 @ toss sign bit
mov xh, r2, asr #3 @ stretch exponent
mov xh, xh, rrx @ retrieve sign bit
mov xl, r2, lsl #28 @ retrieve remaining bits
- ands r2, r2, #0xff000000 @ isolate exponent
- beq 2f @ exponent was 0 but not mantissa
- teq r2, #0xff000000 @ check if INF or NAN
+ andnes r3, r2, #0xff000000 @ isolate exponent
+ teqne r3, #0xff000000 @ if not 0, check if INF or NAN
eorne xh, xh, #0x38000000 @ fixup exponent otherwise.
- RET
+ RETc(ne) @ and return it.
-1: mov xh, r0
- mov xl, #0
- RET
+ teq r2, #0 @ if actually 0
+ teqne r3, #0xff000000 @ or INF or NAN
+ RETc(eq) @ we are done already.
-2: @ value was denormalized. We can normalize it now.
+ @ value was denormalized. We can normalize it now.
stmfd sp!, {r4, r5, lr}
- mov r4, #(0x380 << 20) @ setup corresponding exponent
- add r4, r4, #(1 << 20)
+ mov r4, #0x380 @ setup corresponding exponent
and r5, xh, #0x80000000 @ move sign bit in r5
bic xh, xh, #0x80000000
b LSYM(Lad_l)
+ FUNC_END aeabi_f2d
FUNC_END extendsfdf2
+ARM_FUNC_START floatundidf
+ARM_FUNC_ALIAS aeabi_ul2d floatundidf
+
+ orrs r2, r0, r1
+#if !defined (__VFP_FP__) && !defined(__SOFTFP__)
+ mvfeqd f0, #0.0
+#endif
+ RETc(eq)
+
+#if !defined (__VFP_FP__) && !defined(__SOFTFP__)
+ @ For hard FPA code we want to return via the tail below so that
+ @ we can return the result in f0 as well as in r0/r1 for backwards
+ @ compatibility.
+ adr ip, LSYM(f0_ret)
+ stmfd sp!, {r4, r5, ip, lr}
+#else
+ stmfd sp!, {r4, r5, lr}
+#endif
+
+ mov r5, #0
+ b 2f
+
+ARM_FUNC_START floatdidf
+ARM_FUNC_ALIAS aeabi_l2d floatdidf
+
+ orrs r2, r0, r1
+#if !defined (__VFP_FP__) && !defined(__SOFTFP__)
+ mvfeqd f0, #0.0
+#endif
+ RETc(eq)
+
+#if !defined (__VFP_FP__) && !defined(__SOFTFP__)
+ @ For hard FPA code we want to return via the tail below so that
+ @ we can return the result in f0 as well as in r0/r1 for backwards
+ @ compatibility.
+ adr ip, LSYM(f0_ret)
+ stmfd sp!, {r4, r5, ip, lr}
+#else
+ stmfd sp!, {r4, r5, lr}
+#endif
+
+ ands r5, ah, #0x80000000 @ sign bit in r5
+ bpl 2f
+ rsbs al, al, #0
+ rsc ah, ah, #0
+2:
+ mov r4, #0x400 @ initial exponent
+ add r4, r4, #(52-1 - 1)
+
+ @ FPA little-endian: must swap the word order.
+ .ifnc xh, ah
+ mov ip, al
+ mov xh, ah
+ mov xl, ip
+ .endif
+
+ movs ip, xh, lsr #22
+ beq LSYM(Lad_p)
+
+ @ The value is too big. Scale it down a bit...
+ mov r2, #3
+ movs ip, ip, lsr #3
+ addne r2, r2, #3
+ movs ip, ip, lsr #3
+ addne r2, r2, #3
+ add r2, r2, ip, lsr #3
+
+ rsb r3, r2, #32
+ mov ip, xl, lsl r3
+ mov xl, xl, lsr r2
+ orr xl, xl, xh, lsl r3
+ mov xh, xh, lsr r2
+ add r4, r4, r2
+ b LSYM(Lad_p)
+
+#if !defined (__VFP_FP__) && !defined(__SOFTFP__)
+
+ @ Legacy code expects the result to be returned in f0. Copy it
+ @ there as well.
+LSYM(f0_ret):
+ stmfd sp!, {r0, r1}
+ ldfd f0, [sp], #8
+ RETLDM
+
+#endif
+
+ FUNC_END floatdidf
+ FUNC_END aeabi_l2d
+ FUNC_END floatundidf
+ FUNC_END aeabi_ul2d
+
#endif /* L_addsubdf3 */
#ifdef L_muldivdf3
ARM_FUNC_START muldf3
-
+ARM_FUNC_ALIAS aeabi_dmul muldf3
stmfd sp!, {r4, r5, r6, lr}
- @ Mask out exponents.
- mov ip, #0x7f000000
- orr ip, ip, #0x00f00000
- and r4, xh, ip
- and r5, yh, ip
-
- @ Trap any INF/NAN.
- teq r4, ip
+ @ Mask out exponents, trap any zero/denormal/INF/NAN.
+ mov ip, #0xff
+ orr ip, ip, #0x700
+ ands r4, ip, xh, lsr #20
+ andnes r5, ip, yh, lsr #20
+ teqne r4, ip
teqne r5, ip
- beq LSYM(Lml_s)
+ bleq LSYM(Lml_s)
- @ Trap any multiplication by 0.
- orrs r6, xl, xh, lsl #1
- orrnes r6, yl, yh, lsl #1
- beq LSYM(Lml_z)
-
- @ Shift exponents right one bit to make room for overflow bit.
- @ If either of them is 0, scale denormalized arguments off line.
- @ Then add both exponents together.
- movs r4, r4, lsr #1
- teqne r5, #0
- beq LSYM(Lml_d)
-LSYM(Lml_x):
- add r4, r4, r5, asr #1
-
- @ Preserve final sign in r4 along with exponent for now.
- teq xh, yh
- orrmi r4, r4, #0x8000
+ @ Add exponents together
+ add r4, r4, r5
+
+ @ Determine final sign.
+ eor r6, xh, yh
@ Convert mantissa to unsigned integer.
- bic xh, xh, ip, lsl #1
- bic yh, yh, ip, lsl #1
+ @ If power of two, branch to a separate path.
+ bic xh, xh, ip, lsl #21
+ bic yh, yh, ip, lsl #21
+ orrs r5, xl, xh, lsl #12
+ orrnes r5, yl, yh, lsl #12
orr xh, xh, #0x00100000
orr yh, yh, #0x00100000
+ beq LSYM(Lml_1)
#if __ARM_ARCH__ < 4
+ @ Put sign bit in r6, which will be restored in yl later.
+ and r6, r6, #0x80000000
+
@ Well, no way to make it shorter without the umull instruction.
- @ We must perform that 53 x 53 bit multiplication by hand.
- stmfd sp!, {r7, r8, r9, sl, fp}
+ stmfd sp!, {r6, r7, r8, r9, sl, fp}
mov r7, xl, lsr #16
mov r8, yl, lsr #16
mov r9, xh, lsr #16
@@ -530,92 +628,83 @@ LSYM(Lml_x):
mul fp, xh, yh
adcs r5, r5, fp
adc r6, r6, #0
- ldmfd sp!, {r7, r8, r9, sl, fp}
+ ldmfd sp!, {yl, r7, r8, r9, sl, fp}
#else
- @ Here is the actual multiplication: 53 bits * 53 bits -> 106 bits.
+ @ Here is the actual multiplication.
umull ip, lr, xl, yl
mov r5, #0
- umlal lr, r5, xl, yh
umlal lr, r5, xh, yl
+ and yl, r6, #0x80000000
+ umlal lr, r5, xl, yh
mov r6, #0
umlal r5, r6, xh, yh
#endif
@ The LSBs in ip are only significant for the final rounding.
- @ Fold them into one bit of lr.
+ @ Fold them into lr.
teq ip, #0
orrne lr, lr, #1
- @ Put final sign in xh.
- mov xh, r4, lsl #16
- bic r4, r4, #0x8000
-
- @ Adjust result if one extra MSB appeared (one of four times).
- tst r6, #(1 << 9)
- beq 1f
- add r4, r4, #(1 << 19)
- movs r6, r6, lsr #1
- movs r5, r5, rrx
- movs lr, lr, rrx
- orrcs lr, lr, #1
-1:
- @ Scale back to 53 bits.
- @ xh contains sign bit already.
- orr xh, xh, r6, lsl #12
- orr xh, xh, r5, lsr #20
- mov xl, r5, lsl #12
- orr xl, xl, lr, lsr #20
-
- @ Apply exponent bias, check range for underflow.
- sub r4, r4, #0x00f80000
- subs r4, r4, #0x1f000000
- ble LSYM(Lml_u)
-
- @ Round the result.
- movs lr, lr, lsl #12
- bpl 1f
- adds xl, xl, #1
- adc xh, xh, #0
- teq lr, #0x80000000
- biceq xl, xl, #1
-
- @ Rounding may have produced an extra MSB here.
- @ The extra bit is cleared before merging the exponent below.
- tst xh, #0x00200000
- addne r4, r4, #(1 << 19)
+ @ Adjust result upon the MSB position.
+ sub r4, r4, #0xff
+ cmp r6, #(1 << (20-11))
+ sbc r4, r4, #0x300
+ bcs 1f
+ movs lr, lr, lsl #1
+ adcs r5, r5, r5
+ adc r6, r6, r6
1:
- @ Check exponent for overflow.
- adds ip, r4, #(1 << 19)
- tst ip, #(1 << 30)
- bne LSYM(Lml_o)
-
- @ Add final exponent.
- bic xh, xh, #0x00300000
- orr xh, xh, r4, lsl #1
+ @ Shift to final position, add sign to result.
+ orr xh, yl, r6, lsl #11
+ orr xh, xh, r5, lsr #21
+ mov xl, r5, lsl #11
+ orr xl, xl, lr, lsr #21
+ mov lr, lr, lsl #11
+
+ @ Check exponent range for under/overflow.
+ subs ip, r4, #(254 - 1)
+ cmphi ip, #0x700
+ bhi LSYM(Lml_u)
+
+ @ Round the result, merge final exponent.
+ cmp lr, #0x80000000
+ moveqs lr, xl, lsr #1
+ adcs xl, xl, #0
+ adc xh, xh, r4, lsl #20
RETLDM "r4, r5, r6"
- @ Result is 0, but determine sign anyway.
-LSYM(Lml_z):
+ @ Multiplication by 0x1p*: let''s shortcut a lot of code.
+LSYM(Lml_1):
+ and r6, r6, #0x80000000
+ orr xh, r6, xh
+ orr xl, xl, yl
eor xh, xh, yh
-LSYM(Ldv_z):
- bic xh, xh, #0x7fffffff
- mov xl, #0
- RETLDM "r4, r5, r6"
+ subs r4, r4, ip, lsr #1
+ rsbgts r5, r4, ip
+ orrgt xh, xh, r4, lsl #20
+ RETLDM "r4, r5, r6" gt
+
+ @ Under/overflow: fix things up for the code below.
+ orr xh, xh, #0x00100000
+ mov lr, #0
+ subs r4, r4, #1
- @ Check if denormalized result is possible, otherwise return signed 0.
LSYM(Lml_u):
- cmn r4, #(53 << 19)
+ @ Overflow?
+ bgt LSYM(Lml_o)
+
+ @ Check if denormalized result is possible, otherwise return signed 0.
+ cmn r4, #(53 + 1)
movle xl, #0
bicle xh, xh, #0x7fffffff
RETLDM "r4, r5, r6" le
@ Find out proper shift value.
-LSYM(Lml_r):
- mvn r4, r4, asr #19
- subs r4, r4, #30
+ rsb r4, r4, #0
+ subs r4, r4, #32
bge 2f
adds r4, r4, #12
bgt 1f
@@ -626,14 +715,12 @@ LSYM(Lml_r):
mov r3, xl, lsl r5
mov xl, xl, lsr r4
orr xl, xl, xh, lsl r5
- movs xh, xh, lsl #1
- mov xh, xh, lsr r4
- mov xh, xh, rrx
+ and r2, xh, #0x80000000
+ bic xh, xh, #0x80000000
adds xl, xl, r3, lsr #31
- adc xh, xh, #0
- teq lr, #0
- teqeq r3, #0x80000000
- biceq xl, xl, #1
+ adc xh, r2, xh, lsr r4
+ orrs lr, lr, r3, lsl #1
+ biceq xl, xl, r3, lsr #31
RETLDM "r4, r5, r6"
@ shift result right of 21 to 31 bits, or left 11 to 1 bits after
@@ -646,53 +733,70 @@ LSYM(Lml_r):
bic xh, xh, #0x7fffffff
adds xl, xl, r3, lsr #31
adc xh, xh, #0
- teq lr, #0
- teqeq r3, #0x80000000
- biceq xl, xl, #1
+ orrs lr, lr, r3, lsl #1
+ biceq xl, xl, r3, lsr #31
RETLDM "r4, r5, r6"
@ Shift value right of 32 to 64 bits, or 0 to 32 bits after a switch
@ from xh to xl. Leftover bits are in r3-r6-lr for rounding.
2: rsb r5, r4, #32
- mov r6, xl, lsl r5
+ orr lr, lr, xl, lsl r5
mov r3, xl, lsr r4
orr r3, r3, xh, lsl r5
mov xl, xh, lsr r4
bic xh, xh, #0x7fffffff
bic xl, xl, xh, lsr r4
add xl, xl, r3, lsr #31
- orrs r6, r6, lr
- teqeq r3, #0x80000000
- biceq xl, xl, #1
+ orrs lr, lr, r3, lsl #1
+ biceq xl, xl, r3, lsr #31
RETLDM "r4, r5, r6"
@ One or both arguments are denormalized.
@ Scale them leftwards and preserve sign bit.
LSYM(Lml_d):
- mov lr, #0
teq r4, #0
bne 2f
and r6, xh, #0x80000000
1: movs xl, xl, lsl #1
- adc xh, lr, xh, lsl #1
+ adc xh, xh, xh
tst xh, #0x00100000
- subeq r4, r4, #(1 << 19)
+ subeq r4, r4, #1
beq 1b
orr xh, xh, r6
teq r5, #0
- bne LSYM(Lml_x)
+ movne pc, lr
2: and r6, yh, #0x80000000
3: movs yl, yl, lsl #1
- adc yh, lr, yh, lsl #1
+ adc yh, yh, yh
tst yh, #0x00100000
- subeq r5, r5, #(1 << 20)
+ subeq r5, r5, #1
beq 3b
orr yh, yh, r6
- b LSYM(Lml_x)
+ mov pc, lr
- @ One or both args are INF or NAN.
LSYM(Lml_s):
+ @ Isolate the INF and NAN cases away
+ teq r4, ip
+ and r5, ip, yh, lsr #20
+ teqne r5, ip
+ beq 1f
+
+ @ Here, one or more arguments are either denormalized or zero.
+ orrs r6, xl, xh, lsl #1
+ orrnes r6, yl, yh, lsl #1
+ bne LSYM(Lml_d)
+
+ @ Result is 0, but determine sign anyway.
+LSYM(Lml_z):
+ eor xh, xh, yh
+ bic xh, xh, #0x7fffffff
+ mov xl, #0
+ RETLDM "r4, r5, r6"
+
+1: @ One or both args are INF or NAN.
orrs r6, xl, xh, lsl #1
+ moveq xl, yl
+ moveq xh, yh
orrnes r6, yl, yh, lsl #1
beq LSYM(Lml_n) @ 0 * INF or INF * 0 -> NAN
teq r4, ip
@@ -702,6 +806,8 @@ LSYM(Lml_s):
1: teq r5, ip
bne LSYM(Lml_i)
orrs r6, yl, yh, lsl #12
+ movne xl, yl
+ movne xh, yh
bne LSYM(Lml_n) @ <anything> * NAN -> NAN
@ Result is INF, but we need to determine its sign.
@@ -716,53 +822,45 @@ LSYM(Lml_o):
mov xl, #0
RETLDM "r4, r5, r6"
- @ Return NAN.
+ @ Return a quiet NAN.
LSYM(Lml_n):
- mov xh, #0x7f000000
+ orr xh, xh, #0x7f000000
orr xh, xh, #0x00f80000
RETLDM "r4, r5, r6"
+ FUNC_END aeabi_dmul
FUNC_END muldf3
ARM_FUNC_START divdf3
-
+ARM_FUNC_ALIAS aeabi_ddiv divdf3
+
stmfd sp!, {r4, r5, r6, lr}
- @ Mask out exponents.
- mov ip, #0x7f000000
- orr ip, ip, #0x00f00000
- and r4, xh, ip
- and r5, yh, ip
-
- @ Trap any INF/NAN or zeroes.
- teq r4, ip
+ @ Mask out exponents, trap any zero/denormal/INF/NAN.
+ mov ip, #0xff
+ orr ip, ip, #0x700
+ ands r4, ip, xh, lsr #20
+ andnes r5, ip, yh, lsr #20
+ teqne r4, ip
teqne r5, ip
- orrnes r6, xl, xh, lsl #1
- orrnes r6, yl, yh, lsl #1
- beq LSYM(Ldv_s)
+ bleq LSYM(Ldv_s)
- @ Shift exponents right one bit to make room for overflow bit.
- @ If either of them is 0, scale denormalized arguments off line.
- @ Then substract divisor exponent from dividend''s.
- movs r4, r4, lsr #1
- teqne r5, #0
- beq LSYM(Ldv_d)
-LSYM(Ldv_x):
- sub r4, r4, r5, asr #1
+ @ Substract divisor exponent from dividend''s.
+ sub r4, r4, r5
@ Preserve final sign into lr.
eor lr, xh, yh
@ Convert mantissa to unsigned integer.
@ Dividend -> r5-r6, divisor -> yh-yl.
- mov r5, #0x10000000
+ orrs r5, yl, yh, lsl #12
+ mov xh, xh, lsl #12
+ beq LSYM(Ldv_1)
mov yh, yh, lsl #12
+ mov r5, #0x10000000
orr yh, r5, yh, lsr #4
orr yh, yh, yl, lsr #24
- movs yl, yl, lsl #8
- mov xh, xh, lsl #12
- teqeq yh, r5
- beq LSYM(Ldv_1)
+ mov yl, yl, lsl #8
orr r5, r5, xh, lsr #4
orr r5, r5, xl, lsr #24
mov r6, xl, lsl #8
@@ -771,21 +869,15 @@ LSYM(Ldv_x):
and xh, lr, #0x80000000
@ Ensure result will land to known bit position.
+ @ Apply exponent bias accordingly.
cmp r5, yh
cmpeq r6, yl
+ adc r4, r4, #(255 - 2)
+ add r4, r4, #0x300
bcs 1f
- sub r4, r4, #(1 << 19)
movs yh, yh, lsr #1
mov yl, yl, rrx
1:
- @ Apply exponent bias, check range for over/underflow.
- add r4, r4, #0x1f000000
- add r4, r4, #0x00f80000
- cmn r4, #(53 << 19)
- ble LSYM(Ldv_z)
- cmp r4, ip, lsr #1
- bge LSYM(Lml_o)
-
@ Perform first substraction to align result to a nibble.
subs r6, r6, yl
sbc r5, r5, yh
@@ -847,73 +939,42 @@ LSYM(Ldv_x):
orreq xh, xh, xl
moveq xl, #0
3:
- @ Check if denormalized result is needed.
- cmp r4, #0
- ble LSYM(Ldv_u)
+ @ Check exponent range for under/overflow.
+ subs ip, r4, #(254 - 1)
+ cmphi ip, #0x700
+ bhi LSYM(Lml_u)
- @ Apply proper rounding.
+ @ Round the result, merge final exponent.
subs ip, r5, yh
subeqs ip, r6, yl
+ moveqs ip, xl, lsr #1
adcs xl, xl, #0
- adc xh, xh, #0
- teq ip, #0
- biceq xl, xl, #1
-
- @ Add exponent to result.
- bic xh, xh, #0x00100000
- orr xh, xh, r4, lsl #1
+ adc xh, xh, r4, lsl #20
RETLDM "r4, r5, r6"
@ Division by 0x1p*: shortcut a lot of code.
LSYM(Ldv_1):
and lr, lr, #0x80000000
orr xh, lr, xh, lsr #12
- add r4, r4, #0x1f000000
- add r4, r4, #0x00f80000
- cmp r4, ip, lsr #1
- bge LSYM(Lml_o)
- cmp r4, #0
- orrgt xh, xh, r4, lsl #1
+ adds r4, r4, ip, lsr #1
+ rsbgts r5, r4, ip
+ orrgt xh, xh, r4, lsl #20
RETLDM "r4, r5, r6" gt
- cmn r4, #(53 << 19)
- ble LSYM(Ldv_z)
orr xh, xh, #0x00100000
mov lr, #0
- b LSYM(Lml_r)
+ subs r4, r4, #1
+ b LSYM(Lml_u)
- @ Result must be denormalized: put remainder in lr for
- @ rounding considerations.
+ @ Result mightt need to be denormalized: put remainder bits
+ @ in lr for rounding considerations.
LSYM(Ldv_u):
orr lr, r5, r6
- b LSYM(Lml_r)
-
- @ One or both arguments are denormalized.
- @ Scale them leftwards and preserve sign bit.
-LSYM(Ldv_d):
- mov lr, #0
- teq r4, #0
- bne 2f
- and r6, xh, #0x80000000
-1: movs xl, xl, lsl #1
- adc xh, lr, xh, lsl #1
- tst xh, #0x00100000
- subeq r4, r4, #(1 << 19)
- beq 1b
- orr xh, xh, r6
- teq r5, #0
- bne LSYM(Ldv_x)
-2: and r6, yh, #0x80000000
-3: movs yl, yl, lsl #1
- adc yh, lr, yh, lsl #1
- tst yh, #0x00100000
- subeq r5, r5, #(1 << 20)
- beq 3b
- orr yh, yh, r6
- b LSYM(Ldv_x)
+ b LSYM(Lml_u)
@ One or both arguments is either INF, NAN or zero.
LSYM(Ldv_s):
+ and r5, ip, yh, lsr #20
teq r4, ip
teqeq r5, ip
beq LSYM(Lml_n) @ INF/NAN / INF/NAN -> NAN
@@ -921,25 +982,38 @@ LSYM(Ldv_s):
bne 1f
orrs r4, xl, xh, lsl #12
bne LSYM(Lml_n) @ NAN / <anything> -> NAN
- b LSYM(Lml_i) @ INF / <anything> -> INF
+ teq r5, ip
+ bne LSYM(Lml_i) @ INF / <anything> -> INF
+ mov xl, yl
+ mov xh, yh
+ b LSYM(Lml_n) @ INF / (INF or NAN) -> NAN
1: teq r5, ip
bne 2f
orrs r5, yl, yh, lsl #12
- bne LSYM(Lml_n) @ <anything> / NAN -> NAN
- b LSYM(Lml_z) @ <anything> / INF -> 0
-2: @ One or both arguments are 0.
+ beq LSYM(Lml_z) @ <anything> / INF -> 0
+ mov xl, yl
+ mov xh, yh
+ b LSYM(Lml_n) @ <anything> / NAN -> NAN
+2: @ If both are nonzero, we need to normalize and resume above.
+ orrs r6, xl, xh, lsl #1
+ orrnes r6, yl, yh, lsl #1
+ bne LSYM(Lml_d)
+ @ One or both arguments are 0.
orrs r4, xl, xh, lsl #1
bne LSYM(Lml_i) @ <non_zero> / 0 -> INF
orrs r5, yl, yh, lsl #1
bne LSYM(Lml_z) @ 0 / <non_zero> -> 0
b LSYM(Lml_n) @ 0 / 0 -> NAN
+ FUNC_END aeabi_ddiv
FUNC_END divdf3
#endif /* L_muldivdf3 */
#ifdef L_cmpdf2
+@ Note: only r0 (return value) and ip are clobbered here.
+
ARM_FUNC_START gtdf2
ARM_FUNC_ALIAS gedf2 gtdf2
mov ip, #-1
@@ -955,15 +1029,13 @@ ARM_FUNC_ALIAS nedf2 cmpdf2
ARM_FUNC_ALIAS eqdf2 cmpdf2
mov ip, #1 @ how should we specify unordered here?
-1: stmfd sp!, {r4, r5, lr}
+1: str ip, [sp, #-4]
@ Trap any INF/NAN first.
- mov lr, #0x7f000000
- orr lr, lr, #0x00f00000
- and r4, xh, lr
- and r5, yh, lr
- teq r4, lr
- teqne r5, lr
+ mov ip, xh, lsl #1
+ mvns ip, ip, asr #21
+ mov ip, yh, lsl #1
+ mvnnes ip, ip, asr #21
beq 3f
@ Test for equality.
@@ -973,37 +1045,37 @@ ARM_FUNC_ALIAS eqdf2 cmpdf2
teqne xh, yh @ or xh == yh
teqeq xl, yl @ and xl == yl
moveq r0, #0 @ then equal.
- RETLDM "r4, r5" eq
+ RETc(eq)
- @ Check for sign difference.
- teq xh, yh
- movmi r0, xh, asr #31
- orrmi r0, r0, #1
- RETLDM "r4, r5" mi
+ @ Clear C flag
+ cmn r0, #0
- @ Compare exponents.
- cmp r4, r5
+ @ Compare sign,
+ teq xh, yh
- @ Compare mantissa if exponents are equal.
- moveq xh, xh, lsl #12
- cmpeq xh, yh, lsl #12
+ @ Compare values if same sign
+ cmppl xh, yh
cmpeq xl, yl
+
+ @ Result:
movcs r0, yh, asr #31
mvncc r0, yh, asr #31
orr r0, r0, #1
- RETLDM "r4, r5"
+ RET
@ Look for a NAN.
-3: teq r4, lr
+3: mov ip, xh, lsl #1
+ mvns ip, ip, asr #21
bne 4f
- orrs xl, xl, xh, lsl #12
+ orrs ip, xl, xh, lsl #12
bne 5f @ x is NAN
-4: teq r5, lr
+4: mov ip, yh, lsl #1
+ mvns ip, ip, asr #21
bne 2b
- orrs yl, yl, yh, lsl #12
+ orrs ip, yl, yh, lsl #12
beq 2b @ y is not NAN
-5: mov r0, ip @ return unordered code from ip
- RETLDM "r4, r5"
+5: ldr r0, [sp, #-4] @ unordered return code
+ RET
FUNC_END gedf2
FUNC_END gtdf2
@@ -1013,30 +1085,109 @@ ARM_FUNC_ALIAS eqdf2 cmpdf2
FUNC_END eqdf2
FUNC_END cmpdf2
+ARM_FUNC_START aeabi_cdrcmple
+
+ mov ip, r0
+ mov r0, r2
+ mov r2, ip
+ mov ip, r1
+ mov r1, r3
+ mov r3, ip
+ b 6f
+
+ARM_FUNC_START aeabi_cdcmpeq
+ARM_FUNC_ALIAS aeabi_cdcmple aeabi_cdcmpeq
+
+ @ The status-returning routines are required to preserve all
+ @ registers except ip, lr, and cpsr.
+6: stmfd sp!, {r0, lr}
+ ARM_CALL cmpdf2
+ @ Set the Z flag correctly, and the C flag unconditionally.
+ cmp r0, #0
+ @ Clear the C flag if the return value was -1, indicating
+ @ that the first operand was smaller than the second.
+ cmnmi r0, #0
+ RETLDM "r0"
+
+ FUNC_END aeabi_cdcmple
+ FUNC_END aeabi_cdcmpeq
+ FUNC_END aeabi_cdrcmple
+
+ARM_FUNC_START aeabi_dcmpeq
+
+ str lr, [sp, #-8]!
+ ARM_CALL aeabi_cdcmple
+ moveq r0, #1 @ Equal to.
+ movne r0, #0 @ Less than, greater than, or unordered.
+ RETLDM
+
+ FUNC_END aeabi_dcmpeq
+
+ARM_FUNC_START aeabi_dcmplt
+
+ str lr, [sp, #-8]!
+ ARM_CALL aeabi_cdcmple
+ movcc r0, #1 @ Less than.
+ movcs r0, #0 @ Equal to, greater than, or unordered.
+ RETLDM
+
+ FUNC_END aeabi_dcmplt
+
+ARM_FUNC_START aeabi_dcmple
+
+ str lr, [sp, #-8]!
+ ARM_CALL aeabi_cdcmple
+ movls r0, #1 @ Less than or equal to.
+ movhi r0, #0 @ Greater than or unordered.
+ RETLDM
+
+ FUNC_END aeabi_dcmple
+
+ARM_FUNC_START aeabi_dcmpge
+
+ str lr, [sp, #-8]!
+ ARM_CALL aeabi_cdrcmple
+ movls r0, #1 @ Operand 2 is less than or equal to operand 1.
+ movhi r0, #0 @ Operand 2 greater than operand 1, or unordered.
+ RETLDM
+
+ FUNC_END aeabi_dcmpge
+
+ARM_FUNC_START aeabi_dcmpgt
+
+ str lr, [sp, #-8]!
+ ARM_CALL aeabi_cdrcmple
+ movcc r0, #1 @ Operand 2 is less than operand 1.
+ movcs r0, #0 @ Operand 2 is greater than or equal to operand 1,
+ @ or they are unordered.
+ RETLDM
+
+ FUNC_END aeabi_dcmpgt
+
#endif /* L_cmpdf2 */
#ifdef L_unorddf2
ARM_FUNC_START unorddf2
- str lr, [sp, #-4]!
- mov ip, #0x7f000000
- orr ip, ip, #0x00f00000
- and lr, xh, ip
- teq lr, ip
+ARM_FUNC_ALIAS aeabi_dcmpun unorddf2
+
+ mov ip, xh, lsl #1
+ mvns ip, ip, asr #21
bne 1f
- orrs xl, xl, xh, lsl #12
+ orrs ip, xl, xh, lsl #12
bne 3f @ x is NAN
-1: and lr, yh, ip
- teq lr, ip
+1: mov ip, yh, lsl #1
+ mvns ip, ip, asr #21
bne 2f
- orrs yl, yl, yh, lsl #12
+ orrs ip, yl, yh, lsl #12
bne 3f @ y is NAN
2: mov r0, #0 @ arguments are ordered.
- RETLDM
+ RET
3: mov r0, #1 @ arguments are unordered.
- RETLDM
+ RET
+ FUNC_END aeabi_dcmpun
FUNC_END unorddf2
#endif /* L_unorddf2 */
@@ -1044,31 +1195,23 @@ ARM_FUNC_START unorddf2
#ifdef L_fixdfsi
ARM_FUNC_START fixdfsi
- orrs ip, xl, xh, lsl #1
- beq 1f @ value is 0.
-
- mov r3, r3, rrx @ preserve C flag (the actual sign)
+ARM_FUNC_ALIAS aeabi_d2iz fixdfsi
@ check exponent range.
- mov ip, #0x7f000000
- orr ip, ip, #0x00f00000
- and r2, xh, ip
- teq r2, ip
- beq 2f @ value is INF or NAN
- bic ip, ip, #0x40000000
- cmp r2, ip
- bcc 1f @ value is too small
- add ip, ip, #(31 << 20)
- cmp r2, ip
- bcs 3f @ value is too large
-
- rsb r2, r2, ip
- mov ip, xh, lsl #11
- orr ip, ip, #0x80000000
- orr ip, ip, xl, lsr #21
- mov r2, r2, lsr #20
- tst r3, #0x80000000 @ the sign bit
- mov r0, ip, lsr r2
+ mov r2, xh, lsl #1
+ adds r2, r2, #(1 << 21)
+ bcs 2f @ value is INF or NAN
+ bpl 1f @ value is too small
+ mov r3, #(0xfffffc00 + 31)
+ subs r2, r3, r2, asr #21
+ bls 3f @ value is too large
+
+ @ scale value
+ mov r3, xh, lsl #11
+ orr r3, r3, #0x80000000
+ orr r3, r3, xl, lsr #21
+ tst xh, #0x80000000 @ the sign bit
+ mov r0, r3, lsr r2
rsbne r0, r0, #0
RET
@@ -1076,14 +1219,15 @@ ARM_FUNC_START fixdfsi
RET
2: orrs xl, xl, xh, lsl #12
- bne 4f @ r0 is NAN.
-3: ands r0, r3, #0x80000000 @ the sign bit
+ bne 4f @ x is NAN.
+3: ands r0, xh, #0x80000000 @ the sign bit
moveq r0, #0x7fffffff @ maximum signed positive si
RET
4: mov r0, #0 @ How should we convert NAN?
RET
+ FUNC_END aeabi_d2iz
FUNC_END fixdfsi
#endif /* L_fixdfsi */
@@ -1091,29 +1235,23 @@ ARM_FUNC_START fixdfsi
#ifdef L_fixunsdfsi
ARM_FUNC_START fixunsdfsi
- orrs ip, xl, xh, lsl #1
- movcss r0, #0 @ value is negative
- RETc(eq) @ or 0 (xl, xh overlap r0)
+ARM_FUNC_ALIAS aeabi_d2uiz fixunsdfsi
@ check exponent range.
- mov ip, #0x7f000000
- orr ip, ip, #0x00f00000
- and r2, xh, ip
- teq r2, ip
- beq 2f @ value is INF or NAN
- bic ip, ip, #0x40000000
- cmp r2, ip
- bcc 1f @ value is too small
- add ip, ip, #(31 << 20)
- cmp r2, ip
- bhi 3f @ value is too large
-
- rsb r2, r2, ip
- mov ip, xh, lsl #11
- orr ip, ip, #0x80000000
- orr ip, ip, xl, lsr #21
- mov r2, r2, lsr #20
- mov r0, ip, lsr r2
+ movs r2, xh, lsl #1
+ bcs 1f @ value is negative
+ adds r2, r2, #(1 << 21)
+ bcs 2f @ value is INF or NAN
+ bpl 1f @ value is too small
+ mov r3, #(0xfffffc00 + 31)
+ subs r2, r3, r2, asr #21
+ bmi 3f @ value is too large
+
+ @ scale value
+ mov r3, xh, lsl #11
+ orr r3, r3, #0x80000000
+ orr r3, r3, xl, lsr #21
+ mov r0, r3, lsr r2
RET
1: mov r0, #0
@@ -1127,6 +1265,7 @@ ARM_FUNC_START fixunsdfsi
4: mov r0, #0 @ How should we convert NAN?
RET
+ FUNC_END aeabi_d2uiz
FUNC_END fixunsdfsi
#endif /* L_fixunsdfsi */
@@ -1134,91 +1273,63 @@ ARM_FUNC_START fixunsdfsi
#ifdef L_truncdfsf2
ARM_FUNC_START truncdfsf2
- orrs r2, xl, xh, lsl #1
- moveq r0, r2, rrx
- RETc(eq) @ value is 0.0 or -0.0
-
+ARM_FUNC_ALIAS aeabi_d2f truncdfsf2
+
@ check exponent range.
- mov ip, #0x7f000000
- orr ip, ip, #0x00f00000
- and r2, ip, xh
- teq r2, ip
- beq 2f @ value is INF or NAN
- bic xh, xh, ip
- cmp r2, #(0x380 << 20)
- bls 4f @ value is too small
-
- @ shift and round mantissa
-1: movs r3, xl, lsr #29
- adc r3, r3, xh, lsl #3
-
- @ if halfway between two numbers, round towards LSB = 0.
- mov xl, xl, lsl #3
- teq xl, #0x80000000
- biceq r3, r3, #1
-
- @ rounding might have created an extra MSB. If so adjust exponent.
- tst r3, #0x00800000
- addne r2, r2, #(1 << 20)
- bicne r3, r3, #0x00800000
-
- @ check exponent for overflow
- mov ip, #(0x400 << 20)
- orr ip, ip, #(0x07f << 20)
- cmp r2, ip
- bcs 3f @ overflow
-
- @ adjust exponent, merge with sign bit and mantissa.
- movs xh, xh, lsl #1
- mov r2, r2, lsl #4
- orr r0, r3, r2, rrx
- eor r0, r0, #0x40000000
+ mov r2, xh, lsl #1
+ subs r3, r2, #((1023 - 127) << 21)
+ subcss ip, r3, #(1 << 21)
+ rsbcss ip, ip, #(254 << 21)
+ bls 2f @ value is out of range
+
+1: @ shift and round mantissa
+ and ip, xh, #0x80000000
+ mov r2, xl, lsl #3
+ orr xl, ip, xl, lsr #29
+ cmp r2, #0x80000000
+ adc r0, xl, r3, lsl #2
+ biceq r0, r0, #1
RET
-2: @ chech for NAN
- orrs xl, xl, xh, lsl #12
- movne r0, #0x7f000000
- orrne r0, r0, #0x00c00000
- RETc(ne) @ return NAN
+2: @ either overflow or underflow
+ tst xh, #0x40000000
+ bne 3f @ overflow
-3: @ return INF with sign
- and r0, xh, #0x80000000
- orr r0, r0, #0x7f000000
- orr r0, r0, #0x00800000
- RET
+ @ check if denormalized value is possible
+ adds r2, r3, #(23 << 21)
+ andlt r0, xh, #0x80000000 @ too small, return signed 0.
+ RETc(lt)
-4: @ check if denormalized value is possible
- subs r2, r2, #((0x380 - 24) << 20)
- andle r0, xh, #0x80000000 @ too small, return signed 0.
- RETc(le)
-
@ denormalize value so we can resume with the code above afterwards.
orr xh, xh, #0x00100000
- mov r2, r2, lsr #20
- rsb r2, r2, #25
- cmp r2, #20
- bgt 6f
-
+ mov r2, r2, lsr #21
+ rsb r2, r2, #24
rsb ip, r2, #32
- mov r3, xl, lsl ip
+ movs r3, xl, lsl ip
mov xl, xl, lsr r2
- orr xl, xl, xh, lsl ip
- movs xh, xh, lsl #1
- mov xh, xh, lsr r2
- mov xh, xh, rrx
-5: teq r3, #0 @ fold r3 bits into the LSB
- orrne xl, xl, #1 @ for rounding considerations.
- mov r2, #(0x380 << 20) @ equivalent to the 0 float exponent
+ orrne xl, xl, #1 @ fold r3 for rounding considerations.
+ mov r3, xh, lsl #11
+ mov r3, r3, lsr #11
+ orr xl, xl, r3, lsl ip
+ mov r3, r3, lsr r2
+ mov r3, r3, lsl #1
b 1b
-6: rsb r2, r2, #(12 + 20)
- rsb ip, r2, #32
- mov r3, xl, lsl r2
- mov xl, xl, lsr ip
- orr xl, xl, xh, lsl r2
- and xh, xh, #0x80000000
- b 5b
+3: @ chech for NAN
+ mvns r3, r2, asr #21
+ bne 5f @ simple overflow
+ orrs r3, xl, xh, lsl #12
+ movne r0, #0x7f000000
+ orrne r0, r0, #0x00c00000
+ RETc(ne) @ return NAN
+
+5: @ return INF with sign
+ and r0, xh, #0x80000000
+ orr r0, r0, #0x7f000000
+ orr r0, r0, #0x00800000
+ RET
+ FUNC_END aeabi_d2f
FUNC_END truncdfsf2
#endif /* L_truncdfsf2 */
diff --git a/contrib/gcc/config/arm/ieee754-sf.S b/contrib/gcc/config/arm/ieee754-sf.S
index 5c97245..f74f458 100644
--- a/contrib/gcc/config/arm/ieee754-sf.S
+++ b/contrib/gcc/config/arm/ieee754-sf.S
@@ -1,6 +1,6 @@
/* ieee754-sf.S single-precision floating point support for ARM
- Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
Contributed by Nicolas Pitre (nico@cam.org)
This file is free software; you can redistribute it and/or modify it
@@ -24,8 +24,8 @@
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/*
* Notes:
@@ -41,48 +41,46 @@
#ifdef L_negsf2
ARM_FUNC_START negsf2
+ARM_FUNC_ALIAS aeabi_fneg negsf2
+
eor r0, r0, #0x80000000 @ flip sign bit
RET
+ FUNC_END aeabi_fneg
FUNC_END negsf2
#endif
#ifdef L_addsubsf3
+ARM_FUNC_START aeabi_frsub
+
+ eor r0, r0, #0x80000000 @ flip sign bit of first arg
+ b 1f
+
ARM_FUNC_START subsf3
+ARM_FUNC_ALIAS aeabi_fsub subsf3
+
eor r1, r1, #0x80000000 @ flip sign bit of second arg
-#if defined(__thumb__) && !defined(__THUMB_INTERWORK__)
+#if defined(__INTERWORKING_STUBS__)
b 1f @ Skip Thumb-code prologue
#endif
ARM_FUNC_START addsf3
+ARM_FUNC_ALIAS aeabi_fadd addsf3
-1: @ Compare both args, return zero if equal but the sign.
- eor r2, r0, r1
- teq r2, #0x80000000
- beq LSYM(Lad_z)
-
- @ If first arg is 0 or -0, return second arg.
- @ If second arg is 0 or -0, return first arg.
- bics r2, r0, #0x80000000
- moveq r0, r1
- bicnes r2, r1, #0x80000000
- RETc(eq)
-
- @ Mask out exponents.
- mov ip, #0xff000000
- and r2, r0, ip, lsr #1
- and r3, r1, ip, lsr #1
-
- @ If either of them is 255, result will be INF or NAN
- teq r2, ip, lsr #1
- teqne r3, ip, lsr #1
- beq LSYM(Lad_i)
+1: @ Look for zeroes, equal values, INF, or NAN.
+ movs r2, r0, lsl #1
+ movnes r3, r1, lsl #1
+ teqne r2, r3
+ mvnnes ip, r2, asr #24
+ mvnnes ip, r3, asr #24
+ beq LSYM(Lad_s)
@ Compute exponent difference. Make largest exponent in r2,
@ corresponding arg in r0, and positive exponent difference in r3.
- subs r3, r3, r2
+ mov r2, r2, lsr #24
+ rsbs r3, r2, r3, lsr #24
addgt r2, r2, r3
eorgt r1, r0, r1
eorgt r0, r1, r0
@@ -92,7 +90,7 @@ ARM_FUNC_START addsf3
@ If exponent difference is too large, return largest argument
@ already in r0. We need up to 25 bit to handle proper rounding
@ of 0x1p25 - 1.1.
- cmp r3, #(25 << 23)
+ cmp r3, #25
RETc(hi)
@ Convert mantissa to signed integer.
@@ -111,25 +109,17 @@ ARM_FUNC_START addsf3
beq LSYM(Lad_d)
LSYM(Lad_x):
- @ Scale down second arg with exponent difference.
- @ Apply shift one bit left to first arg and the rest to second arg
- @ to simplify things later, but only if exponent does not become 0.
- movs r3, r3, lsr #23
- teqne r2, #(1 << 23)
- movne r0, r0, lsl #1
- subne r2, r2, #(1 << 23)
- subne r3, r3, #1
+ @ Compensate for the exponent overlapping the mantissa MSB added later
+ sub r2, r2, #1
- @ Shift second arg into ip, keep leftover bits into r1.
- mov ip, r1, asr r3
+ @ Shift and add second arg to first arg in r0.
+ @ Keep leftover bits into r1.
+ adds r0, r0, r1, asr r3
rsb r3, r3, #32
mov r1, r1, lsl r3
- add r0, r0, ip @ the actual addition
-
- @ We now have a 64 bit result in r0-r1.
- @ Keep absolute value in r0-r1, sign in r3.
- ands r3, r0, #0x80000000
+ @ Keep absolute value in r0-r1, sign in r3 (the n bit was set above)
+ and r3, r0, #0x80000000
bpl LSYM(Lad_p)
rsbs r1, r1, #0
rsc r0, r0, #0
@@ -137,103 +127,117 @@ LSYM(Lad_x):
@ Determine how to normalize the result.
LSYM(Lad_p):
cmp r0, #0x00800000
- bcc LSYM(Lad_l)
+ bcc LSYM(Lad_a)
cmp r0, #0x01000000
- bcc LSYM(Lad_r0)
- cmp r0, #0x02000000
- bcc LSYM(Lad_r1)
+ bcc LSYM(Lad_e)
@ Result needs to be shifted right.
movs r0, r0, lsr #1
mov r1, r1, rrx
- add r2, r2, #(1 << 23)
-LSYM(Lad_r1):
- movs r0, r0, lsr #1
- mov r1, r1, rrx
- add r2, r2, #(1 << 23)
-
- @ Our result is now properly aligned into r0, remaining bits in r1.
- @ Round with MSB of r1. If halfway between two numbers, round towards
- @ LSB of r0 = 0.
-LSYM(Lad_r0):
- add r0, r0, r1, lsr #31
- teq r1, #0x80000000
- biceq r0, r0, #1
-
- @ Rounding may have added a new MSB. Adjust exponent.
- @ That MSB will be cleared when exponent is merged below.
- tst r0, #0x01000000
- addne r2, r2, #(1 << 23)
+ add r2, r2, #1
@ Make sure we did not bust our exponent.
- cmp r2, #(254 << 23)
- bhi LSYM(Lad_o)
+ cmp r2, #254
+ bhs LSYM(Lad_o)
+ @ Our result is now properly aligned into r0, remaining bits in r1.
@ Pack final result together.
+ @ Round with MSB of r1. If halfway between two numbers, round towards
+ @ LSB of r0 = 0.
LSYM(Lad_e):
- bic r0, r0, #0x01800000
- orr r0, r0, r2
+ cmp r1, #0x80000000
+ adc r0, r0, r2, lsl #23
+ biceq r0, r0, #1
orr r0, r0, r3
RET
- @ Result must be shifted left.
- @ No rounding necessary since r1 will always be 0.
+ @ Result must be shifted left and exponent adjusted.
+LSYM(Lad_a):
+ movs r1, r1, lsl #1
+ adc r0, r0, r0
+ tst r0, #0x00800000
+ sub r2, r2, #1
+ bne LSYM(Lad_e)
+
+ @ No rounding necessary since r1 will always be 0 at this point.
LSYM(Lad_l):
#if __ARM_ARCH__ < 5
movs ip, r0, lsr #12
moveq r0, r0, lsl #12
- subeq r2, r2, #(12 << 23)
+ subeq r2, r2, #12
tst r0, #0x00ff0000
moveq r0, r0, lsl #8
- subeq r2, r2, #(8 << 23)
+ subeq r2, r2, #8
tst r0, #0x00f00000
moveq r0, r0, lsl #4
- subeq r2, r2, #(4 << 23)
+ subeq r2, r2, #4
tst r0, #0x00c00000
moveq r0, r0, lsl #2
- subeq r2, r2, #(2 << 23)
- tst r0, #0x00800000
- moveq r0, r0, lsl #1
- subeq r2, r2, #(1 << 23)
- cmp r2, #0
- bgt LSYM(Lad_e)
+ subeq r2, r2, #2
+ cmp r0, #0x00800000
+ movcc r0, r0, lsl #1
+ sbcs r2, r2, #0
#else
clz ip, r0
sub ip, ip, #8
+ subs r2, r2, ip
mov r0, r0, lsl ip
- subs r2, r2, ip, lsl #23
- bgt LSYM(Lad_e)
#endif
- @ Exponent too small, denormalize result.
- mvn r2, r2, asr #23
- add r2, r2, #2
- orr r0, r3, r0, lsr r2
+ @ Final result with sign
+ @ If exponent negative, denormalize result.
+ addge r0, r0, r2, lsl #23
+ rsblt r2, r2, #0
+ orrge r0, r0, r3
+ orrlt r0, r3, r0, lsr r2
RET
@ Fixup and adjust bit position for denormalized arguments.
@ Note that r2 must not remain equal to 0.
LSYM(Lad_d):
teq r2, #0
- eoreq r0, r0, #0x00800000
- addeq r2, r2, #(1 << 23)
eor r1, r1, #0x00800000
- subne r3, r3, #(1 << 23)
+ eoreq r0, r0, #0x00800000
+ addeq r2, r2, #1
+ subne r3, r3, #1
b LSYM(Lad_x)
- @ Result is x - x = 0, unless x is INF or NAN.
-LSYM(Lad_z):
- mov ip, #0xff000000
- and r2, r0, ip, lsr #1
- teq r2, ip, lsr #1
- moveq r0, ip, asr #2
+LSYM(Lad_s):
+ mov r3, r1, lsl #1
+
+ mvns ip, r2, asr #24
+ mvnnes ip, r3, asr #24
+ beq LSYM(Lad_i)
+
+ teq r2, r3
+ beq 1f
+
+ @ Result is x + 0.0 = x or 0.0 + y = y.
+ teq r2, #0
+ moveq r0, r1
+ RET
+
+1: teq r0, r1
+
+ @ Result is x - x = 0.
movne r0, #0
+ RETc(ne)
+
+ @ Result is x + x = 2x.
+ tst r2, #0xff000000
+ bne 2f
+ movs r0, r0, lsl #1
+ orrcs r0, r0, #0x80000000
RET
+2: adds r2, r2, #(2 << 24)
+ addcc r0, r0, #(1 << 23)
+ RETc(cc)
+ and r3, r0, #0x80000000
@ Overflow: return INF.
LSYM(Lad_o):
@@ -246,191 +250,271 @@ LSYM(Lad_o):
@ if r1 != INF/NAN: return r0 (which is INF/NAN)
@ if r0 or r1 is NAN: return NAN
@ if opposite sign: return NAN
- @ return r0 (which is INF or -INF)
+ @ otherwise return r0 (which is INF or -INF)
LSYM(Lad_i):
- teq r2, ip, lsr #1
+ mvns r2, r2, asr #24
movne r0, r1
- teqeq r3, ip, lsr #1
- RETc(ne)
+ mvneqs r3, r3, asr #24
+ movne r1, r0
movs r2, r0, lsl #9
- moveqs r2, r1, lsl #9
+ moveqs r3, r1, lsl #9
teqeq r0, r1
- orrne r0, r3, #0x00400000 @ NAN
+ orrne r0, r0, #0x00400000 @ quiet NAN
RET
+ FUNC_END aeabi_frsub
+ FUNC_END aeabi_fadd
FUNC_END addsf3
+ FUNC_END aeabi_fsub
FUNC_END subsf3
ARM_FUNC_START floatunsisf
+ARM_FUNC_ALIAS aeabi_ui2f floatunsisf
+
mov r3, #0
b 1f
ARM_FUNC_START floatsisf
+ARM_FUNC_ALIAS aeabi_i2f floatsisf
+
ands r3, r0, #0x80000000
rsbmi r0, r0, #0
-1: teq r0, #0
+1: movs ip, r0
RETc(eq)
- mov r1, #0
- mov r2, #((127 + 23) << 23)
- tst r0, #0xfc000000
- beq LSYM(Lad_p)
-
- @ We need to scale the value a little before branching to code above.
- tst r0, #0xf0000000
- movne r1, r0, lsl #28
- movne r0, r0, lsr #4
- addne r2, r2, #(4 << 23)
- tst r0, #0x0c000000
- beq LSYM(Lad_p)
- mov r1, r1, lsr #2
- orr r1, r1, r0, lsl #30
- mov r0, r0, lsr #2
- add r2, r2, #(2 << 23)
- b LSYM(Lad_p)
+ @ Add initial exponent to sign
+ orr r3, r3, #((127 + 23) << 23)
+ .ifnc ah, r0
+ mov ah, r0
+ .endif
+ mov al, #0
+ b 2f
+
+ FUNC_END aeabi_i2f
FUNC_END floatsisf
+ FUNC_END aeabi_ui2f
FUNC_END floatunsisf
+ARM_FUNC_START floatundisf
+ARM_FUNC_ALIAS aeabi_ul2f floatundisf
+
+ orrs r2, r0, r1
+#if !defined (__VFP_FP__) && !defined(__SOFTFP__)
+ mvfeqs f0, #0.0
+#endif
+ RETc(eq)
+
+ mov r3, #0
+ b 1f
+
+ARM_FUNC_START floatdisf
+ARM_FUNC_ALIAS aeabi_l2f floatdisf
+
+ orrs r2, r0, r1
+#if !defined (__VFP_FP__) && !defined(__SOFTFP__)
+ mvfeqs f0, #0.0
+#endif
+ RETc(eq)
+
+ ands r3, ah, #0x80000000 @ sign bit in r3
+ bpl 1f
+ rsbs al, al, #0
+ rsc ah, ah, #0
+1:
+#if !defined (__VFP_FP__) && !defined(__SOFTFP__)
+ @ For hard FPA code we want to return via the tail below so that
+ @ we can return the result in f0 as well as in r0 for backwards
+ @ compatibility.
+ str lr, [sp, #-8]!
+ adr lr, LSYM(f0_ret)
+#endif
+
+ movs ip, ah
+ moveq ip, al
+ moveq ah, al
+ moveq al, #0
+
+ @ Add initial exponent to sign
+ orr r3, r3, #((127 + 23 + 32) << 23)
+ subeq r3, r3, #(32 << 23)
+2: sub r3, r3, #(1 << 23)
+
+#if __ARM_ARCH__ < 5
+
+ mov r2, #23
+ cmp ip, #(1 << 16)
+ movhs ip, ip, lsr #16
+ subhs r2, r2, #16
+ cmp ip, #(1 << 8)
+ movhs ip, ip, lsr #8
+ subhs r2, r2, #8
+ cmp ip, #(1 << 4)
+ movhs ip, ip, lsr #4
+ subhs r2, r2, #4
+ cmp ip, #(1 << 2)
+ subhs r2, r2, #2
+ sublo r2, r2, ip, lsr #1
+ subs r2, r2, ip, lsr #3
+
+#else
+
+ clz r2, ip
+ subs r2, r2, #8
+
+#endif
+
+ sub r3, r3, r2, lsl #23
+ blt 3f
+
+ add r3, r3, ah, lsl r2
+ mov ip, al, lsl r2
+ rsb r2, r2, #32
+ cmp ip, #0x80000000
+ adc r0, r3, al, lsr r2
+ biceq r0, r0, #1
+ RET
+
+3: add r2, r2, #32
+ mov ip, ah, lsl r2
+ rsb r2, r2, #32
+ orrs al, al, ip, lsl #1
+ adc r0, r3, ah, lsr r2
+ biceq r0, r0, ip, lsr #31
+ RET
+
+#if !defined (__VFP_FP__) && !defined(__SOFTFP__)
+
+LSYM(f0_ret):
+ str r0, [sp, #-4]!
+ ldfs f0, [sp], #4
+ RETLDM
+
+#endif
+
+ FUNC_END floatdisf
+ FUNC_END aeabi_l2f
+ FUNC_END floatundisf
+ FUNC_END aeabi_ul2f
+
#endif /* L_addsubsf3 */
#ifdef L_muldivsf3
ARM_FUNC_START mulsf3
-
- @ Mask out exponents.
- mov ip, #0xff000000
- and r2, r0, ip, lsr #1
- and r3, r1, ip, lsr #1
-
- @ Trap any INF/NAN.
- teq r2, ip, lsr #1
- teqne r3, ip, lsr #1
+ARM_FUNC_ALIAS aeabi_fmul mulsf3
+
+ @ Mask out exponents, trap any zero/denormal/INF/NAN.
+ mov ip, #0xff
+ ands r2, ip, r0, lsr #23
+ andnes r3, ip, r1, lsr #23
+ teqne r2, ip
+ teqne r3, ip
beq LSYM(Lml_s)
-
- @ Trap any multiplication by 0.
- bics ip, r0, #0x80000000
- bicnes ip, r1, #0x80000000
- beq LSYM(Lml_z)
-
- @ Shift exponents right one bit to make room for overflow bit.
- @ If either of them is 0, scale denormalized arguments off line.
- @ Then add both exponents together.
- movs r2, r2, lsr #1
- teqne r3, #0
- beq LSYM(Lml_d)
LSYM(Lml_x):
- add r2, r2, r3, asr #1
- @ Preserve final sign in r2 along with exponent for now.
- teq r0, r1
- orrmi r2, r2, #0x8000
+ @ Add exponents together
+ add r2, r2, r3
+
+ @ Determine final sign.
+ eor ip, r0, r1
@ Convert mantissa to unsigned integer.
- bic r0, r0, #0xff000000
- bic r1, r1, #0xff000000
- orr r0, r0, #0x00800000
- orr r1, r1, #0x00800000
+ @ If power of two, branch to a separate path.
+ @ Make up for final alignment.
+ movs r0, r0, lsl #9
+ movnes r1, r1, lsl #9
+ beq LSYM(Lml_1)
+ mov r3, #0x08000000
+ orr r0, r3, r0, lsr #5
+ orr r1, r3, r1, lsr #5
#if __ARM_ARCH__ < 4
+ @ Put sign bit in r3, which will be restored into r0 later.
+ and r3, ip, #0x80000000
+
@ Well, no way to make it shorter without the umull instruction.
- @ We must perform that 24 x 24 -> 48 bit multiplication by hand.
- stmfd sp!, {r4, r5}
+ stmfd sp!, {r3, r4, r5}
mov r4, r0, lsr #16
mov r5, r1, lsr #16
- bic r0, r0, #0x00ff0000
- bic r1, r1, #0x00ff0000
+ bic r0, r0, r4, lsl #16
+ bic r1, r1, r5, lsl #16
mul ip, r4, r5
mul r3, r0, r1
mul r0, r5, r0
mla r0, r4, r1, r0
adds r3, r3, r0, lsl #16
- adc ip, ip, r0, lsr #16
- ldmfd sp!, {r4, r5}
+ adc r1, ip, r0, lsr #16
+ ldmfd sp!, {r0, r4, r5}
#else
- umull r3, ip, r0, r1 @ The actual multiplication.
+ @ The actual multiplication.
+ umull r3, r1, r0, r1
+
+ @ Put final sign in r0.
+ and r0, ip, #0x80000000
#endif
- @ Put final sign in r0.
- mov r0, r2, lsl #16
- bic r2, r2, #0x8000
-
- @ Adjust result if one extra MSB appeared.
- @ The LSB may be lost but this never changes the result in this case.
- tst ip, #(1 << 15)
- addne r2, r2, #(1 << 22)
- movnes ip, ip, lsr #1
- movne r3, r3, rrx
-
- @ Apply exponent bias, check range for underflow.
- subs r2, r2, #(127 << 22)
- ble LSYM(Lml_u)
-
- @ Scale back to 24 bits with rounding.
- @ r0 contains sign bit already.
- orrs r0, r0, r3, lsr #23
- adc r0, r0, ip, lsl #9
-
- @ If halfway between two numbers, rounding should be towards LSB = 0.
- mov r3, r3, lsl #9
- teq r3, #0x80000000
- biceq r0, r0, #1
+ @ Adjust result upon the MSB position.
+ cmp r1, #(1 << 23)
+ movcc r1, r1, lsl #1
+ orrcc r1, r1, r3, lsr #31
+ movcc r3, r3, lsl #1
- @ Note: rounding may have produced an extra MSB here.
- @ The extra bit is cleared before merging the exponent below.
- tst r0, #0x01000000
- addne r2, r2, #(1 << 22)
+ @ Add sign to result.
+ orr r0, r0, r1
- @ Check for exponent overflow
- cmp r2, #(255 << 22)
- bge LSYM(Lml_o)
+ @ Apply exponent bias, check for under/overflow.
+ sbc r2, r2, #127
+ cmp r2, #(254 - 1)
+ bhi LSYM(Lml_u)
- @ Add final exponent.
- bic r0, r0, #0x01800000
- orr r0, r0, r2, lsl #1
+ @ Round the result, merge final exponent.
+ cmp r3, #0x80000000
+ adc r0, r0, r2, lsl #23
+ biceq r0, r0, #1
RET
- @ Result is 0, but determine sign anyway.
-LSYM(Lml_z):
- eor r0, r0, r1
- bic r0, r0, #0x7fffffff
- RET
+ @ Multiplication by 0x1p*: let''s shortcut a lot of code.
+LSYM(Lml_1):
+ teq r0, #0
+ and ip, ip, #0x80000000
+ moveq r1, r1, lsl #9
+ orr r0, ip, r0, lsr #9
+ orr r0, r0, r1, lsr #9
+ subs r2, r2, #127
+ rsbgts r3, r2, #255
+ orrgt r0, r0, r2, lsl #23
+ RETc(gt)
+
+ @ Under/overflow: fix things up for the code below.
+ orr r0, r0, #0x00800000
+ mov r3, #0
+ subs r2, r2, #1
- @ Check if denormalized result is possible, otherwise return signed 0.
LSYM(Lml_u):
- cmn r2, #(24 << 22)
- RETc(le)
+ @ Overflow?
+ bgt LSYM(Lml_o)
- @ Find out proper shift value.
- mvn r1, r2, asr #22
- subs r1, r1, #7
- bgt LSYM(Lml_ur)
-
- @ Shift value left, round, etc.
- add r1, r1, #32
- orrs r0, r0, r3, lsr r1
- rsb r1, r1, #32
- adc r0, r0, ip, lsl r1
- mov ip, r3, lsl r1
- teq ip, #0x80000000
- biceq r0, r0, #1
- RET
+ @ Check if denormalized result is possible, otherwise return signed 0.
+ cmn r2, #(24 + 1)
+ bicle r0, r0, #0x7fffffff
+ RETc(le)
@ Shift value right, round, etc.
- @ Note: r1 must not be 0 otherwise carry does not get set.
-LSYM(Lml_ur):
- orrs r0, r0, ip, lsr r1
+ rsb r2, r2, #0
+ movs r1, r0, lsl #1
+ mov r1, r1, lsr r2
+ rsb r2, r2, #32
+ mov ip, r0, lsl r2
+ movs r0, r1, rrx
adc r0, r0, #0
- rsb r1, r1, #32
- mov ip, ip, lsl r1
- teq r3, #0
- teqeq ip, #0x80000000
- biceq r0, r0, #1
+ orrs r3, r3, ip, lsl #1
+ biceq r0, r0, ip, lsr #31
RET
@ One or both arguments are denormalized.
@@ -440,32 +524,51 @@ LSYM(Lml_d):
and ip, r0, #0x80000000
1: moveq r0, r0, lsl #1
tsteq r0, #0x00800000
- subeq r2, r2, #(1 << 22)
+ subeq r2, r2, #1
beq 1b
orr r0, r0, ip
teq r3, #0
and ip, r1, #0x80000000
2: moveq r1, r1, lsl #1
tsteq r1, #0x00800000
- subeq r3, r3, #(1 << 23)
+ subeq r3, r3, #1
beq 2b
orr r1, r1, ip
b LSYM(Lml_x)
- @ One or both args are INF or NAN.
LSYM(Lml_s):
+ @ Isolate the INF and NAN cases away
+ and r3, ip, r1, lsr #23
+ teq r2, ip
+ teqne r3, ip
+ beq 1f
+
+ @ Here, one or more arguments are either denormalized or zero.
+ bics ip, r0, #0x80000000
+ bicnes ip, r1, #0x80000000
+ bne LSYM(Lml_d)
+
+ @ Result is 0, but determine sign anyway.
+LSYM(Lml_z):
+ eor r0, r0, r1
+ bic r0, r0, #0x7fffffff
+ RET
+
+1: @ One or both args are INF or NAN.
teq r0, #0x0
- teqne r1, #0x0
teqne r0, #0x80000000
+ moveq r0, r1
+ teqne r1, #0x0
teqne r1, #0x80000000
beq LSYM(Lml_n) @ 0 * INF or INF * 0 -> NAN
- teq r2, ip, lsr #1
+ teq r2, ip
bne 1f
movs r2, r0, lsl #9
bne LSYM(Lml_n) @ NAN * <anything> -> NAN
-1: teq r3, ip, lsr #1
+1: teq r3, ip
bne LSYM(Lml_i)
movs r3, r1, lsl #9
+ movne r0, r1
bne LSYM(Lml_n) @ <anything> * NAN -> NAN
@ Result is INF, but we need to determine its sign.
@@ -479,46 +582,39 @@ LSYM(Lml_o):
orr r0, r0, #0x00800000
RET
- @ Return NAN.
+ @ Return a quiet NAN.
LSYM(Lml_n):
- mov r0, #0x7f000000
+ orr r0, r0, #0x7f000000
orr r0, r0, #0x00c00000
RET
+ FUNC_END aeabi_fmul
FUNC_END mulsf3
ARM_FUNC_START divsf3
-
- @ Mask out exponents.
- mov ip, #0xff000000
- and r2, r0, ip, lsr #1
- and r3, r1, ip, lsr #1
-
- @ Trap any INF/NAN or zeroes.
- teq r2, ip, lsr #1
- teqne r3, ip, lsr #1
- bicnes ip, r0, #0x80000000
- bicnes ip, r1, #0x80000000
+ARM_FUNC_ALIAS aeabi_fdiv divsf3
+
+ @ Mask out exponents, trap any zero/denormal/INF/NAN.
+ mov ip, #0xff
+ ands r2, ip, r0, lsr #23
+ andnes r3, ip, r1, lsr #23
+ teqne r2, ip
+ teqne r3, ip
beq LSYM(Ldv_s)
-
- @ Shift exponents right one bit to make room for overflow bit.
- @ If either of them is 0, scale denormalized arguments off line.
- @ Then substract divisor exponent from dividend''s.
- movs r2, r2, lsr #1
- teqne r3, #0
- beq LSYM(Ldv_d)
LSYM(Ldv_x):
- sub r2, r2, r3, asr #1
+
+ @ Substract divisor exponent from dividend''s
+ sub r2, r2, r3
@ Preserve final sign into ip.
eor ip, r0, r1
@ Convert mantissa to unsigned integer.
@ Dividend -> r3, divisor -> r1.
- mov r3, #0x10000000
movs r1, r1, lsl #9
mov r0, r0, lsl #9
beq LSYM(Ldv_1)
+ mov r3, #0x10000000
orr r1, r3, r1, lsr #4
orr r3, r3, r0, lsr #4
@@ -526,16 +622,10 @@ LSYM(Ldv_x):
and r0, ip, #0x80000000
@ Ensure result will land to known bit position.
+ @ Apply exponent bias accordingly.
cmp r3, r1
- subcc r2, r2, #(1 << 22)
movcc r3, r3, lsl #1
-
- @ Apply exponent bias, check range for over/underflow.
- add r2, r2, #(127 << 22)
- cmn r2, #(24 << 22)
- RETc(le)
- cmp r2, #(255 << 22)
- bge LSYM(Lml_o)
+ adc r2, r2, #(127 - 2)
@ The actual division loop.
mov ip, #0x00800000
@@ -555,44 +645,29 @@ LSYM(Ldv_x):
movnes ip, ip, lsr #4
bne 1b
- @ Check if denormalized result is needed.
- cmp r2, #0
- ble LSYM(Ldv_u)
+ @ Check exponent for under/overflow.
+ cmp r2, #(254 - 1)
+ bhi LSYM(Lml_u)
- @ Apply proper rounding.
+ @ Round the result, merge final exponent.
cmp r3, r1
- addcs r0, r0, #1
+ adc r0, r0, r2, lsl #23
biceq r0, r0, #1
-
- @ Add exponent to result.
- bic r0, r0, #0x00800000
- orr r0, r0, r2, lsl #1
RET
@ Division by 0x1p*: let''s shortcut a lot of code.
LSYM(Ldv_1):
and ip, ip, #0x80000000
orr r0, ip, r0, lsr #9
- add r2, r2, #(127 << 22)
- cmp r2, #(255 << 22)
- bge LSYM(Lml_o)
- cmp r2, #0
- orrgt r0, r0, r2, lsl #1
+ adds r2, r2, #127
+ rsbgts r3, r2, #255
+ orrgt r0, r0, r2, lsl #23
RETc(gt)
- cmn r2, #(24 << 22)
- movle r0, ip
- RETc(le)
+
orr r0, r0, #0x00800000
mov r3, #0
-
- @ Result must be denormalized: prepare parameters to use code above.
- @ r3 already contains remainder for rounding considerations.
-LSYM(Ldv_u):
- bic ip, r0, #0x80000000
- and r0, r0, #0x80000000
- mvn r1, r2, asr #22
- add r1, r1, #2
- b LSYM(Lml_ur)
+ subs r2, r2, #1
+ b LSYM(Lml_u)
@ One or both arguments are denormalized.
@ Scale them leftwards and preserve sign bit.
@@ -601,108 +676,114 @@ LSYM(Ldv_d):
and ip, r0, #0x80000000
1: moveq r0, r0, lsl #1
tsteq r0, #0x00800000
- subeq r2, r2, #(1 << 22)
+ subeq r2, r2, #1
beq 1b
orr r0, r0, ip
teq r3, #0
and ip, r1, #0x80000000
2: moveq r1, r1, lsl #1
tsteq r1, #0x00800000
- subeq r3, r3, #(1 << 23)
+ subeq r3, r3, #1
beq 2b
orr r1, r1, ip
b LSYM(Ldv_x)
- @ One or both arguments is either INF, NAN or zero.
+ @ One or both arguments are either INF, NAN, zero or denormalized.
LSYM(Ldv_s):
- mov ip, #0xff000000
- teq r2, ip, lsr #1
- teqeq r3, ip, lsr #1
- beq LSYM(Lml_n) @ INF/NAN / INF/NAN -> NAN
- teq r2, ip, lsr #1
+ and r3, ip, r1, lsr #23
+ teq r2, ip
bne 1f
movs r2, r0, lsl #9
bne LSYM(Lml_n) @ NAN / <anything> -> NAN
- b LSYM(Lml_i) @ INF / <anything> -> INF
-1: teq r3, ip, lsr #1
+ teq r3, ip
+ bne LSYM(Lml_i) @ INF / <anything> -> INF
+ mov r0, r1
+ b LSYM(Lml_n) @ INF / (INF or NAN) -> NAN
+1: teq r3, ip
bne 2f
movs r3, r1, lsl #9
- bne LSYM(Lml_n) @ <anything> / NAN -> NAN
- b LSYM(Lml_z) @ <anything> / INF -> 0
-2: @ One or both arguments are 0.
+ beq LSYM(Lml_z) @ <anything> / INF -> 0
+ mov r0, r1
+ b LSYM(Lml_n) @ <anything> / NAN -> NAN
+2: @ If both are nonzero, we need to normalize and resume above.
+ bics ip, r0, #0x80000000
+ bicnes ip, r1, #0x80000000
+ bne LSYM(Ldv_d)
+ @ One or both arguments are zero.
bics r2, r0, #0x80000000
bne LSYM(Lml_i) @ <non_zero> / 0 -> INF
bics r3, r1, #0x80000000
bne LSYM(Lml_z) @ 0 / <non_zero> -> 0
b LSYM(Lml_n) @ 0 / 0 -> NAN
+ FUNC_END aeabi_fdiv
FUNC_END divsf3
#endif /* L_muldivsf3 */
#ifdef L_cmpsf2
+ @ The return value in r0 is
+ @
+ @ 0 if the operands are equal
+ @ 1 if the first operand is greater than the second, or
+ @ the operands are unordered and the operation is
+ @ CMP, LT, LE, NE, or EQ.
+ @ -1 if the first operand is less than the second, or
+ @ the operands are unordered and the operation is GT
+ @ or GE.
+ @
+ @ The Z flag will be set iff the operands are equal.
+ @
+ @ The following registers are clobbered by this function:
+ @ ip, r0, r1, r2, r3
+
ARM_FUNC_START gtsf2
ARM_FUNC_ALIAS gesf2 gtsf2
- mov r3, #-1
+ mov ip, #-1
b 1f
ARM_FUNC_START ltsf2
ARM_FUNC_ALIAS lesf2 ltsf2
- mov r3, #1
+ mov ip, #1
b 1f
ARM_FUNC_START cmpsf2
ARM_FUNC_ALIAS nesf2 cmpsf2
ARM_FUNC_ALIAS eqsf2 cmpsf2
- mov r3, #1 @ how should we specify unordered here?
-
-1: @ Trap any INF/NAN first.
- mov ip, #0xff000000
- and r2, r1, ip, lsr #1
- teq r2, ip, lsr #1
- and r2, r0, ip, lsr #1
- teqne r2, ip, lsr #1
+ mov ip, #1 @ how should we specify unordered here?
+
+1: str ip, [sp, #-4]
+
+ @ Trap any INF/NAN first.
+ mov r2, r0, lsl #1
+ mov r3, r1, lsl #1
+ mvns ip, r2, asr #24
+ mvnnes ip, r3, asr #24
beq 3f
- @ Test for equality.
+ @ Compare values.
@ Note that 0.0 is equal to -0.0.
-2: orr r3, r0, r1
- bics r3, r3, #0x80000000 @ either 0.0 or -0.0
- teqne r0, r1 @ or both the same
- moveq r0, #0
- RETc(eq)
-
- @ Check for sign difference. The N flag is set if it is the case.
- @ If so, return sign of r0.
- movmi r0, r0, asr #31
- orrmi r0, r0, #1
- RETc(mi)
-
- @ Compare exponents.
- and r3, r1, ip, lsr #1
- cmp r2, r3
-
- @ Compare mantissa if exponents are equal
- moveq r0, r0, lsl #9
- cmpeq r0, r1, lsl #9
- movcs r0, r1, asr #31
- mvncc r0, r1, asr #31
- orr r0, r0, #1
+2: orrs ip, r2, r3, lsr #1 @ test if both are 0, clear C flag
+ teqne r0, r1 @ if not 0 compare sign
+ subpls r0, r2, r3 @ if same sign compare values, set r0
+
+ @ Result:
+ movhi r0, r1, asr #31
+ mvnlo r0, r1, asr #31
+ orrne r0, r0, #1
RET
@ Look for a NAN.
-3: and r2, r1, ip, lsr #1
- teq r2, ip, lsr #1
+3: mvns ip, r2, asr #24
bne 4f
- movs r2, r1, lsl #9
- bne 5f @ r1 is NAN
-4: and r2, r0, ip, lsr #1
- teq r2, ip, lsr #1
- bne 2b
movs ip, r0, lsl #9
- beq 2b @ r0 is not NAN
-5: mov r0, r3 @ return unordered code from r3.
+ bne 5f @ r0 is NAN
+4: mvns ip, r3, asr #24
+ bne 2b
+ movs ip, r1, lsl #9
+ beq 2b @ r1 is not NAN
+5: ldr r0, [sp, #-4] @ return unordered code.
RET
FUNC_END gesf2
@@ -713,27 +794,105 @@ ARM_FUNC_ALIAS eqsf2 cmpsf2
FUNC_END eqsf2
FUNC_END cmpsf2
+ARM_FUNC_START aeabi_cfrcmple
+
+ mov ip, r0
+ mov r0, r1
+ mov r1, ip
+ b 6f
+
+ARM_FUNC_START aeabi_cfcmpeq
+ARM_FUNC_ALIAS aeabi_cfcmple aeabi_cfcmpeq
+
+ @ The status-returning routines are required to preserve all
+ @ registers except ip, lr, and cpsr.
+6: stmfd sp!, {r0, r1, r2, r3, lr}
+ ARM_CALL cmpsf2
+ @ Set the Z flag correctly, and the C flag unconditionally.
+ cmp r0, #0
+ @ Clear the C flag if the return value was -1, indicating
+ @ that the first operand was smaller than the second.
+ cmnmi r0, #0
+ RETLDM "r0, r1, r2, r3"
+
+ FUNC_END aeabi_cfcmple
+ FUNC_END aeabi_cfcmpeq
+ FUNC_END aeabi_cfrcmple
+
+ARM_FUNC_START aeabi_fcmpeq
+
+ str lr, [sp, #-8]!
+ ARM_CALL aeabi_cfcmple
+ moveq r0, #1 @ Equal to.
+ movne r0, #0 @ Less than, greater than, or unordered.
+ RETLDM
+
+ FUNC_END aeabi_fcmpeq
+
+ARM_FUNC_START aeabi_fcmplt
+
+ str lr, [sp, #-8]!
+ ARM_CALL aeabi_cfcmple
+ movcc r0, #1 @ Less than.
+ movcs r0, #0 @ Equal to, greater than, or unordered.
+ RETLDM
+
+ FUNC_END aeabi_fcmplt
+
+ARM_FUNC_START aeabi_fcmple
+
+ str lr, [sp, #-8]!
+ ARM_CALL aeabi_cfcmple
+ movls r0, #1 @ Less than or equal to.
+ movhi r0, #0 @ Greater than or unordered.
+ RETLDM
+
+ FUNC_END aeabi_fcmple
+
+ARM_FUNC_START aeabi_fcmpge
+
+ str lr, [sp, #-8]!
+ ARM_CALL aeabi_cfrcmple
+ movls r0, #1 @ Operand 2 is less than or equal to operand 1.
+ movhi r0, #0 @ Operand 2 greater than operand 1, or unordered.
+ RETLDM
+
+ FUNC_END aeabi_fcmpge
+
+ARM_FUNC_START aeabi_fcmpgt
+
+ str lr, [sp, #-8]!
+ ARM_CALL aeabi_cfrcmple
+ movcc r0, #1 @ Operand 2 is less than operand 1.
+ movcs r0, #0 @ Operand 2 is greater than or equal to operand 1,
+ @ or they are unordered.
+ RETLDM
+
+ FUNC_END aeabi_fcmpgt
+
#endif /* L_cmpsf2 */
#ifdef L_unordsf2
ARM_FUNC_START unordsf2
- mov ip, #0xff000000
- and r2, r1, ip, lsr #1
- teq r2, ip, lsr #1
+ARM_FUNC_ALIAS aeabi_fcmpun unordsf2
+
+ mov r2, r0, lsl #1
+ mov r3, r1, lsl #1
+ mvns ip, r2, asr #24
bne 1f
- movs r2, r1, lsl #9
- bne 3f @ r1 is NAN
-1: and r2, r0, ip, lsr #1
- teq r2, ip, lsr #1
- bne 2f
- movs r2, r0, lsl #9
+ movs ip, r0, lsl #9
bne 3f @ r0 is NAN
+1: mvns ip, r3, asr #24
+ bne 2f
+ movs ip, r1, lsl #9
+ bne 3f @ r1 is NAN
2: mov r0, #0 @ arguments are ordered.
RET
3: mov r0, #1 @ arguments are unordered.
RET
+ FUNC_END aeabi_fcmpun
FUNC_END unordsf2
#endif /* L_unordsf2 */
@@ -741,39 +900,39 @@ ARM_FUNC_START unordsf2
#ifdef L_fixsfsi
ARM_FUNC_START fixsfsi
- movs r0, r0, lsl #1
- RETc(eq) @ value is 0.
-
- mov r1, r1, rrx @ preserve C flag (the actual sign)
+ARM_FUNC_ALIAS aeabi_f2iz fixsfsi
@ check exponent range.
- and r2, r0, #0xff000000
+ mov r2, r0, lsl #1
cmp r2, #(127 << 24)
- movcc r0, #0 @ value is too small
- RETc(cc)
- cmp r2, #((127 + 31) << 24)
- bcs 1f @ value is too large
-
- mov r0, r0, lsl #7
- orr r0, r0, #0x80000000
- mov r2, r2, lsr #24
- rsb r2, r2, #(127 + 31)
- tst r1, #0x80000000 @ the sign bit
- mov r0, r0, lsr r2
+ bcc 1f @ value is too small
+ mov r3, #(127 + 31)
+ subs r2, r3, r2, lsr #24
+ bls 2f @ value is too large
+
+ @ scale value
+ mov r3, r0, lsl #8
+ orr r3, r3, #0x80000000
+ tst r0, #0x80000000 @ the sign bit
+ mov r0, r3, lsr r2
rsbne r0, r0, #0
RET
-1: teq r2, #0xff000000
- bne 2f
- movs r0, r0, lsl #8
- bne 3f @ r0 is NAN.
-2: ands r0, r1, #0x80000000 @ the sign bit
+1: mov r0, #0
+ RET
+
+2: cmp r2, #(127 + 31 - 0xff)
+ bne 3f
+ movs r2, r0, lsl #9
+ bne 4f @ r0 is NAN.
+3: ands r0, r0, #0x80000000 @ the sign bit
moveq r0, #0x7fffffff @ the maximum signed positive si
RET
-3: mov r0, #0 @ What should we convert NAN to?
+4: mov r0, #0 @ What should we convert NAN to?
RET
+ FUNC_END aeabi_f2iz
FUNC_END fixsfsi
#endif /* L_fixsfsi */
@@ -781,36 +940,37 @@ ARM_FUNC_START fixsfsi
#ifdef L_fixunssfsi
ARM_FUNC_START fixunssfsi
- movs r0, r0, lsl #1
- movcss r0, #0 @ value is negative...
- RETc(eq) @ ... or 0.
-
+ARM_FUNC_ALIAS aeabi_f2uiz fixunssfsi
@ check exponent range.
- and r2, r0, #0xff000000
+ movs r2, r0, lsl #1
+ bcs 1f @ value is negative
cmp r2, #(127 << 24)
- movcc r0, #0 @ value is too small
- RETc(cc)
- cmp r2, #((127 + 32) << 24)
- bcs 1f @ value is too large
+ bcc 1f @ value is too small
+ mov r3, #(127 + 31)
+ subs r2, r3, r2, lsr #24
+ bmi 2f @ value is too large
+
+ @ scale the value
+ mov r3, r0, lsl #8
+ orr r3, r3, #0x80000000
+ mov r0, r3, lsr r2
+ RET
- mov r0, r0, lsl #7
- orr r0, r0, #0x80000000
- mov r2, r2, lsr #24
- rsb r2, r2, #(127 + 31)
- mov r0, r0, lsr r2
+1: mov r0, #0
RET
-1: teq r2, #0xff000000
- bne 2f
- movs r0, r0, lsl #8
- bne 3f @ r0 is NAN.
-2: mov r0, #0xffffffff @ maximum unsigned si
+2: cmp r2, #(127 + 31 - 0xff)
+ bne 3f
+ movs r2, r0, lsl #9
+ bne 4f @ r0 is NAN.
+3: mov r0, #0xffffffff @ maximum unsigned si
RET
-3: mov r0, #0 @ What should we convert NAN to?
+4: mov r0, #0 @ What should we convert NAN to?
RET
+ FUNC_END aeabi_f2uiz
FUNC_END fixunssfsi
#endif /* L_fixunssfsi */
diff --git a/contrib/gcc/config/arm/iwmmxt.md b/contrib/gcc/config/arm/iwmmxt.md
index f8070a8..380d4b9 100644
--- a/contrib/gcc/config/arm/iwmmxt.md
+++ b/contrib/gcc/config/arm/iwmmxt.md
@@ -1,5 +1,5 @@
;; Patterns for the Intel Wireless MMX technology architecture.
-;; Copyright (C) 2003 Free Software Foundation, Inc.
+;; Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
;; Contributed by Red Hat.
;; This file is part of GCC.
@@ -16,8 +16,8 @@
;; 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, 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
(define_insn "iwmmxt_iordi3"
[(set (match_operand:DI 0 "register_operand" "=y,?&r,?&r")
@@ -64,15 +64,19 @@
[(set_attr "predicable" "yes")])
(define_insn "*iwmmxt_arm_movdi"
- [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r, r, o<>,y,y,yr,y,yrm")
- (match_operand:DI 1 "di_operand" "rIK,mi,r ,y,yr,y,yrm,y"))]
- "TARGET_REALLY_IWMMXT"
+ [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r, r, m,y,y,yr,y,yrUy")
+ (match_operand:DI 1 "di_operand" "rIK,mi,r,y,yr,y,yrUy,y"))]
+ "TARGET_REALLY_IWMMXT
+ && ( register_operand (operands[0], DImode)
+ || register_operand (operands[1], DImode))"
"*
{
switch (which_alternative)
{
default:
return output_move_double (operands);
+ case 0:
+ return \"#\";
case 3:
return \"wmov%?\\t%0,%1\";
case 4:
@@ -86,14 +90,14 @@
}
}"
[(set_attr "length" "8,8,8,4,4,4,4,4")
- (set_attr "type" "*,load,store2,*,*,*,*,*")
+ (set_attr "type" "*,load1,store2,*,*,*,*,*")
(set_attr "pool_range" "*,1020,*,*,*,*,*,*")
(set_attr "neg_pool_range" "*,1012,*,*,*,*,*,*")]
)
(define_insn "*iwmmxt_movsi_insn"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r, m,z,r,?z,m,z")
- (match_operand:SI 1 "general_operand" "rI,K,mi,r,r,z,m,z,z"))]
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r, m,z,r,?z,Uy,z")
+ (match_operand:SI 1 "general_operand" "rI,K,mi,r,r,z,Uy,z,z"))]
"TARGET_REALLY_IWMMXT
&& ( register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode))"
@@ -110,7 +114,7 @@
case 7: return \"wstrw\\t%1, %0\";
default:return \"wstrw\\t%1, [sp, #-4]!\;wldrw\\t%0, [sp], #4\\t@move CG reg\";
}"
- [(set_attr "type" "*,*,load,store1,*,*,load,store1,*")
+ [(set_attr "type" "*,*,load1,store1,*,*,load1,store1,*")
(set_attr "length" "*,*,*, *,*,*, 16, *,8")
(set_attr "pool_range" "*,*,4096, *,*,*,1024, *,*")
(set_attr "neg_pool_range" "*,*,4084, *,*,*, *, 1012,*")
@@ -148,14 +152,14 @@
case 4: return \"tmcr%?\\t%0, %1\";
default: return \"tmrc%?\\t%0, %1\";
}"
- [(set_attr "type" "*,*,load,store1,*,*")
+ [(set_attr "type" "*,*,load1,store1,*,*")
(set_attr "pool_range" "*,*,4096, *,*,*")
(set_attr "neg_pool_range" "*,*,4084, *,*,*")]
)
(define_insn "movv8qi_internal"
[(set (match_operand:V8QI 0 "nonimmediate_operand" "=y,m,y,?r,?y,?r")
- (match_operand:V8QI 1 "general_operand" "y,y,m,y,r,i"))]
+ (match_operand:V8QI 1 "general_operand" "y,y,mi,y,r,mi"))]
"TARGET_REALLY_IWMMXT"
"*
switch (which_alternative)
@@ -169,13 +173,13 @@
}"
[(set_attr "predicable" "yes")
(set_attr "length" "4, 4, 4,4,4, 8")
- (set_attr "type" "*,store1,load,*,*,load")
+ (set_attr "type" "*,store1,load1,*,*,load1")
(set_attr "pool_range" "*, *, 256,*,*, 256")
(set_attr "neg_pool_range" "*, *, 244,*,*, 244")])
(define_insn "movv4hi_internal"
[(set (match_operand:V4HI 0 "nonimmediate_operand" "=y,m,y,?r,?y,?r")
- (match_operand:V4HI 1 "general_operand" "y,y,m,y,r,i"))]
+ (match_operand:V4HI 1 "general_operand" "y,y,mi,y,r,mi"))]
"TARGET_REALLY_IWMMXT"
"*
switch (which_alternative)
@@ -189,13 +193,13 @@
}"
[(set_attr "predicable" "yes")
(set_attr "length" "4, 4, 4,4,4, 8")
- (set_attr "type" "*,store1,load,*,*,load")
+ (set_attr "type" "*,store1,load1,*,*,load1")
(set_attr "pool_range" "*, *, 256,*,*, 256")
(set_attr "neg_pool_range" "*, *, 244,*,*, 244")])
(define_insn "movv2si_internal"
[(set (match_operand:V2SI 0 "nonimmediate_operand" "=y,m,y,?r,?y,?r")
- (match_operand:V2SI 1 "general_operand" "y,y,m,y,r,i"))]
+ (match_operand:V2SI 1 "general_operand" "y,y,mi,y,r,mi"))]
"TARGET_REALLY_IWMMXT"
"*
switch (which_alternative)
@@ -209,7 +213,7 @@
}"
[(set_attr "predicable" "yes")
(set_attr "length" "4, 4, 4,4,4, 24")
- (set_attr "type" "*,store1,load,*,*,load")
+ (set_attr "type" "*,store1,load1,*,*,load1")
(set_attr "pool_range" "*, *, 256,*,*, 256")
(set_attr "neg_pool_range" "*, *, 244,*,*, 244")])
@@ -220,12 +224,12 @@
;; deliberately omitted.
(define_insn "movv2si_internal_2"
[(set (match_operand:V2SI 0 "nonimmediate_operand" "=?r")
- (match_operand 1 "immediate_operand" "i"))]
+ (match_operand 1 "immediate_operand" "mi"))]
"TARGET_REALLY_IWMMXT"
"* return output_move_double (operands);"
[(set_attr "predicable" "yes")
(set_attr "length" "8")
- (set_attr "type" "load")
+ (set_attr "type" "load1")
(set_attr "pool_range" "256")
(set_attr "neg_pool_range" "244")])
@@ -1149,7 +1153,7 @@
"wsrawg%?\\t%0, %1, %2"
[(set_attr "predicable" "yes")])
-(define_insn "ashrdi3"
+(define_insn "ashrdi3_iwmmxt"
[(set (match_operand:DI 0 "register_operand" "=y")
(ashiftrt:DI (match_operand:DI 1 "register_operand" "y")
(match_operand:SI 2 "register_operand" "z")))]
@@ -1173,7 +1177,7 @@
"wsrlwg%?\\t%0, %1, %2"
[(set_attr "predicable" "yes")])
-(define_insn "lshrdi3"
+(define_insn "lshrdi3_iwmmxt"
[(set (match_operand:DI 0 "register_operand" "=y")
(lshiftrt:DI (match_operand:DI 1 "register_operand" "y")
(match_operand:SI 2 "register_operand" "z")))]
diff --git a/contrib/gcc/config/arm/kaos-arm.h b/contrib/gcc/config/arm/kaos-arm.h
index 0d3bf2d..b575489 100644
--- a/contrib/gcc/config/arm/kaos-arm.h
+++ b/contrib/gcc/config/arm/kaos-arm.h
@@ -16,8 +16,8 @@ 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#undef TARGET_VERSION
#define TARGET_VERSION fputs (" (ARM/kaOS[ELF])", stderr);
diff --git a/contrib/gcc/config/arm/kaos-strongarm.h b/contrib/gcc/config/arm/kaos-strongarm.h
index 8eb9473..7be2151 100644
--- a/contrib/gcc/config/arm/kaos-strongarm.h
+++ b/contrib/gcc/config/arm/kaos-strongarm.h
@@ -16,8 +16,8 @@ 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#undef TARGET_VERSION
#define TARGET_VERSION fputs (" (StrongARM/kaOS[ELF])", stderr);
diff --git a/contrib/gcc/config/arm/lib1funcs.asm b/contrib/gcc/config/arm/lib1funcs.asm
index e72af6c..9245b3c 100644
--- a/contrib/gcc/config/arm/lib1funcs.asm
+++ b/contrib/gcc/config/arm/lib1funcs.asm
@@ -1,7 +1,7 @@
@ libgcc routines for ARM cpu.
@ Division routines, written by Richard Earnshaw, (rearnsha@armltd.co.uk)
-/* Copyright 1995, 1996, 1998, 1999, 2000, 2003, 2004
+/* Copyright 1995, 1996, 1998, 1999, 2000, 2003, 2004, 2005
Free Software Foundation, Inc.
This file is free software; you can redistribute it and/or modify it
@@ -25,8 +25,8 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
/* ------------------------------------------------------------------------ */
/* We need to know what prefix to add to function names. */
@@ -60,7 +60,7 @@ Boston, MA 02111-1307, USA. */
#define LSYM(x) x
#endif
-/* Function end macros. Variants for 26 bit APCS and interworking. */
+/* Function end macros. Variants for interworking. */
@ This selects the minimum architecture level required.
#define __ARM_ARCH__ 3
@@ -74,27 +74,44 @@ Boston, MA 02111-1307, USA. */
#endif
#if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \
- || defined(__ARM_ARCH_5TE__)
+ || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \
+ || defined(__ARM_ARCH_5TEJ__)
# undef __ARM_ARCH__
# define __ARM_ARCH__ 5
#endif
-/* How to return from a function call depends on the architecture variant. */
+#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
+ || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
+ || defined(__ARM_ARCH_6ZK__)
+# undef __ARM_ARCH__
+# define __ARM_ARCH__ 6
+#endif
-#ifdef __APCS_26__
+#ifndef __ARM_ARCH__
+#error Unable to determine architecture.
+#endif
-# define RET movs pc, lr
-# define RETc(x) mov##x##s pc, lr
+/* How to return from a function call depends on the architecture variant. */
-#elif (__ARM_ARCH__ > 4) || defined(__ARM_ARCH_4T__)
+#if (__ARM_ARCH__ > 4) || defined(__ARM_ARCH_4T__)
# define RET bx lr
# define RETc(x) bx##x lr
-# if (__ARM_ARCH__ == 4) \
- && (defined(__thumb__) || defined(__THUMB_INTERWORK__))
-# define __INTERWORKING__
-# endif
+/* Special precautions for interworking on armv4t. */
+# if (__ARM_ARCH__ == 4)
+
+/* Always use bx, not ldr pc. */
+# if (defined(__thumb__) || defined(__THUMB_INTERWORK__))
+# define __INTERWORKING__
+# endif /* __THUMB__ || __THUMB_INTERWORK__ */
+
+/* Include thumb stub before arm mode code. */
+# if defined(__thumb__) && !defined(__THUMB_INTERWORK__)
+# define __INTERWORKING_STUBS__
+# endif /* __thumb__ && !__THUMB_INTERWORK__ */
+
+#endif /* __ARM_ARCH == 4 */
#else
@@ -103,25 +120,82 @@ Boston, MA 02111-1307, USA. */
#endif
+.macro cfi_pop advance, reg, cfa_offset
+#ifdef __ELF__
+ .pushsection .debug_frame
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte \advance
+ .byte (0xc0 | \reg) /* DW_CFA_restore */
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .uleb128 \cfa_offset
+ .popsection
+#endif
+.endm
+.macro cfi_push advance, reg, offset, cfa_offset
+#ifdef __ELF__
+ .pushsection .debug_frame
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte \advance
+ .byte (0x80 | \reg) /* DW_CFA_offset */
+ .uleb128 (\offset / -4)
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .uleb128 \cfa_offset
+ .popsection
+#endif
+.endm
+.macro cfi_start start_label, end_label
+#ifdef __ELF__
+ .pushsection .debug_frame
+LSYM(Lstart_frame):
+ .4byte LSYM(Lend_cie) - LSYM(Lstart_cie) @ Length of CIE
+LSYM(Lstart_cie):
+ .4byte 0xffffffff @ CIE Identifier Tag
+ .byte 0x1 @ CIE Version
+ .ascii "\0" @ CIE Augmentation
+ .uleb128 0x1 @ CIE Code Alignment Factor
+ .sleb128 -4 @ CIE Data Alignment Factor
+ .byte 0xe @ CIE RA Column
+ .byte 0xc @ DW_CFA_def_cfa
+ .uleb128 0xd
+ .uleb128 0x0
+
+ .align 2
+LSYM(Lend_cie):
+ .4byte LSYM(Lend_fde)-LSYM(Lstart_fde) @ FDE Length
+LSYM(Lstart_fde):
+ .4byte LSYM(Lstart_frame) @ FDE CIE offset
+ .4byte \start_label @ FDE initial location
+ .4byte \end_label-\start_label @ FDE address range
+ .popsection
+#endif
+.endm
+.macro cfi_end end_label
+#ifdef __ELF__
+ .pushsection .debug_frame
+ .align 2
+LSYM(Lend_fde):
+ .popsection
+\end_label:
+#endif
+.endm
+
/* Don't pass dirn, it's there just to get token pasting right. */
-.macro RETLDM regs=, cond=, dirn=ia
-#ifdef __APCS_26__
- .ifc "\regs",""
- ldm\cond\dirn sp!, {pc}^
- .else
- ldm\cond\dirn sp!, {\regs, pc}^
- .endif
-#elif defined (__INTERWORKING__)
+.macro RETLDM regs=, cond=, unwind=, dirn=ia
+#if defined (__INTERWORKING__)
.ifc "\regs",""
- ldr\cond lr, [sp], #4
+ ldr\cond lr, [sp], #8
.else
ldm\cond\dirn sp!, {\regs, lr}
.endif
+ .ifnc "\unwind", ""
+ /* Mark LR as restored. */
+97: cfi_pop 97b - \unwind, 0xe, 0x0
+ .endif
bx\cond lr
#else
.ifc "\regs",""
- ldr\cond pc, [sp], #4
+ ldr\cond pc, [sp], #8
.else
ldm\cond\dirn sp!, {\regs, pc}
.endif
@@ -129,25 +203,25 @@ Boston, MA 02111-1307, USA. */
.endm
-.macro ARM_LDIV0
-LSYM(Ldiv0):
- str lr, [sp, #-4]!
+.macro ARM_LDIV0 name
+ str lr, [sp, #-8]!
+98: cfi_push 98b - __\name, 0xe, -0x8, 0x8
bl SYM (__div0) __PLT__
mov r0, #0 @ About as wrong as it could be.
- RETLDM
+ RETLDM unwind=98b
.endm
-.macro THUMB_LDIV0
-LSYM(Ldiv0):
- push { lr }
+.macro THUMB_LDIV0 name
+ push { r1, lr }
+98: cfi_push 98b - __\name, 0xe, -0x4, 0x8
bl SYM (__div0)
mov r0, #0 @ About as wrong as it could be.
#if defined (__INTERWORKING__)
- pop { r1 }
- bx r1
+ pop { r1, r2 }
+ bx r2
#else
- pop { pc }
+ pop { r1, pc }
#endif
.endm
@@ -156,12 +230,14 @@ LSYM(Ldiv0):
.endm
.macro DIV_FUNC_END name
+ cfi_start __\name, LSYM(Lend_div0)
LSYM(Ldiv0):
#ifdef __thumb__
- THUMB_LDIV0
+ THUMB_LDIV0 \name
#else
- ARM_LDIV0
+ ARM_LDIV0 \name
#endif
+ cfi_end LSYM(Lend_div0)
FUNC_END \name
.endm
@@ -195,15 +271,22 @@ SYM (__\name):
/* Special function that will always be coded in ARM assembly, even if
in Thumb-only compilation. */
-#if defined(__thumb__) && !defined(__THUMB_INTERWORK__)
+#if defined(__INTERWORKING_STUBS__)
.macro ARM_FUNC_START name
FUNC_START \name
bx pc
nop
.arm
-_L__\name: /* A hook to tell gdb that we've switched to ARM */
+/* A hook to tell gdb that we've switched to ARM mode. Also used to call
+ directly from other local arm routines. */
+_L__\name:
.endm
#define EQUIV .thumb_set
+/* Branch directly to a function declared with ARM_FUNC_START.
+ Must be called in arm mode. */
+.macro ARM_CALL name
+ bl _L__\name
+.endm
#else
.macro ARM_FUNC_START name
.text
@@ -214,11 +297,26 @@ _L__\name: /* A hook to tell gdb that we've switched to ARM */
SYM (__\name):
.endm
#define EQUIV .set
+.macro ARM_CALL name
+ bl __\name
+.endm
#endif
+.macro FUNC_ALIAS new old
+ .globl SYM (__\new)
+#if defined (__thumb__)
+ .thumb_set SYM (__\new), SYM (__\old)
+#else
+ .set SYM (__\new), SYM (__\old)
+#endif
+.endm
+
.macro ARM_FUNC_ALIAS new old
.globl SYM (__\new)
EQUIV SYM (__\new), SYM (__\old)
+#if defined(__INTERWORKING_STUBS__)
+ .set SYM (_L__\new), SYM (_L__\old)
+#endif
.endm
#ifdef __thumb__
@@ -243,6 +341,25 @@ pc .req r15
/* ------------------------------------------------------------------------ */
.macro ARM_DIV_BODY dividend, divisor, result, curbit
+#if __ARM_ARCH__ >= 5 && ! defined (__OPTIMIZE_SIZE__)
+
+ clz \curbit, \dividend
+ clz \result, \divisor
+ sub \curbit, \result, \curbit
+ rsbs \curbit, \curbit, #31
+ addne \curbit, \curbit, \curbit, lsl #1
+ mov \result, #0
+ addne pc, pc, \curbit, lsl #2
+ nop
+ .set shift, 32
+ .rept 32
+ .set shift, shift - 1
+ cmp \dividend, \divisor, lsl #shift
+ adc \result, \result, \result
+ subcs \dividend, \dividend, \divisor, lsl #shift
+ .endr
+
+#else /* __ARM_ARCH__ < 5 || defined (__OPTIMIZE_SIZE__) */
#if __ARM_ARCH__ >= 5
clz \curbit, \divisor
@@ -253,7 +370,7 @@ pc .req r15
mov \curbit, \curbit, lsl \result
mov \result, #0
-#else
+#else /* __ARM_ARCH__ < 5 */
@ Initially shift the divisor left 3 bits if possible,
@ set curbit accordingly. This allows for curbit to be located
@@ -284,7 +401,7 @@ pc .req r15
mov \result, #0
-#endif
+#endif /* __ARM_ARCH__ < 5 */
@ Division loop
1: cmp \dividend, \divisor
@@ -304,6 +421,8 @@ pc .req r15
movne \divisor, \divisor, lsr #4
bne 1b
+#endif /* __ARM_ARCH__ < 5 || defined (__OPTIMIZE_SIZE__) */
+
.endm
/* ------------------------------------------------------------------------ */
.macro ARM_DIV2_ORDER divisor, order
@@ -338,6 +457,22 @@ pc .req r15
/* ------------------------------------------------------------------------ */
.macro ARM_MOD_BODY dividend, divisor, order, spare
+#if __ARM_ARCH__ >= 5 && ! defined (__OPTIMIZE_SIZE__)
+
+ clz \order, \divisor
+ clz \spare, \dividend
+ sub \order, \order, \spare
+ rsbs \order, \order, #31
+ addne pc, pc, \order, lsl #3
+ nop
+ .set shift, 32
+ .rept 32
+ .set shift, shift - 1
+ cmp \dividend, \divisor, lsl #shift
+ subcs \dividend, \dividend, \divisor, lsl #shift
+ .endr
+
+#else /* __ARM_ARCH__ < 5 || defined (__OPTIMIZE_SIZE__) */
#if __ARM_ARCH__ >= 5
clz \order, \divisor
@@ -345,7 +480,7 @@ pc .req r15
sub \order, \order, \spare
mov \divisor, \divisor, lsl \order
-#else
+#else /* __ARM_ARCH__ < 5 */
mov \order, #0
@@ -367,7 +502,7 @@ pc .req r15
addlo \order, \order, #1
blo 1b
-#endif
+#endif /* __ARM_ARCH__ < 5 */
@ Perform all needed substractions to keep only the reminder.
@ Do comparisons in batch of 4 first.
@@ -404,6 +539,9 @@ pc .req r15
4: cmp \dividend, \divisor
subhs \dividend, \dividend, \divisor
5:
+
+#endif /* __ARM_ARCH__ < 5 || defined (__OPTIMIZE_SIZE__) */
+
.endm
/* ------------------------------------------------------------------------ */
.macro THUMB_DIV_MOD_BODY modulo
@@ -568,6 +706,7 @@ LSYM(Lgot_result):
#ifdef L_udivsi3
FUNC_START udivsi3
+ FUNC_ALIAS aeabi_uidiv udivsi3
#ifdef __thumb__
@@ -614,6 +753,24 @@ LSYM(Lgot_result):
DIV_FUNC_END udivsi3
+FUNC_START aeabi_uidivmod
+#ifdef __thumb__
+ push {r0, r1, lr}
+ bl SYM(__udivsi3)
+ POP {r1, r2, r3}
+ mul r2, r0
+ sub r1, r1, r2
+ bx r3
+#else
+ stmfd sp!, { r0, r1, lr }
+ bl SYM(__udivsi3)
+ ldmfd sp!, { r1, r2, lr }
+ mul r3, r2, r0
+ sub r1, r1, r3
+ RET
+#endif
+ FUNC_END aeabi_uidivmod
+
#endif /* L_udivsi3 */
/* ------------------------------------------------------------------------ */
#ifdef L_umodsi3
@@ -660,6 +817,7 @@ LSYM(Lover10):
#ifdef L_divsi3
FUNC_START divsi3
+ FUNC_ALIAS aeabi_idiv divsi3
#ifdef __thumb__
cmp divisor, #0
@@ -734,6 +892,24 @@ LSYM(Lover12):
DIV_FUNC_END divsi3
+FUNC_START aeabi_idivmod
+#ifdef __thumb__
+ push {r0, r1, lr}
+ bl SYM(__divsi3)
+ POP {r1, r2, r3}
+ mul r2, r0
+ sub r1, r1, r2
+ bx r3
+#else
+ stmfd sp!, { r0, r1, lr }
+ bl SYM(__divsi3)
+ ldmfd sp!, { r1, r2, lr }
+ mul r3, r2, r0
+ sub r1, r1, r3
+ RET
+#endif
+ FUNC_END aeabi_idivmod
+
#endif /* L_divsi3 */
/* ------------------------------------------------------------------------ */
#ifdef L_modsi3
@@ -799,9 +975,13 @@ LSYM(Lover12):
#ifdef L_dvmd_tls
FUNC_START div0
+ FUNC_ALIAS aeabi_idiv0 div0
+ FUNC_ALIAS aeabi_ldiv0 div0
RET
+ FUNC_END aeabi_ldiv0
+ FUNC_END aeabi_idiv0
FUNC_END div0
#endif /* L_divmodsi_tools */
@@ -809,34 +989,155 @@ LSYM(Lover12):
#ifdef L_dvmd_lnx
@ GNU/Linux division-by zero handler. Used in place of L_dvmd_tls
-/* Constants taken from <asm/unistd.h> and <asm/signal.h> */
+/* Constant taken from <asm/signal.h>. */
#define SIGFPE 8
-#define __NR_SYSCALL_BASE 0x900000
-#define __NR_getpid (__NR_SYSCALL_BASE+ 20)
-#define __NR_kill (__NR_SYSCALL_BASE+ 37)
.code 32
FUNC_START div0
stmfd sp!, {r1, lr}
- swi __NR_getpid
- cmn r0, #1000
- RETLDM r1 hs
- mov r1, #SIGFPE
- swi __NR_kill
+ mov r0, #SIGFPE
+ bl SYM(raise) __PLT__
RETLDM r1
FUNC_END div0
#endif /* L_dvmd_lnx */
/* ------------------------------------------------------------------------ */
+/* Dword shift operations. */
+/* All the following Dword shift variants rely on the fact that
+ shft xxx, Reg
+ is in fact done as
+ shft xxx, (Reg & 255)
+ so for Reg value in (32...63) and (-1...-31) we will get zero (in the
+ case of logical shifts) or the sign (for asr). */
+
+#ifdef __ARMEB__
+#define al r1
+#define ah r0
+#else
+#define al r0
+#define ah r1
+#endif
+
+/* Prevent __aeabi double-word shifts from being produced on SymbianOS. */
+#ifndef __symbian__
+
+#ifdef L_lshrdi3
+
+ FUNC_START lshrdi3
+ FUNC_ALIAS aeabi_llsr lshrdi3
+
+#ifdef __thumb__
+ lsr al, r2
+ mov r3, ah
+ lsr ah, r2
+ mov ip, r3
+ sub r2, #32
+ lsr r3, r2
+ orr al, r3
+ neg r2, r2
+ mov r3, ip
+ lsl r3, r2
+ orr al, r3
+ RET
+#else
+ subs r3, r2, #32
+ rsb ip, r2, #32
+ movmi al, al, lsr r2
+ movpl al, ah, lsr r3
+ orrmi al, al, ah, lsl ip
+ mov ah, ah, lsr r2
+ RET
+#endif
+ FUNC_END aeabi_llsr
+ FUNC_END lshrdi3
+
+#endif
+
+#ifdef L_ashrdi3
+
+ FUNC_START ashrdi3
+ FUNC_ALIAS aeabi_lasr ashrdi3
+
+#ifdef __thumb__
+ lsr al, r2
+ mov r3, ah
+ asr ah, r2
+ sub r2, #32
+ @ If r2 is negative at this point the following step would OR
+ @ the sign bit into all of AL. That's not what we want...
+ bmi 1f
+ mov ip, r3
+ asr r3, r2
+ orr al, r3
+ mov r3, ip
+1:
+ neg r2, r2
+ lsl r3, r2
+ orr al, r3
+ RET
+#else
+ subs r3, r2, #32
+ rsb ip, r2, #32
+ movmi al, al, lsr r2
+ movpl al, ah, asr r3
+ orrmi al, al, ah, lsl ip
+ mov ah, ah, asr r2
+ RET
+#endif
+
+ FUNC_END aeabi_lasr
+ FUNC_END ashrdi3
+
+#endif
+
+#ifdef L_ashldi3
+
+ FUNC_START ashldi3
+ FUNC_ALIAS aeabi_llsl ashldi3
+
+#ifdef __thumb__
+ lsl ah, r2
+ mov r3, al
+ lsl al, r2
+ mov ip, r3
+ sub r2, #32
+ lsl r3, r2
+ orr ah, r3
+ neg r2, r2
+ mov r3, ip
+ lsr r3, r2
+ orr ah, r3
+ RET
+#else
+ subs r3, r2, #32
+ rsb ip, r2, #32
+ movmi ah, ah, lsl r2
+ movpl ah, al, lsl r3
+ orrmi ah, ah, al, lsr ip
+ mov al, al, lsl r2
+ RET
+#endif
+ FUNC_END aeabi_llsl
+ FUNC_END ashldi3
+
+#endif
+
+#endif /* __symbian__ */
+
+/* ------------------------------------------------------------------------ */
/* These next two sections are here despite the fact that they contain Thumb
assembler because their presence allows interworked code to be linked even
when the GCC library is this one. */
/* Do not build the interworking functions when the target architecture does
not support Thumb instructions. (This can be a multilib option). */
-#if defined L_call_via_rX && (defined __ARM_ARCH_4T__ || defined __ARM_ARCH_5T__ || defined __ARM_ARCH_5TE__)
+#if defined __ARM_ARCH_4T__ || defined __ARM_ARCH_5T__\
+ || defined __ARM_ARCH_5TE__ || defined __ARM_ARCH_5TEJ__ \
+ || __ARM_ARCH__ >= 6
+
+#if defined L_call_via_rX
/* These labels & instructions are used by the Arm/Thumb interworking code.
The address of function to be called is loaded into a register and then
@@ -874,10 +1175,8 @@ LSYM(Lover12):
call_via lr
#endif /* L_call_via_rX */
-/* ------------------------------------------------------------------------ */
-/* Do not build the interworking functions when the target architecture does
- not support Thumb instructions. (This can be a multilib option). */
-#if defined L_interwork_call_via_rX && (defined __ARM_ARCH_4T__ || defined __ARM_ARCH_5T__ || defined __ARM_ARCH_5TE__)
+
+#if defined L_interwork_call_via_rX
/* These labels & instructions are used by the Arm/Thumb interworking code,
when the target address is in an unknown instruction set. The address
@@ -888,16 +1187,61 @@ LSYM(Lover12):
the target code cannot be relied upon to return via a BX instruction, so
instead we have to store the resturn address on the stack and allow the
called function to return here instead. Upon return we recover the real
- return address and use a BX to get back to Thumb mode. */
+ return address and use a BX to get back to Thumb mode.
+
+ There are three variations of this code. The first,
+ _interwork_call_via_rN(), will push the return address onto the
+ stack and pop it in _arm_return(). It should only be used if all
+ arguments are passed in registers.
+
+ The second, _interwork_r7_call_via_rN(), instead stores the return
+ address at [r7, #-4]. It is the caller's responsibility to ensure
+ that this address is valid and contains no useful data.
+
+ The third, _interwork_r11_call_via_rN(), works in the same way but
+ uses r11 instead of r7. It is useful if the caller does not really
+ need a frame pointer. */
.text
.align 0
.code 32
.globl _arm_return
+LSYM(Lstart_arm_return):
+ cfi_start LSYM(Lstart_arm_return) LSYM(Lend_arm_return)
+ cfi_push 0, 0xe, -0x8, 0x8
+ nop @ This nop is for the benefit of debuggers, so that
+ @ backtraces will use the correct unwind information.
_arm_return:
- RETLDM
- .code 16
+ RETLDM unwind=LSYM(Lstart_arm_return)
+ cfi_end LSYM(Lend_arm_return)
+
+ .globl _arm_return_r7
+_arm_return_r7:
+ ldr lr, [r7, #-4]
+ bx lr
+
+ .globl _arm_return_r11
+_arm_return_r11:
+ ldr lr, [r11, #-4]
+ bx lr
+
+.macro interwork_with_frame frame, register, name, return
+ .code 16
+
+ THUMB_FUNC_START \name
+
+ bx pc
+ nop
+
+ .code 32
+ tst \register, #1
+ streq lr, [\frame, #-4]
+ adreq lr, _arm_return_\frame
+ bx \register
+
+ SIZE (\name)
+.endm
.macro interwork register
.code 16
@@ -911,11 +1255,14 @@ _arm_return:
.globl LSYM(Lchange_\register)
LSYM(Lchange_\register):
tst \register, #1
- streq lr, [sp, #-4]!
+ streq lr, [sp, #-8]!
adreq lr, _arm_return
bx \register
SIZE (_interwork_call_via_\register)
+
+ interwork_with_frame r7,\register,_interwork_r7_call_via_\register
+ interwork_with_frame r11,\register,_interwork_r11_call_via_\register
.endm
interwork r0
@@ -945,7 +1292,7 @@ LSYM(Lchange_\register):
.globl .Lchange_lr
.Lchange_lr:
tst lr, #1
- stmeqdb r13!, {lr}
+ stmeqdb r13!, {lr, pc}
mov ip, lr
adreq lr, _arm_return
bx ip
@@ -953,7 +1300,10 @@ LSYM(Lchange_\register):
SIZE (_interwork_call_via_lr)
#endif /* L_interwork_call_via_rX */
+#endif /* Arch supports thumb. */
+#ifndef __symbian__
#include "ieee754-df.S"
#include "ieee754-sf.S"
-
+#include "bpabi.S"
+#endif /* __symbian__ */
diff --git a/contrib/gcc/config/arm/libgcc-bpabi.ver b/contrib/gcc/config/arm/libgcc-bpabi.ver
new file mode 100644
index 0000000..2f259eb
--- /dev/null
+++ b/contrib/gcc/config/arm/libgcc-bpabi.ver
@@ -0,0 +1,83 @@
+GCC_3.5 {
+ # BPABI symbols
+ __aeabi_cdcmpeq
+ __aeabi_cdcmple
+ __aeabi_cdrcmple
+ __aeabi_cfcmpeq
+ __aeabi_cfcmple
+ __aeabi_cfrcmple
+ __aeabi_d2f
+ __aeabi_d2iz
+ __aeabi_d2lz
+ __aeabi_d2uiz
+ __aeabi_d2ulz
+ __aeabi_dadd
+ __aeabi_dcmpeq
+ __aeabi_dcmpge
+ __aeabi_dcmpgt
+ __aeabi_dcmple
+ __aeabi_dcmplt
+ __aeabi_dcmpun
+ __aeabi_ddiv
+ __aeabi_dmul
+ __aeabi_dneg
+ __aeabi_drsub
+ __aeabi_dsub
+ __aeabi_f2d
+ __aeabi_f2iz
+ __aeabi_f2lz
+ __aeabi_f2uiz
+ __aeabi_f2ulz
+ __aeabi_fadd
+ __aeabi_fcmpeq
+ __aeabi_fcmpge
+ __aeabi_fcmpgt
+ __aeabi_fcmple
+ __aeabi_fcmplt
+ __aeabi_fcmpun
+ __aeabi_fdiv
+ __aeabi_fmul
+ __aeabi_fneg
+ __aeabi_frsub
+ __aeabi_fsub
+ __aeabi_i2d
+ __aeabi_i2f
+ __aeabi_idiv
+ __aeabi_idiv0
+ __aeabi_idivmod
+ __aeabi_l2d
+ __aeabi_l2f
+ __aeabi_lasr
+ __aeabi_lcmp
+ __aeabi_ldiv0
+ __aeabi_ldivmod
+ __aeabi_llsl
+ __aeabi_llsr
+ __aeabi_lmul
+ __aeabi_ui2d
+ __aeabi_ui2f
+ __aeabi_uidiv
+ __aeabi_uidivmod
+ __aeabi_uldivmod
+ __aeabi_ulcmp
+ __aeabi_ul2d
+ __aeabi_ul2f
+ __aeabi_uread4
+ __aeabi_uread8
+ __aeabi_uwrite4
+ __aeabi_uwrite8
+
+ # Exception-Handling
+ # \S 7.5
+ _Unwind_Complete
+ _Unwind_VRS_Get
+ _Unwind_VRS_Set
+ _Unwind_VRS_Pop
+ # \S 9.2
+ __aeabi_unwind_cpp_pr0
+ __aeabi_unwind_cpp_pr1
+ __aeabi_unwind_cpp_pr2
+ # The libstdc++ exception-handling personality routine uses this
+ # GNU-specific entry point.
+ __gnu_unwind_frame
+}
diff --git a/contrib/gcc/config/arm/libunwind.S b/contrib/gcc/config/arm/libunwind.S
new file mode 100644
index 0000000..06e1310
--- /dev/null
+++ b/contrib/gcc/config/arm/libunwind.S
@@ -0,0 +1,120 @@
+/* Support functions for the unwinder.
+ Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+ Contributed by Paul Brook
+
+ 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, 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.)
+
+ 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 program; see the file COPYING. If not, write to
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#ifndef __symbian__
+
+#include "lib1funcs.asm"
+
+.macro UNPREFIX name
+ .global SYM (\name)
+ EQUIV SYM (\name), SYM (__\name)
+.endm
+
+/* r0 points to a 16-word block. Upload these values to the actual core
+ state. */
+ARM_FUNC_START restore_core_regs
+ /* We must use sp as the base register when restoring sp. Push the
+ last 3 registers onto the top of the current stack to achieve
+ this. */
+ add r1, r0, #52
+ ldmia r1, {r3, r4, r5} /* {sp, lr, pc}. */
+#ifdef __INTERWORKING__
+ /* Restore pc into ip. */
+ mov r2, r5
+ stmfd sp!, {r2, r3, r4}
+#else
+ stmfd sp!, {r3, r4, r5}
+#endif
+ /* Don't bother restoring ip. */
+ ldmia r0, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp}
+ /* Pop the three registers we pushed earlier. */
+#ifdef __INTERWORKING__
+ ldmfd sp, {ip, sp, lr}
+ bx ip
+#else
+ ldmfd sp, {sp, lr, pc}
+#endif
+ FUNC_END restore_core_regs
+ UNPREFIX restore_core_regs
+
+/* Load VFP registers d0-d15 from the address in r0. */
+ARM_FUNC_START gnu_Unwind_Restore_VFP
+ /* Use the generic coprocessor form so that gas doesn't complain
+ on soft-float targets. */
+ ldc p11,cr0,[r0],{0x21} /* fldmiax r0, {d0-d15} */
+ RET
+
+/* Store VFR regsters d0-d15 to the address in r0. */
+ARM_FUNC_START gnu_Unwind_Save_VFP
+ /* Use the generic coprocessor form so that gas doesn't complain
+ on soft-float targets. */
+ stc p11,cr0,[r0],{0x21} /* fstmiax r0, {d0-d15} */
+ RET
+
+/* Wrappers to save core registers, then call the real routine. */
+
+.macro UNWIND_WRAPPER name nargs
+ ARM_FUNC_START \name
+ /* Create a phase2_vrs structure. */
+ /* Split reg push in two to ensure the correct value for sp. */
+ stmfd sp!, {sp, lr, pc}
+ stmfd sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip}
+
+ /* Demand-save flags, plus an extra word for alignment. */
+ mov r3, #0
+ stmfd sp!, {r2, r3}
+
+ /* Point r1 at the block. Pass r[0..nargs) unchanged. */
+ add r\nargs, sp, #4
+#if defined(__thumb__)
+ /* Switch back to thumb mode to avoid interworking hassle. */
+ adr ip, .L1_\name
+ orr ip, ip, #1
+ bx ip
+ .thumb
+.L1_\name:
+ bl SYM (__gnu\name) __PLT__
+ ldr r3, [sp, #64]
+ add sp, #72
+ bx r3
+#else
+ bl SYM (__gnu\name) __PLT__
+ ldr lr, [sp, #64]
+ add sp, sp, #72
+ RET
+#endif
+ FUNC_END \name
+ UNPREFIX \name
+.endm
+
+UNWIND_WRAPPER _Unwind_RaiseException 1
+UNWIND_WRAPPER _Unwind_Resume 1
+UNWIND_WRAPPER _Unwind_Resume_or_Rethrow 1
+UNWIND_WRAPPER _Unwind_ForcedUnwind 3
+
+#endif /* __symbian__ */
diff --git a/contrib/gcc/config/arm/linux-eabi.h b/contrib/gcc/config/arm/linux-eabi.h
new file mode 100644
index 0000000..6612f74
--- /dev/null
+++ b/contrib/gcc/config/arm/linux-eabi.h
@@ -0,0 +1,85 @@
+/* Configuration file for ARM GNU/Linux EABI targets.
+ Copyright (C) 2004, 2005, 2006
+ Free Software Foundation, Inc.
+ Contributed by CodeSourcery, LLC
+
+ 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.
+
+ 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. */
+
+/* On EABI GNU/Linux, we want both the BPABI builtins and the
+ GNU/Linux builtins. */
+#undef TARGET_OS_CPP_BUILTINS
+#define TARGET_OS_CPP_BUILTINS() \
+ do \
+ { \
+ TARGET_BPABI_CPP_BUILTINS(); \
+ LINUX_TARGET_OS_CPP_BUILTINS(); \
+ } \
+ while (false)
+
+/* We default to a soft-float ABI so that binaries can run on all
+ target hardware. */
+#undef TARGET_DEFAULT_FLOAT_ABI
+#define TARGET_DEFAULT_FLOAT_ABI ARM_FLOAT_ABI_SOFT
+
+/* We default to the "aapcs-linux" ABI so that enums are int-sized by
+ default. */
+#undef ARM_DEFAULT_ABI
+#define ARM_DEFAULT_ABI ARM_ABI_AAPCS_LINUX
+
+/* Default to armv5t so that thumb shared libraries work.
+ The ARM10TDMI core is the default for armv5t, so set
+ SUBTARGET_CPU_DEFAULT to achieve this. */
+#undef SUBTARGET_CPU_DEFAULT
+#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm10tdmi
+
+#undef SUBTARGET_EXTRA_LINK_SPEC
+#define SUBTARGET_EXTRA_LINK_SPEC " -m armelf_linux_eabi"
+
+/* Use ld-linux.so.3 so that it will be possible to run "classic"
+ GNU/Linux binaries on an EABI system. */
+#undef GLIBC_DYNAMIC_LINKER
+#define GLIBC_DYNAMIC_LINKER "/lib/ld-linux.so.3"
+
+/* At this point, bpabi.h will have clobbered LINK_SPEC. We want to
+ use the GNU/Linux version, not the generic BPABI version. */
+#undef LINK_SPEC
+#define LINK_SPEC LINUX_TARGET_LINK_SPEC
+
+/* Use the default LIBGCC_SPEC, not the version in linux-elf.h, as we
+ do not use -lfloat. */
+#undef LIBGCC_SPEC
+
+/* Use the AAPCS type for wchar_t, or the previous Linux default for
+ non-AAPCS. */
+#undef WCHAR_TYPE
+#define WCHAR_TYPE (TARGET_AAPCS_BASED ? "unsigned int" : "long int")
+
+/* Clear the instruction cache from `beg' to `end'. This makes an
+ inline system call to SYS_cacheflush. It is modified to work with
+ both the original and EABI-only syscall interfaces. */
+#undef CLEAR_INSN_CACHE
+#define CLEAR_INSN_CACHE(BEG, END) \
+{ \
+ register unsigned long _beg __asm ("a1") = (unsigned long) (BEG); \
+ register unsigned long _end __asm ("a2") = (unsigned long) (END); \
+ register unsigned long _flg __asm ("a3") = 0; \
+ register unsigned long _scno __asm ("r7") = 0xf0002; \
+ __asm __volatile ("swi 0x9f0002 @ sys_cacheflush" \
+ : "=r" (_beg) \
+ : "0" (_beg), "r" (_end), "r" (_flg), "r" (_scno)); \
+}
diff --git a/contrib/gcc/config/arm/linux-elf.h b/contrib/gcc/config/arm/linux-elf.h
index 9f291c0..acb13cd 100644
--- a/contrib/gcc/config/arm/linux-elf.h
+++ b/contrib/gcc/config/arm/linux-elf.h
@@ -1,5 +1,6 @@
/* Definitions for ARM running Linux-based GNU systems using ELF
- Copyright (C) 1993, 1994, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ Copyright (C) 1993, 1994, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+ 2005, 2006
Free Software Foundation, Inc.
Contributed by Philip Blundell <philb@gnu.org>
@@ -17,8 +18,8 @@
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* elfos.h should have already been included. Now just override
any conflicting definitions and add any extras. */
@@ -27,12 +28,11 @@
#undef TARGET_VERSION
#define TARGET_VERSION fputs (" (ARM GNU/Linux with ELF)", stderr);
-/* Do not assume anything about header files. */
-#define NO_IMPLICIT_EXTERN_C
+#undef TARGET_DEFAULT_FLOAT_ABI
+#define TARGET_DEFAULT_FLOAT_ABI ARM_FLOAT_ABI_HARD
-/* Default is to use APCS-32 mode. */
#undef TARGET_DEFAULT
-#define TARGET_DEFAULT (ARM_FLAG_APCS_32 | ARM_FLAG_MMU_TRAPS)
+#define TARGET_DEFAULT (0)
#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6
@@ -40,13 +40,7 @@
#undef MULTILIB_DEFAULTS
#define MULTILIB_DEFAULTS \
- { "marm", "mlittle-endian", "mhard-float", "mapcs-32", "mno-thumb-interwork" }
-
-#define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__"
-
-/* The GNU C++ standard library requires that these macros be defined. */
-#undef CPLUSPLUS_CPP_SPEC
-#define CPLUSPLUS_CPP_SPEC "-D_GNU_SOURCE %(cpp)"
+ { "marm", "mlittle-endian", "mhard-float", "mno-thumb-interwork" }
/* Now we define the strings used to build the spec file. */
#undef LIB_SPEC
@@ -55,44 +49,30 @@
%{shared:-lc} \
%{!shared:%{profile:-lc_p}%{!profile:-lc}}"
-#define LIBGCC_SPEC "%{msoft-float:-lfloat} -lgcc"
-
-/* Provide a STARTFILE_SPEC appropriate for GNU/Linux. Here we add
- the GNU/Linux magical crtbegin.o file (see crtstuff.c) which
- provides part of the support for getting C++ file-scope static
- object constructed before entering `main'. */
-
-#undef STARTFILE_SPEC
-#define STARTFILE_SPEC \
- "%{!shared: \
- %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} \
- %{!p:%{profile:gcrt1.o%s} \
- %{!profile:crt1.o%s}}}} \
- crti.o%s %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}"
-
-/* Provide a ENDFILE_SPEC appropriate for GNU/Linux. Here we tack on
- the GNU/Linux magical crtend.o file (see crtstuff.c) which
- provides part of the support for getting C++ file-scope static
- object constructed before entering `main', followed by a normal
- GNU/Linux "finalizer" file, `crtn.o'. */
-
-#undef ENDFILE_SPEC
-#define ENDFILE_SPEC \
- "%{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.o%s"
+#define LIBGCC_SPEC "%{msoft-float:-lfloat} %{mfloat-abi=soft*:-lfloat} -lgcc"
-#undef LINK_SPEC
-#define LINK_SPEC "%{h*} %{version:-v} \
- %{b} %{Wl,*:%*} \
+#define GLIBC_DYNAMIC_LINKER "/lib/ld-linux.so.2"
+
+#define LINUX_TARGET_LINK_SPEC "%{h*} %{version:-v} \
+ %{b} \
%{static:-Bstatic} \
%{shared:-shared} \
%{symbolic:-Bsymbolic} \
%{rdynamic:-export-dynamic} \
- %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.2} \
+ %{!dynamic-linker:-dynamic-linker " LINUX_DYNAMIC_LINKER "} \
-X \
%{mbig-endian:-EB}" \
SUBTARGET_EXTRA_LINK_SPEC
-#define TARGET_OS_CPP_BUILTINS() LINUX_TARGET_OS_CPP_BUILTINS()
+#undef LINK_SPEC
+#define LINK_SPEC LINUX_TARGET_LINK_SPEC
+
+#define TARGET_OS_CPP_BUILTINS() \
+ do \
+ { \
+ LINUX_TARGET_OS_CPP_BUILTINS(); \
+ } \
+ while (0)
/* This is how we tell the assembler that two symbols have the same value. */
#define ASM_OUTPUT_DEF(FILE, NAME1, NAME2) \
@@ -113,16 +93,14 @@
#undef ARM_FUNCTION_PROFILER
#define ARM_FUNCTION_PROFILER(STREAM, LABELNO) \
{ \
- fprintf (STREAM, "\tbl\tmcount%s\n", NEED_PLT_RELOC ? "(PLT)" : ""); \
+ fprintf (STREAM, "\tbl\tmcount%s\n", \
+ (TARGET_ARM && NEED_PLT_RELOC) ? "(PLT)" : ""); \
}
-/* The linux profiler clobbers the link register. Make sure the
+/* The GNU/Linux profiler clobbers the link register. Make sure the
prologue knows to save it. */
#define PROFILE_HOOK(X) \
emit_insn (gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, LR_REGNUM)))
-#undef CC1_SPEC
-#define CC1_SPEC "%{profile:-p}"
-
-#define LINK_GCC_C_SEQUENCE_SPEC \
- "%{static:--start-group} %G %L %{static:--end-group}%{!static:%G}"
+/* The GNU/Linux profiler needs a frame pointer. */
+#define SUBTARGET_FRAME_POINTER_REQUIRED current_function_profile
diff --git a/contrib/gcc/config/arm/linux-gas.h b/contrib/gcc/config/arm/linux-gas.h
index 6911284..a04e050 100644
--- a/contrib/gcc/config/arm/linux-gas.h
+++ b/contrib/gcc/config/arm/linux-gas.h
@@ -1,6 +1,7 @@
/* Definitions of target machine for GNU compiler.
ARM Linux-based GNU systems version.
- Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ Copyright (C) 1997, 1998, 1999, 2000, 2001, 2004
+ Free Software Foundation, Inc.
Contributed by Russell King <rmk92@ecs.soton.ac.uk>.
This file is part of GCC.
@@ -17,8 +18,8 @@
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* This is how we tell the assembler that a symbol is weak.
GAS always supports weak symbols. */
@@ -27,7 +28,7 @@
#define DEFAULT_SIGNED_CHAR 0
#undef SUBTARGET_CPP_SPEC
-#define SUBTARGET_CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{fPIC|fPIE:-D__PIC__ -D__pic__} %{fpic|fpie:-D__PIC__ -D__pic__}"
+#define SUBTARGET_CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}"
#undef SIZE_TYPE
#define SIZE_TYPE "unsigned int"
@@ -41,19 +42,6 @@
#undef WCHAR_TYPE_SIZE
#define WCHAR_TYPE_SIZE BITS_PER_WORD
-/* Emit code to set up a trampoline and synchronize the caches. */
-#undef INITIALIZE_TRAMPOLINE
-#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
-{ \
- emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 8)), \
- (CXT)); \
- emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 12)), \
- (FNADDR)); \
- emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"), \
- 0, VOIDmode, 2, TRAMP, Pmode, \
- plus_constant (TRAMP, TRAMPOLINE_SIZE), Pmode); \
-}
-
/* Clear the instruction cache from `beg' to `end'. This makes an
inline system call to SYS_cacheflush. */
#define CLEAR_INSN_CACHE(BEG, END) \
diff --git a/contrib/gcc/config/arm/mmintrin.h b/contrib/gcc/config/arm/mmintrin.h
index 4dc1d45..bed6204 100644
--- a/contrib/gcc/config/arm/mmintrin.h
+++ b/contrib/gcc/config/arm/mmintrin.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GCC.
@@ -14,8 +14,8 @@
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, 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
+ 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
@@ -31,9 +31,9 @@
typedef unsigned long long __m64, __int64;
/* Internal data types for implementing the intrinsics. */
-typedef int __v2si __attribute__ ((__mode__ (__V2SI__)));
-typedef int __v4hi __attribute__ ((__mode__ (__V4HI__)));
-typedef int __v8qi __attribute__ ((__mode__ (__V8QI__)));
+typedef int __v2si __attribute__ ((vector_size (8)));
+typedef short __v4hi __attribute__ ((vector_size (8)));
+typedef char __v8qi __attribute__ ((vector_size (8)));
/* "Convert" __m64 and __int64 into each other. */
static __inline __m64
@@ -419,7 +419,7 @@ _mm_madd_pu16 (__m64 __m1, __m64 __m2)
static __inline __m64
_mm_mulhi_pi16 (__m64 __m1, __m64 __m2)
{
- return (__m64) __builtin_arm_wmulsh ((__v4hi)__m1, (__v4hi)__m2);
+ return (__m64) __builtin_arm_wmulsm ((__v4hi)__m1, (__v4hi)__m2);
}
/* Multiply four signed 16-bit values in M1 by four signed 16-bit values in
@@ -427,7 +427,7 @@ _mm_mulhi_pi16 (__m64 __m1, __m64 __m2)
static __inline __m64
_mm_mulhi_pu16 (__m64 __m1, __m64 __m2)
{
- return (__m64) __builtin_arm_wmuluh ((__v4hi)__m1, (__v4hi)__m2);
+ return (__m64) __builtin_arm_wmulum ((__v4hi)__m1, (__v4hi)__m2);
}
/* Multiply four 16-bit values in M1 by four 16-bit values in M2 and produce
@@ -986,18 +986,18 @@ _mm_setzero_si64 (void)
the rest are reserved. */
static __inline void
-_mm_setwcx (const int __regno, const int __value)
+_mm_setwcx (const int __value, const int __regno)
{
switch (__regno)
{
- case 0: __builtin_arm_setwcx (0, __value); break;
- case 1: __builtin_arm_setwcx (1, __value); break;
- case 2: __builtin_arm_setwcx (2, __value); break;
- case 3: __builtin_arm_setwcx (3, __value); break;
- case 8: __builtin_arm_setwcx (8, __value); break;
- case 9: __builtin_arm_setwcx (9, __value); break;
- case 10: __builtin_arm_setwcx (10, __value); break;
- case 11: __builtin_arm_setwcx (11, __value); break;
+ case 0: __builtin_arm_setwcx (__value, 0); break;
+ case 1: __builtin_arm_setwcx (__value, 1); break;
+ case 2: __builtin_arm_setwcx (__value, 2); break;
+ case 3: __builtin_arm_setwcx (__value, 3); break;
+ case 8: __builtin_arm_setwcx (__value, 8); break;
+ case 9: __builtin_arm_setwcx (__value, 9); break;
+ case 10: __builtin_arm_setwcx (__value, 10); break;
+ case 11: __builtin_arm_setwcx (__value, 11); break;
default: break;
}
}
diff --git a/contrib/gcc/config/arm/netbsd-elf.h b/contrib/gcc/config/arm/netbsd-elf.h
index a8b43f6..8a01b0f 100644
--- a/contrib/gcc/config/arm/netbsd-elf.h
+++ b/contrib/gcc/config/arm/netbsd-elf.h
@@ -1,5 +1,5 @@
/* Definitions of target machine for GNU compiler, NetBSD/arm ELF version.
- Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
Contributed by Wasabi Systems, Inc.
This file is part of GCC.
@@ -16,8 +16,8 @@
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, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* Run-time Target Specification. */
#undef TARGET_VERSION
@@ -35,14 +35,12 @@
/* Default it to use ATPCS with soft-VFP. */
#undef TARGET_DEFAULT
#define TARGET_DEFAULT \
- (ARM_FLAG_APCS_32 \
- | ARM_FLAG_SOFT_FLOAT \
- | ARM_FLAG_APCS_FRAME \
- | ARM_FLAG_ATPCS \
- | ARM_FLAG_VFP \
- | ARM_FLAG_MMU_TRAPS \
+ (MASK_APCS_FRAME \
| TARGET_ENDIAN_DEFAULT)
+#undef ARM_DEFAULT_ABI
+#define ARM_DEFAULT_ABI ARM_ABI_ATPCS
+
#define TARGET_OS_CPP_BUILTINS() \
do \
{ \
@@ -57,14 +55,11 @@
#define SUBTARGET_EXTRA_ASM_SPEC \
"-matpcs %{fpic|fpie:-k} %{fPIC|fPIE:-k}"
-/* Default floating point model is soft-VFP.
- FIXME: -mhard-float currently implies FPA. */
+/* Default to full VFP if -mhard-float is specified. */
#undef SUBTARGET_ASM_FLOAT_SPEC
#define SUBTARGET_ASM_FLOAT_SPEC \
- "%{mhard-float:-mfpu=fpa} \
- %{msoft-float:-mfpu=softvfp} \
- %{!mhard-float: \
- %{!msoft-float:-mfpu=softvfp}}"
+ "%{mhard-float:{!mfpu=*:-mfpu=vfp}} \
+ %{mfloat-abi=hard:{!mfpu=*:-mfpu=vfp}}"
#undef SUBTARGET_EXTRA_SPECS
#define SUBTARGET_EXTRA_SPECS \
@@ -102,7 +97,8 @@
{ \
asm_fprintf (STREAM, "\tmov\t%Rip, %Rlr\n"); \
asm_fprintf (STREAM, "\tbl\t__mcount%s\n", \
- NEED_PLT_RELOC ? "(PLT)" : ""); \
+ (TARGET_ARM && NEED_PLT_RELOC) \
+ ? "(PLT)" : ""); \
}
/* VERY BIG NOTE: Change of structure alignment for NetBSD/arm.
@@ -140,21 +136,6 @@
#undef DEFAULT_STRUCTURE_SIZE_BOUNDARY
#define DEFAULT_STRUCTURE_SIZE_BOUNDARY 8
-/* Emit code to set up a trampoline and synchronize the caches. */
-#undef INITIALIZE_TRAMPOLINE
-#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
-do \
- { \
- emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 8)), \
- (CXT)); \
- emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 12)), \
- (FNADDR)); \
- emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"), \
- 0, VOIDmode, 2, TRAMP, Pmode, \
- plus_constant (TRAMP, TRAMPOLINE_SIZE), Pmode); \
- } \
-while (0)
-
/* Clear the instruction cache from `BEG' to `END'. This makes a
call to the ARM_SYNC_ICACHE architecture specific syscall. */
#define CLEAR_INSN_CACHE(BEG, END) \
@@ -171,3 +152,7 @@ do \
(void) sysarch (0, &s); \
} \
while (0)
+
+#undef FPUTYPE_DEFAULT
+#define FPUTYPE_DEFAULT FPUTYPE_VFP
+
diff --git a/contrib/gcc/config/arm/netbsd.h b/contrib/gcc/config/arm/netbsd.h
index 71763e6..4d14744 100644
--- a/contrib/gcc/config/arm/netbsd.h
+++ b/contrib/gcc/config/arm/netbsd.h
@@ -1,5 +1,6 @@
/* NetBSD/arm a.out version.
- Copyright (C) 1993, 1994, 1997, 1998, 2003 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1994, 1997, 1998, 2003, 2004, 2005
+ Free Software Foundation, Inc.
Contributed by Mark Brinicombe (amb@physig.ph.kcl.ac.uk)
This file is part of GCC.
@@ -16,8 +17,8 @@
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, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* Run-time Target Specification. */
#undef TARGET_VERSION
@@ -34,9 +35,8 @@
/* ARM6 family default cpu. */
#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6
-/* Default is to use APCS-32 mode. */
#undef TARGET_DEFAULT
-#define TARGET_DEFAULT (ARM_FLAG_APCS_32 | ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_FRAME | ARM_FLAG_MMU_TRAPS)
+#define TARGET_DEFAULT (MASK_APCS_FRAME)
/* Some defines for CPP.
arm32 is the NetBSD port name, so we always define arm32 and __arm32__. */
@@ -55,14 +55,10 @@
#undef CPP_SPEC
#define CPP_SPEC "\
-%(cpp_cpu_arch) %(cpp_apcs_pc) %(cpp_float) %(cpp_endian) %(netbsd_cpp_spec) \
+%(cpp_cpu_arch) %(cpp_float) %(cpp_endian) %(netbsd_cpp_spec) \
"
-/* Because TARGET_DEFAULT sets ARM_FLAG_APCS_32 */
-#undef CPP_APCS_PC_DEFAULT_SPEC
-#define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__"
-
-/* Because TARGET_DEFAULT sets ARM_FLAG_SOFT_FLOAT */
+/* Because TARGET_DEFAULT sets MASK_SOFT_FLOAT */
#undef CPP_FLOAT_DEFAULT_SPEC
#define CPP_FLOAT_DEFAULT_SPEC "-D__SOFTFP__"
@@ -142,19 +138,6 @@
#undef DEFAULT_STRUCTURE_SIZE_BOUNDARY
#define DEFAULT_STRUCTURE_SIZE_BOUNDARY 8
-/* Emit code to set up a trampoline and synchronize the caches. */
-#undef INITIALIZE_TRAMPOLINE
-#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
-{ \
- emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 8)), \
- (CXT)); \
- emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 12)), \
- (FNADDR)); \
- emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"), \
- 0, VOIDmode, 2, TRAMP, Pmode, \
- plus_constant (TRAMP, TRAMPOLINE_SIZE), Pmode); \
-}
-
/* Clear the instruction cache from `BEG' to `END'. This makes a
call to the ARM32_SYNC_ICACHE architecture specific syscall. */
#define CLEAR_INSN_CACHE(BEG, END) \
diff --git a/contrib/gcc/config/arm/pe.c b/contrib/gcc/config/arm/pe.c
index d25fd0d..f2f67d5 100644
--- a/contrib/gcc/config/arm/pe.c
+++ b/contrib/gcc/config/arm/pe.c
@@ -1,5 +1,6 @@
/* Routines for GCC for ARM/pe.
- Copyright (C) 1995, 1996, 2000, 2001, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 2000, 2001, 2002, 2004, 2005
+ Free Software Foundation, Inc.
Contributed by Doug Evans (dje@cygnus.com).
This file is part of GCC.
@@ -16,8 +17,8 @@
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, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#include "config.h"
#include "system.h"
@@ -95,7 +96,7 @@ arm_dllimport_name_p (symbol)
}
/* Mark a DECL as being dllexport'd.
- Note that we override the previous setting (eg: dllimport). */
+ Note that we override the previous setting (e.g.: dllimport). */
void
arm_mark_dllexport (decl)
@@ -107,13 +108,11 @@ arm_mark_dllexport (decl)
tree idp;
rtlname = XEXP (DECL_RTL (decl), 0);
- if (GET_CODE (rtlname) == SYMBOL_REF)
- oldname = XSTR (rtlname, 0);
- else if (GET_CODE (rtlname) == MEM
- && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
- oldname = XSTR (XEXP (rtlname, 0), 0);
- else
- abort ();
+ if (GET_CODE (rtlname) == MEM)
+ rtlname = XEXP (rtlname, 0);
+ gcc_assert (GET_CODE (rtlname) == SYMBOL_REF);
+ oldname = XSTR (rtlname, 0);
+
if (arm_dllimport_name_p (oldname))
oldname += 9;
else if (arm_dllexport_name_p (oldname))
@@ -130,7 +129,7 @@ arm_mark_dllexport (decl)
idp = get_identifier (newname);
XEXP (DECL_RTL (decl), 0) =
- gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp));
+ gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
}
/* Mark a DECL as being dllimport'd. */
@@ -146,17 +145,13 @@ arm_mark_dllimport (decl)
rtlname = XEXP (DECL_RTL (decl), 0);
- if (GET_CODE (rtlname) == SYMBOL_REF)
- oldname = XSTR (rtlname, 0);
- else if (GET_CODE (rtlname) == MEM
- && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
- oldname = XSTR (XEXP (rtlname, 0), 0);
- else
- abort ();
+ if (GET_CODE (rtlname) == MEM)
+ rtlname = XEXP (rtlname, 0);
+ gcc_assert (GET_CODE (rtlname) == SYMBOL_REF);
+ oldname = XSTR (rtlname, 0);
- if (arm_dllexport_name_p (oldname))
- abort (); /* this shouldn't happen */
- else if (arm_dllimport_name_p (oldname))
+ gcc_assert (!arm_dllexport_name_p (oldname));
+ if (arm_dllimport_name_p (oldname))
return; /* already done */
/* ??? One can well ask why we're making these checks here,
@@ -167,7 +162,7 @@ arm_mark_dllimport (decl)
&& !DECL_VIRTUAL_P (decl)
&& DECL_INITIAL (decl))
{
- error ("%Jinitialized variable '%D' is marked dllimport", decl, decl);
+ error ("initialized variable %q+D is marked dllimport", decl);
return;
}
/* Nor can they be static. */
@@ -176,7 +171,7 @@ arm_mark_dllimport (decl)
&& !DECL_VIRTUAL_P (decl)
&& 0 /*???*/)
{
- error ("%Jstatic variable '%D' is marked dllimport", decl, decl);
+ error ("static variable %q+D is marked dllimport", decl);
return;
}
@@ -200,9 +195,9 @@ arm_mark_dllimport (decl)
/* ??? At least I think that's why we do this. */
idp = get_identifier (newname);
- newrtl = gen_rtx (MEM, Pmode,
- gen_rtx (SYMBOL_REF, Pmode,
- IDENTIFIER_POINTER (idp)));
+ newrtl = gen_rtx_MEM (Pmode,
+ gen_rtx_SYMBOL_REF (Pmode,
+ IDENTIFIER_POINTER (idp)));
XEXP (DECL_RTL (decl), 0) = newrtl;
}
@@ -213,8 +208,7 @@ arm_pe_encode_section_info (decl, rtl, first)
int first ATTRIBUTE_UNUSED;
{
/* This bit is copied from arm_encode_section_info. */
- if (optimize > 0 && TREE_CONSTANT (decl)
- && (!flag_writable_strings || TREE_CODE (decl) != STRING_CST))
+ if (optimize > 0 && TREE_CONSTANT (decl))
SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
/* Mark the decl so we can tell from the rtl whether the object is
@@ -236,7 +230,7 @@ arm_pe_encode_section_info (decl, rtl, first)
{
const char *oldname = XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0);
tree idp = get_identifier (oldname + 9);
- rtx newrtl = gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp));
+ rtx newrtl = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
XEXP (DECL_RTL (decl), 0) = newrtl;
diff --git a/contrib/gcc/config/arm/pe.h b/contrib/gcc/config/arm/pe.h
index e83f97b..f96cd66 100644
--- a/contrib/gcc/config/arm/pe.h
+++ b/contrib/gcc/config/arm/pe.h
@@ -1,5 +1,6 @@
/* Definitions of target machine for GNU compiler, for ARM with PE obj format.
- Copyright (C) 1995, 1996, 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1999, 2000, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
Contributed by Doug Evans (dje@cygnus.com).
This file is part of GCC.
@@ -16,8 +17,8 @@
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, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* Enable PE specific code. */
#define ARM_PE 1
@@ -39,44 +40,17 @@
/* Get tree.c to declare a target-specific specialization of
merge_decl_attributes. */
-#define TARGET_DLLIMPORT_DECL_ATTRIBUTES
-
-/* Support the __declspec keyword by turning them into attributes.
- We currently only support: naked, dllimport, and dllexport.
- Note that the current way we do this may result in a collision with
- predefined attributes later on. This can be solved by using one attribute,
- say __declspec__, and passing args to it. The problem with that approach
- is that args are not accumulated: each new appearance would clobber any
- existing args. */
-#undef SUBTARGET_CPP_SPEC
-#define SUBTARGET_CPP_SPEC "-D__pe__ -D__declspec(x)=__attribute__((x))"
-
-
-/* Experimental addition for pr 7885.
- Ignore dllimport for functions. */
-#define TARGET_FLAG_NOP_FUN (1 << 24)
-
-#undef TARGET_NOP_FUN_DLLIMPORT
-#define TARGET_NOP_FUN_DLLIMPORT (target_flags & TARGET_FLAG_NOP_FUN)
-
-#undef SUBTARGET_SWITCHES
-#define SUBTARGET_SWITCHES \
-{ "nop-fun-dllimport", TARGET_FLAG_NOP_FUN, \
- N_("Ignore dllimport attribute for functions") }, \
-{ "no-nop-fun-dllimport", - TARGET_FLAG_NOP_FUN, "" },
+#define TARGET_DLLIMPORT_DECL_ATTRIBUTES 1
-/* Defaulting to APCS-26 support is a legacy issue. It has been done
- that way for a long time, so changing it will probably break some
- people's worlds. Support for APCS-32 is now enabled as a multilib,
- and at some point in the future APCS-32 may become the default.
- Possibly when chips that support APCS-26 are no longer made. */
+#undef SUBTARGET_CPP_SPEC
+#define SUBTARGET_CPP_SPEC "-D__pe__"
#undef TARGET_DEFAULT
-#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | TARGET_FLAG_NOP_FUN | ARM_FLAG_MMU_TRAPS)
+#define TARGET_DEFAULT (MASK_NOP_FUN_DLLIMPORT)
#undef MULTILIB_DEFAULTS
#define MULTILIB_DEFAULTS \
- { "marm", "mlittle-endian", "msoft-float", "mapcs-26", "mno-thumb-interwork" }
+ { "marm", "mlittle-endian", "msoft-float", "mno-thumb-interwork" }
#undef WCHAR_TYPE
#define WCHAR_TYPE "short unsigned int"
@@ -90,13 +64,11 @@
call_used_regs [11] = 1;
-/* Define this macro if in some cases global symbols from one translation
- unit may not be bound to undefined symbols in another translation unit
- without user intervention. For instance, under Microsoft Windows
- symbols must be explicitly imported from shared libraries (DLLs). */
-#define MULTIPLE_SYMBOL_SPACES
+/* PE/COFF uses explicit import from shared libraries. */
+#define MULTIPLE_SYMBOL_SPACES 1
#define TARGET_ASM_UNIQUE_SECTION arm_pe_unique_section
+#define TARGET_ASM_FUNCTION_RODATA_SECTION default_no_function_rodata_section
#define SUPPORTS_ONE_ONLY 1
@@ -121,7 +93,7 @@
drectve_section (); \
fprintf (STREAM, "\t.ascii \" -export:%s\"\n", \
arm_strip_name_encoding (NAME)); \
- function_section (DECL); \
+ switch_to_section (function_section (DECL)); \
} \
ARM_DECLARE_FUNCTION_NAME (STREAM, NAME, DECL); \
if (TARGET_THUMB) \
@@ -158,11 +130,11 @@
{ \
if (arm_dllexport_name_p (NAME)) \
{ \
- enum in_section save_section = in_section; \
+ section *save_section = in_section; \
drectve_section (); \
fprintf (STREAM, "\t.ascii \" -export:%s\"\n",\
arm_strip_name_encoding (NAME)); \
- switch_to_section (save_section, (DECL)); \
+ switch_to_section (save_section); \
} \
ASM_OUTPUT_LABEL ((STREAM), (NAME)); \
} \
@@ -172,50 +144,6 @@
#define DRECTVE_SECTION_ASM_OP "\t.section .drectve"
-/* A list of other sections which the compiler might be "in" at any
- given time. */
-
-#undef EXTRA_SECTIONS
-#define EXTRA_SECTIONS in_drectve
-
-/* A list of extra section function definitions. */
-
-#undef EXTRA_SECTION_FUNCTIONS
-#define EXTRA_SECTION_FUNCTIONS \
- DRECTVE_SECTION_FUNCTION \
- SWITCH_TO_SECTION_FUNCTION
-
-#define DRECTVE_SECTION_FUNCTION \
-void \
-drectve_section (void) \
-{ \
- if (in_section != in_drectve) \
- { \
- fprintf (asm_out_file, "%s\n", DRECTVE_SECTION_ASM_OP); \
- in_section = in_drectve; \
- } \
-}
-
-/* Switch to SECTION (an `enum in_section').
-
- ??? This facility should be provided by GCC proper.
- The problem is that we want to temporarily switch sections in
- ASM_DECLARE_OBJECT_NAME and then switch back to the original section
- afterwards. */
-#define SWITCH_TO_SECTION_FUNCTION \
-static void \
-switch_to_section (enum in_section section, tree decl) \
-{ \
- switch (section) \
- { \
- case in_text: text_section (); break; \
- case in_data: data_section (); break; \
- case in_named: named_section (decl, NULL, 0); break; \
- case in_readonly_data: readonly_data_section (); break; \
- case in_ctors: ctors_section (); break; \
- case in_dtors: dtors_section (); break; \
- case in_drectve: drectve_section (); break; \
- default: abort (); break; \
- } \
-}
-
+#define drectve_section() \
+ (fprintf (asm_out_file, "%s\n", DRECTVE_SECTION_ASM_OP), \
+ in_section = NULL)
diff --git a/contrib/gcc/config/arm/pe.opt b/contrib/gcc/config/arm/pe.opt
new file mode 100644
index 0000000..f3d6d8b
--- /dev/null
+++ b/contrib/gcc/config/arm/pe.opt
@@ -0,0 +1,24 @@
+; PE-specific options for the ARM port
+
+; Copyright (C) 2005 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.
+;
+; 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.
+
+mnop-fun-dllimport
+Target Report Mask(NOP_FUN_DLLIMPORT)
+Ignore dllimport attribute for functions
diff --git a/contrib/gcc/config/arm/pr-support.c b/contrib/gcc/config/arm/pr-support.c
new file mode 100644
index 0000000..0e750bf
--- /dev/null
+++ b/contrib/gcc/config/arm/pr-support.c
@@ -0,0 +1,381 @@
+/* ARM EABI compliant unwinding routines
+ Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Contributed by Paul Brook
+
+ 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, 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.)
+
+ 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 program; see the file COPYING. If not, write to
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+#include "unwind.h"
+
+/* We add a prototype for abort here to avoid creating a dependency on
+ target headers. */
+extern void abort (void);
+
+typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
+
+/* Misc constants. */
+#define R_IP 12
+#define R_SP 13
+#define R_LR 14
+#define R_PC 15
+
+#define uint32_highbit (((_uw) 1) << 31)
+
+void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
+
+/* Unwind descriptors. */
+
+typedef struct
+{
+ _uw16 length;
+ _uw16 offset;
+} EHT16;
+
+typedef struct
+{
+ _uw length;
+ _uw offset;
+} EHT32;
+
+/* Calculate the address encoded by a 31-bit self-relative offset at address
+ P. Copy of routine in unwind-arm.c. */
+
+static inline _uw
+selfrel_offset31 (const _uw *p)
+{
+ _uw offset;
+
+ offset = *p;
+ /* Sign extend to 32 bits. */
+ if (offset & (1 << 30))
+ offset |= 1u << 31;
+
+ return offset + (_uw) p;
+}
+
+
+/* Personality routine helper functions. */
+
+#define CODE_FINISH (0xb0)
+
+/* Return the next byte of unwinding information, or CODE_FINISH if there is
+ no data remaining. */
+static inline _uw8
+next_unwind_byte (__gnu_unwind_state * uws)
+{
+ _uw8 b;
+
+ if (uws->bytes_left == 0)
+ {
+ /* Load another word */
+ if (uws->words_left == 0)
+ return CODE_FINISH; /* Nothing left. */
+ uws->words_left--;
+ uws->data = *(uws->next++);
+ uws->bytes_left = 3;
+ }
+ else
+ uws->bytes_left--;
+
+ /* Extract the most significant byte. */
+ b = (uws->data >> 24) & 0xff;
+ uws->data <<= 8;
+ return b;
+}
+
+/* Execute the unwinding instructions described by UWS. */
+_Unwind_Reason_Code
+__gnu_unwind_execute (_Unwind_Context * context, __gnu_unwind_state * uws)
+{
+ _uw op;
+ int set_pc;
+ _uw reg;
+
+ set_pc = 0;
+ for (;;)
+ {
+ op = next_unwind_byte (uws);
+ if (op == CODE_FINISH)
+ {
+ /* If we haven't already set pc then copy it from lr. */
+ if (!set_pc)
+ {
+ _Unwind_VRS_Get (context, _UVRSC_CORE, R_LR, _UVRSD_UINT32,
+ &reg);
+ _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32,
+ &reg);
+ set_pc = 1;
+ }
+ /* Drop out of the loop. */
+ break;
+ }
+ if ((op & 0x80) == 0)
+ {
+ /* vsp = vsp +- (imm6 << 2 + 4). */
+ _uw offset;
+
+ offset = ((op & 0x3f) << 2) + 4;
+ _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
+ if (op & 0x40)
+ reg -= offset;
+ else
+ reg += offset;
+ _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
+ continue;
+ }
+
+ if ((op & 0xf0) == 0x80)
+ {
+ op = (op << 8) | next_unwind_byte (uws);
+ if (op == 0x8000)
+ {
+ /* Refuse to unwind. */
+ return _URC_FAILURE;
+ }
+ /* Pop r4-r15 under mask. */
+ op = (op << 4) & 0xfff0;
+ if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32)
+ != _UVRSR_OK)
+ return _URC_FAILURE;
+ if (op & (1 << R_PC))
+ set_pc = 1;
+ continue;
+ }
+ if ((op & 0xf0) == 0x90)
+ {
+ op &= 0xf;
+ if (op == 13 || op == 15)
+ /* Reserved. */
+ return _URC_FAILURE;
+ /* vsp = r[nnnn]. */
+ _Unwind_VRS_Get (context, _UVRSC_CORE, op, _UVRSD_UINT32, &reg);
+ _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
+ continue;
+ }
+ if ((op & 0xf0) == 0xa0)
+ {
+ /* Pop r4-r[4+nnn], [lr]. */
+ _uw mask;
+
+ mask = (0xff0 >> (7 - (op & 7))) & 0xff0;
+ if (op & 8)
+ mask |= (1 << R_LR);
+ if (_Unwind_VRS_Pop (context, _UVRSC_CORE, mask, _UVRSD_UINT32)
+ != _UVRSR_OK)
+ return _URC_FAILURE;
+ continue;
+ }
+ if ((op & 0xf0) == 0xb0)
+ {
+ /* op == 0xb0 already handled. */
+ if (op == 0xb1)
+ {
+ op = next_unwind_byte (uws);
+ if (op == 0 || ((op & 0xf0) != 0))
+ /* Spare. */
+ return _URC_FAILURE;
+ /* Pop r0-r4 under mask. */
+ if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32)
+ != _UVRSR_OK)
+ return _URC_FAILURE;
+ continue;
+ }
+ if (op == 0xb2)
+ {
+ /* vsp = vsp + 0x204 + (uleb128 << 2). */
+ int shift;
+
+ _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
+ &reg);
+ op = next_unwind_byte (uws);
+ shift = 2;
+ while (op & 0x80)
+ {
+ reg += ((op & 0x7f) << shift);
+ shift += 7;
+ op = next_unwind_byte (uws);
+ }
+ reg += ((op & 0x7f) << shift) + 0x204;
+ _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
+ &reg);
+ continue;
+ }
+ if (op == 0xb3)
+ {
+ /* Pop VFP registers with fldmx. */
+ op = next_unwind_byte (uws);
+ op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
+ if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX)
+ != _UVRSR_OK)
+ return _URC_FAILURE;
+ continue;
+ }
+ if ((op & 0xfc) == 0xb4)
+ {
+ /* Pop FPA E[4]-E[4+nn]. */
+ op = 0x40000 | ((op & 3) + 1);
+ if (_Unwind_VRS_Pop (context, _UVRSC_FPA, op, _UVRSD_FPAX)
+ != _UVRSR_OK)
+ return _URC_FAILURE;
+ continue;
+ }
+ /* op & 0xf8 == 0xb8. */
+ /* Pop VFP D[8]-D[8+nnn] with fldmx. */
+ op = 0x80000 | ((op & 7) + 1);
+ if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX)
+ != _UVRSR_OK)
+ return _URC_FAILURE;
+ continue;
+ }
+ if ((op & 0xf0) == 0xc0)
+ {
+ if (op == 0xc6)
+ {
+ /* Pop iWMMXt D registers. */
+ op = next_unwind_byte (uws);
+ op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
+ if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64)
+ != _UVRSR_OK)
+ return _URC_FAILURE;
+ continue;
+ }
+ if (op == 0xc7)
+ {
+ op = next_unwind_byte (uws);
+ if (op == 0 || (op & 0xf0) != 0)
+ /* Spare. */
+ return _URC_FAILURE;
+ /* Pop iWMMXt wCGR{3,2,1,0} under mask. */
+ if (_Unwind_VRS_Pop (context, _UVRSC_WMMXC, op, _UVRSD_UINT32)
+ != _UVRSR_OK)
+ return _URC_FAILURE;
+ continue;
+ }
+ if ((op & 0xf8) == 0xc0)
+ {
+ /* Pop iWMMXt wR[10]-wR[10+nnn]. */
+ op = 0xa0000 | ((op & 0xf) + 1);
+ if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64)
+ != _UVRSR_OK)
+ return _URC_FAILURE;
+ continue;
+ }
+ if (op == 0xc8)
+ {
+ /* Pop FPA registers. */
+ op = next_unwind_byte (uws);
+ op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
+ if (_Unwind_VRS_Pop (context, _UVRSC_FPA, op, _UVRSD_FPAX)
+ != _UVRSR_OK)
+ return _URC_FAILURE;
+ continue;
+ }
+ if (op == 0xc9)
+ {
+ /* Pop VFP registers with fldmd. */
+ op = next_unwind_byte (uws);
+ op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
+ if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
+ != _UVRSR_OK)
+ return _URC_FAILURE;
+ continue;
+ }
+ /* Spare. */
+ return _URC_FAILURE;
+ }
+ if ((op & 0xf8) == 0xd0)
+ {
+ /* Pop VFP D[8]-D[8+nnn] with fldmd. */
+ op = 0x80000 | ((op & 7) + 1);
+ if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
+ != _UVRSR_OK)
+ return _URC_FAILURE;
+ continue;
+ }
+ /* Spare. */
+ return _URC_FAILURE;
+ }
+ return _URC_OK;
+}
+
+
+/* Execute the unwinding instructions associated with a frame. UCBP and
+ CONTEXT are the current exception object and virtual CPU state
+ respectively. */
+
+_Unwind_Reason_Code
+__gnu_unwind_frame (_Unwind_Control_Block * ucbp, _Unwind_Context * context)
+{
+ _uw *ptr;
+ __gnu_unwind_state uws;
+
+ ptr = (_uw *) ucbp->pr_cache.ehtp;
+ /* Skip over the personality routine address. */
+ ptr++;
+ /* Setup the unwinder state. */
+ uws.data = (*ptr) << 8;
+ uws.next = ptr + 1;
+ uws.bytes_left = 3;
+ uws.words_left = ((*ptr) >> 24) & 0xff;
+
+ return __gnu_unwind_execute (context, &uws);
+}
+
+/* Get the _Unwind_Control_Block from an _Unwind_Context. */
+
+static inline _Unwind_Control_Block *
+unwind_UCB_from_context (_Unwind_Context * context)
+{
+ return (_Unwind_Control_Block *) _Unwind_GetGR (context, R_IP);
+}
+
+/* Get the start address of the function being unwound. */
+
+_Unwind_Ptr
+_Unwind_GetRegionStart (_Unwind_Context * context)
+{
+ _Unwind_Control_Block *ucbp;
+
+ ucbp = unwind_UCB_from_context (context);
+ return (_Unwind_Ptr) ucbp->pr_cache.fnstart;
+}
+
+/* Find the Language specific exception data. */
+
+void *
+_Unwind_GetLanguageSpecificData (_Unwind_Context * context)
+{
+ _Unwind_Control_Block *ucbp;
+ _uw *ptr;
+
+ /* Get a pointer to the exception table entry. */
+ ucbp = unwind_UCB_from_context (context);
+ ptr = (_uw *) ucbp->pr_cache.ehtp;
+ /* Skip the personality routine address. */
+ ptr++;
+ /* Skip the unwind opcodes. */
+ ptr += (((*ptr) >> 24) & 0xff) + 1;
+
+ return ptr;
+}
+
diff --git a/contrib/gcc/config/arm/predicates.md b/contrib/gcc/config/arm/predicates.md
new file mode 100644
index 0000000..4a08204
--- /dev/null
+++ b/contrib/gcc/config/arm/predicates.md
@@ -0,0 +1,458 @@
+;; Predicate definitions for ARM and Thumb
+;; Copyright (C) 2004 Free Software Foundation, Inc.
+;; Contributed by ARM Ltd.
+
+;; 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.
+
+;; 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.
+
+(define_predicate "s_register_operand"
+ (match_code "reg,subreg")
+{
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+ /* We don't consider registers whose class is NO_REGS
+ to be a register operand. */
+ /* XXX might have to check for lo regs only for thumb ??? */
+ return (GET_CODE (op) == REG
+ && (REGNO (op) >= FIRST_PSEUDO_REGISTER
+ || REGNO_REG_CLASS (REGNO (op)) != NO_REGS));
+})
+
+;; Any hard register.
+(define_predicate "arm_hard_register_operand"
+ (match_code "reg")
+{
+ return REGNO (op) < FIRST_PSEUDO_REGISTER;
+})
+
+;; Any core register, or any pseudo. */
+(define_predicate "arm_general_register_operand"
+ (match_code "reg,subreg")
+{
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+
+ return (GET_CODE (op) == REG
+ && (REGNO (op) <= LAST_ARM_REGNUM
+ || REGNO (op) >= FIRST_PSEUDO_REGISTER));
+})
+
+(define_predicate "f_register_operand"
+ (match_code "reg,subreg")
+{
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+
+ /* We don't consider registers whose class is NO_REGS
+ to be a register operand. */
+ return (GET_CODE (op) == REG
+ && (REGNO (op) >= FIRST_PSEUDO_REGISTER
+ || REGNO_REG_CLASS (REGNO (op)) == FPA_REGS));
+})
+
+;; Reg, subreg(reg) or const_int.
+(define_predicate "reg_or_int_operand"
+ (ior (match_code "const_int")
+ (match_operand 0 "s_register_operand")))
+
+(define_predicate "arm_immediate_operand"
+ (and (match_code "const_int")
+ (match_test "const_ok_for_arm (INTVAL (op))")))
+
+(define_predicate "arm_neg_immediate_operand"
+ (and (match_code "const_int")
+ (match_test "const_ok_for_arm (-INTVAL (op))")))
+
+(define_predicate "arm_not_immediate_operand"
+ (and (match_code "const_int")
+ (match_test "const_ok_for_arm (~INTVAL (op))")))
+
+;; Something valid on the RHS of an ARM data-processing instruction
+(define_predicate "arm_rhs_operand"
+ (ior (match_operand 0 "s_register_operand")
+ (match_operand 0 "arm_immediate_operand")))
+
+(define_predicate "arm_rhsm_operand"
+ (ior (match_operand 0 "arm_rhs_operand")
+ (match_operand 0 "memory_operand")))
+
+(define_predicate "arm_add_operand"
+ (ior (match_operand 0 "arm_rhs_operand")
+ (match_operand 0 "arm_neg_immediate_operand")))
+
+(define_predicate "arm_addimm_operand"
+ (ior (match_operand 0 "arm_immediate_operand")
+ (match_operand 0 "arm_neg_immediate_operand")))
+
+(define_predicate "arm_not_operand"
+ (ior (match_operand 0 "arm_rhs_operand")
+ (match_operand 0 "arm_not_immediate_operand")))
+
+;; True if the operand is a memory reference which contains an
+;; offsettable address.
+(define_predicate "offsettable_memory_operand"
+ (and (match_code "mem")
+ (match_test
+ "offsettable_address_p (reload_completed | reload_in_progress,
+ mode, XEXP (op, 0))")))
+
+;; True if the operand is a memory operand that does not have an
+;; automodified base register (and thus will not generate output reloads).
+(define_predicate "call_memory_operand"
+ (and (match_code "mem")
+ (and (match_test "GET_RTX_CLASS (GET_CODE (XEXP (op, 0)))
+ != RTX_AUTOINC")
+ (match_operand 0 "memory_operand"))))
+
+(define_predicate "arm_reload_memory_operand"
+ (and (match_code "mem,reg,subreg")
+ (match_test "(!CONSTANT_P (op)
+ && (true_regnum(op) == -1
+ || (GET_CODE (op) == REG
+ && REGNO (op) >= FIRST_PSEUDO_REGISTER)))")))
+
+;; True for valid operands for the rhs of an floating point insns.
+;; Allows regs or certain consts on FPA, just regs for everything else.
+(define_predicate "arm_float_rhs_operand"
+ (ior (match_operand 0 "s_register_operand")
+ (and (match_code "const_double")
+ (match_test "TARGET_FPA && arm_const_double_rtx (op)"))))
+
+(define_predicate "arm_float_add_operand"
+ (ior (match_operand 0 "arm_float_rhs_operand")
+ (and (match_code "const_double")
+ (match_test "TARGET_FPA && neg_const_double_rtx_ok_for_fpa (op)"))))
+
+(define_predicate "vfp_compare_operand"
+ (ior (match_operand 0 "s_register_operand")
+ (and (match_code "const_double")
+ (match_test "arm_const_double_rtx (op)"))))
+
+(define_predicate "arm_float_compare_operand"
+ (if_then_else (match_test "TARGET_VFP")
+ (match_operand 0 "vfp_compare_operand")
+ (match_operand 0 "arm_float_rhs_operand")))
+
+;; True for valid index operands.
+(define_predicate "index_operand"
+ (ior (match_operand 0 "s_register_operand")
+ (and (match_operand 0 "immediate_operand")
+ (match_test "(GET_CODE (op) != CONST_INT
+ || (INTVAL (op) < 4096 && INTVAL (op) > -4096))"))))
+
+;; True for operators that can be combined with a shift in ARM state.
+(define_special_predicate "shiftable_operator"
+ (and (match_code "plus,minus,ior,xor,and")
+ (match_test "mode == GET_MODE (op)")))
+
+;; True for logical binary operators.
+(define_special_predicate "logical_binary_operator"
+ (and (match_code "ior,xor,and")
+ (match_test "mode == GET_MODE (op)")))
+
+;; True for shift operators.
+(define_special_predicate "shift_operator"
+ (and (ior (ior (and (match_code "mult")
+ (match_test "power_of_two_operand (XEXP (op, 1), mode)"))
+ (and (match_code "rotate")
+ (match_test "GET_CODE (XEXP (op, 1)) == CONST_INT
+ && ((unsigned HOST_WIDE_INT) INTVAL (XEXP (op, 1))) < 32")))
+ (match_code "ashift,ashiftrt,lshiftrt,rotatert"))
+ (match_test "mode == GET_MODE (op)")))
+
+;; True for EQ & NE
+(define_special_predicate "equality_operator"
+ (match_code "eq,ne"))
+
+;; True for comparisons other than LTGT or UNEQ.
+(define_special_predicate "arm_comparison_operator"
+ (match_code "eq,ne,le,lt,ge,gt,geu,gtu,leu,ltu,unordered,ordered,unlt,unle,unge,ungt"))
+
+(define_special_predicate "minmax_operator"
+ (and (match_code "smin,smax,umin,umax")
+ (match_test "mode == GET_MODE (op)")))
+
+(define_special_predicate "cc_register"
+ (and (match_code "reg")
+ (and (match_test "REGNO (op) == CC_REGNUM")
+ (ior (match_test "mode == GET_MODE (op)")
+ (match_test "mode == VOIDmode && GET_MODE_CLASS (GET_MODE (op)) == MODE_CC")))))
+
+(define_special_predicate "dominant_cc_register"
+ (match_code "reg")
+{
+ if (mode == VOIDmode)
+ {
+ mode = GET_MODE (op);
+
+ if (GET_MODE_CLASS (mode) != MODE_CC)
+ return false;
+ }
+
+ return (cc_register (op, mode)
+ && (mode == CC_DNEmode
+ || mode == CC_DEQmode
+ || mode == CC_DLEmode
+ || mode == CC_DLTmode
+ || mode == CC_DGEmode
+ || mode == CC_DGTmode
+ || mode == CC_DLEUmode
+ || mode == CC_DLTUmode
+ || mode == CC_DGEUmode
+ || mode == CC_DGTUmode));
+})
+
+(define_special_predicate "arm_extendqisi_mem_op"
+ (and (match_operand 0 "memory_operand")
+ (match_test "arm_legitimate_address_p (mode, XEXP (op, 0), SIGN_EXTEND,
+ 0)")))
+
+(define_predicate "power_of_two_operand"
+ (match_code "const_int")
+{
+ HOST_WIDE_INT value = INTVAL (op);
+
+ return value != 0 && (value & (value - 1)) == 0;
+})
+
+(define_predicate "nonimmediate_di_operand"
+ (match_code "reg,subreg,mem")
+{
+ if (s_register_operand (op, mode))
+ return true;
+
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+
+ return GET_CODE (op) == MEM && memory_address_p (DImode, XEXP (op, 0));
+})
+
+(define_predicate "di_operand"
+ (ior (match_code "const_int,const_double")
+ (and (match_code "reg,subreg,mem")
+ (match_operand 0 "nonimmediate_di_operand"))))
+
+(define_predicate "nonimmediate_soft_df_operand"
+ (match_code "reg,subreg,mem")
+{
+ if (s_register_operand (op, mode))
+ return true;
+
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+
+ return GET_CODE (op) == MEM && memory_address_p (DFmode, XEXP (op, 0));
+})
+
+(define_predicate "soft_df_operand"
+ (ior (match_code "const_double")
+ (and (match_code "reg,subreg,mem")
+ (match_operand 0 "nonimmediate_soft_df_operand"))))
+
+(define_predicate "const_shift_operand"
+ (and (match_code "const_int")
+ (ior (match_operand 0 "power_of_two_operand")
+ (match_test "((unsigned HOST_WIDE_INT) INTVAL (op)) < 32"))))
+
+
+(define_special_predicate "load_multiple_operation"
+ (match_code "parallel")
+{
+ HOST_WIDE_INT count = XVECLEN (op, 0);
+ int dest_regno;
+ rtx src_addr;
+ HOST_WIDE_INT i = 1, base = 0;
+ rtx elt;
+
+ if (count <= 1
+ || GET_CODE (XVECEXP (op, 0, 0)) != SET)
+ return false;
+
+ /* Check to see if this might be a write-back. */
+ if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS)
+ {
+ i++;
+ base = 1;
+
+ /* Now check it more carefully. */
+ if (GET_CODE (SET_DEST (elt)) != REG
+ || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG
+ || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT
+ || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 1) * 4)
+ return false;
+ }
+
+ /* Perform a quick check so we don't blow up below. */
+ if (count <= i
+ || GET_CODE (XVECEXP (op, 0, i - 1)) != SET
+ || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != REG
+ || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != MEM)
+ return false;
+
+ dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, i - 1)));
+ src_addr = XEXP (SET_SRC (XVECEXP (op, 0, i - 1)), 0);
+
+ for (; i < count; i++)
+ {
+ elt = XVECEXP (op, 0, i);
+
+ if (GET_CODE (elt) != SET
+ || GET_CODE (SET_DEST (elt)) != REG
+ || GET_MODE (SET_DEST (elt)) != SImode
+ || REGNO (SET_DEST (elt)) != (unsigned int)(dest_regno + i - base)
+ || GET_CODE (SET_SRC (elt)) != MEM
+ || GET_MODE (SET_SRC (elt)) != SImode
+ || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
+ || !rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
+ || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
+ || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != (i - base) * 4)
+ return false;
+ }
+
+ return true;
+})
+
+(define_special_predicate "store_multiple_operation"
+ (match_code "parallel")
+{
+ HOST_WIDE_INT count = XVECLEN (op, 0);
+ int src_regno;
+ rtx dest_addr;
+ HOST_WIDE_INT i = 1, base = 0;
+ rtx elt;
+
+ if (count <= 1
+ || GET_CODE (XVECEXP (op, 0, 0)) != SET)
+ return false;
+
+ /* Check to see if this might be a write-back. */
+ if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS)
+ {
+ i++;
+ base = 1;
+
+ /* Now check it more carefully. */
+ if (GET_CODE (SET_DEST (elt)) != REG
+ || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG
+ || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT
+ || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 1) * 4)
+ return false;
+ }
+
+ /* Perform a quick check so we don't blow up below. */
+ if (count <= i
+ || GET_CODE (XVECEXP (op, 0, i - 1)) != SET
+ || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != MEM
+ || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != REG)
+ return false;
+
+ src_regno = REGNO (SET_SRC (XVECEXP (op, 0, i - 1)));
+ dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, i - 1)), 0);
+
+ for (; i < count; i++)
+ {
+ elt = XVECEXP (op, 0, i);
+
+ if (GET_CODE (elt) != SET
+ || GET_CODE (SET_SRC (elt)) != REG
+ || GET_MODE (SET_SRC (elt)) != SImode
+ || REGNO (SET_SRC (elt)) != (unsigned int)(src_regno + i - base)
+ || GET_CODE (SET_DEST (elt)) != MEM
+ || GET_MODE (SET_DEST (elt)) != SImode
+ || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
+ || !rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
+ || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
+ || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != (i - base) * 4)
+ return false;
+ }
+
+ return true;
+})
+
+(define_special_predicate "multi_register_push"
+ (match_code "parallel")
+{
+ if ((GET_CODE (XVECEXP (op, 0, 0)) != SET)
+ || (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC)
+ || (XINT (SET_SRC (XVECEXP (op, 0, 0)), 1) != UNSPEC_PUSH_MULT))
+ return false;
+
+ return true;
+})
+
+;;-------------------------------------------------------------------------
+;;
+;; Thumb predicates
+;;
+
+(define_predicate "thumb_cmp_operand"
+ (ior (and (match_code "reg,subreg")
+ (match_operand 0 "s_register_operand"))
+ (and (match_code "const_int")
+ (match_test "((unsigned HOST_WIDE_INT) INTVAL (op)) < 256"))))
+
+(define_predicate "thumb_cmpneg_operand"
+ (and (match_code "const_int")
+ (match_test "INTVAL (op) < 0 && INTVAL (op) > -256")))
+
+;; Return TRUE if a result can be stored in OP without clobbering the
+;; condition code register. Prior to reload we only accept a
+;; register. After reload we have to be able to handle memory as
+;; well, since a pseudo may not get a hard reg and reload cannot
+;; handle output-reloads on jump insns.
+
+;; We could possibly handle mem before reload as well, but that might
+;; complicate things with the need to handle increment
+;; side-effects.
+(define_predicate "thumb_cbrch_target_operand"
+ (and (match_code "reg,subreg,mem")
+ (ior (match_operand 0 "s_register_operand")
+ (and (match_test "reload_in_progress || reload_completed")
+ (match_operand 0 "memory_operand")))))
+
+;;-------------------------------------------------------------------------
+;;
+;; MAVERICK predicates
+;;
+
+(define_predicate "cirrus_register_operand"
+ (match_code "reg,subreg")
+{
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+
+ return (GET_CODE (op) == REG
+ && (REGNO_REG_CLASS (REGNO (op)) == CIRRUS_REGS
+ || REGNO_REG_CLASS (REGNO (op)) == GENERAL_REGS));
+})
+
+(define_predicate "cirrus_fp_register"
+ (match_code "reg,subreg")
+{
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+
+ return (GET_CODE (op) == REG
+ && (REGNO (op) >= FIRST_PSEUDO_REGISTER
+ || REGNO_REG_CLASS (REGNO (op)) == CIRRUS_REGS));
+})
+
+(define_predicate "cirrus_shift_const"
+ (and (match_code "const_int")
+ (match_test "((unsigned HOST_WIDE_INT) INTVAL (op)) < 64")))
+
+
diff --git a/contrib/gcc/config/arm/rtems-elf.h b/contrib/gcc/config/arm/rtems-elf.h
index a736ee1..f71e582 100644
--- a/contrib/gcc/config/arm/rtems-elf.h
+++ b/contrib/gcc/config/arm/rtems-elf.h
@@ -1,5 +1,5 @@
/* Definitions for RTEMS based ARM systems using ELF
- Copyright (C) 2000, 2002 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2002, 2005 Free Software Foundation, Inc.
This file is part of GCC.
@@ -15,8 +15,8 @@
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* Run-time Target Specification. */
#undef TARGET_VERSION
@@ -29,3 +29,18 @@
builtin_define ("__rtems__"); \
builtin_assert ("system=rtems"); \
} while (0)
+
+/*
+ * The default in gcc now is soft-float, but gcc misses it to
+ * pass it to the assembler.
+ */
+#undef SUBTARGET_EXTRA_ASM_SPEC
+#define SUBTARGET_EXTRA_ASM_SPEC "\
+ %{!mhard-float: %{!msoft-float:-mfpu=softfpa}}"
+
+/*
+ * The default includes --start-group and --end-group which conflicts
+ * with how this used to be defined.
+ */
+#undef LINK_GCC_C_SEQUENCE_SPEC
+#define LINK_GCC_C_SEQUENCE_SPEC "%G %L"
diff --git a/contrib/gcc/config/arm/semi.h b/contrib/gcc/config/arm/semi.h
index 2ab06cb..0de57d6 100644
--- a/contrib/gcc/config/arm/semi.h
+++ b/contrib/gcc/config/arm/semi.h
@@ -1,5 +1,6 @@
/* Definitions of target machine for GNU compiler. ARM on semi-hosted platform
- Copyright (C) 1994, 1995, 1996, 1997, 2001 Free Software Foundation, Inc.
+ Copyright (C) 1994, 1995, 1996, 1997, 2001, 2004, 2005
+ Free Software Foundation, Inc.
Contributed by Richard Earnshaw (richard.earnshaw@arm.com)
This file is part of GCC.
@@ -16,8 +17,8 @@
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, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#define STARTFILE_SPEC "crt0.o%s"
@@ -37,8 +38,12 @@
#define TARGET_VERSION fputs (" (ARM/semi-hosted)", stderr);
#endif
+#ifndef TARGET_DEFAULT_FLOAT_ABI
+#define TARGET_DEFAULT_FLOAT_ABI ARM_FLOAT_ABI_HARD
+#endif
+
#ifndef TARGET_DEFAULT
-#define TARGET_DEFAULT (ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME | ARM_FLAG_MMU_TRAPS)
+#define TARGET_DEFAULT (MASK_APCS_FRAME)
#endif
#ifndef SUBTARGET_EXTRA_SPECS
@@ -64,10 +69,8 @@
%{mcpu=*:-mcpu=%*} \
%{march=*:-march=%*} \
%{mapcs-float:-mfloat} \
-%{msoft-float:-mfpu=softfpa} \
+%{msoft-float:-mfloat-abi=soft} %{mhard-float:-mfloat-abi=hard} \
+%{mfloat-abi=*} %{mfpu=*} \
%{mthumb-interwork:-mthumb-interwork} \
%(subtarget_extra_asm_spec)"
#endif
-
-#undef CPP_APCS_PC_DEFAULT_SPEC
-#define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__"
diff --git a/contrib/gcc/config/arm/semiaof.h b/contrib/gcc/config/arm/semiaof.h
index 19a6cf8..9038f0d 100644
--- a/contrib/gcc/config/arm/semiaof.h
+++ b/contrib/gcc/config/arm/semiaof.h
@@ -1,6 +1,6 @@
/* Definitions of target machine for GNU compiler. ARM on semi-hosted platform
AOF Syntax assembler.
- Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997, 2004 Free Software Foundation, Inc.
Contributed by Richard Earnshaw (richard.earnshaw@armltd.co.uk)
This file is part of GCC.
@@ -17,8 +17,8 @@
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, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#define TARGET_OS_CPP_BUILTINS() \
do { \
@@ -26,17 +26,15 @@
builtin_define_std ("semi"); \
} while (0)
-#define ASM_SPEC "%{g -g} -arch 4 \
--apcs 3%{mapcs-32:/32bit}%{mapcs-26:/26bit}%{!mapcs-26:%{!macps-32:/32bit}}"
+#define ASM_SPEC "%{g -g} -arch 4 -apcs 3/32bit"
#define LIB_SPEC "%{Eb: armlib_h.32b%s}%{!Eb: armlib_h.32l%s}"
#define TARGET_VERSION fputs (" (ARM/semi-hosted)", stderr);
-#define TARGET_DEFAULT (ARM_FLAG_APCS_32 | ARM_FLAG_MMU_TRAPS)
+#define TARGET_DEFAULT_FLOAT_ABI ARM_FLOAT_ABI_HARD
+
+#define TARGET_DEFAULT (0)
/* The Norcroft C library defines size_t as "unsigned int". */
#define SIZE_TYPE "unsigned int"
-
-#undef CPP_APCS_PC_DEFAULT_SPEC
-#define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__"
diff --git a/contrib/gcc/config/arm/strongarm-coff.h b/contrib/gcc/config/arm/strongarm-coff.h
index 77dab37..0ba32ce 100644
--- a/contrib/gcc/config/arm/strongarm-coff.h
+++ b/contrib/gcc/config/arm/strongarm-coff.h
@@ -16,8 +16,8 @@
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* Run-time Target Specification. */
#ifndef SUBTARGET_CPU_DEFAULT
diff --git a/contrib/gcc/config/arm/strongarm-elf.h b/contrib/gcc/config/arm/strongarm-elf.h
index 476b2e4..84c2099 100644
--- a/contrib/gcc/config/arm/strongarm-elf.h
+++ b/contrib/gcc/config/arm/strongarm-elf.h
@@ -16,8 +16,8 @@
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* Run-time Target Specification. */
#ifndef TARGET_VERSION
diff --git a/contrib/gcc/config/arm/strongarm-pe.h b/contrib/gcc/config/arm/strongarm-pe.h
index bb123e5..f1a13c0 100644
--- a/contrib/gcc/config/arm/strongarm-pe.h
+++ b/contrib/gcc/config/arm/strongarm-pe.h
@@ -16,8 +16,8 @@
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, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#undef TARGET_VERSION
#define TARGET_VERSION fputs (" (StrongARM/PE)", stderr);
diff --git a/contrib/gcc/config/arm/symbian.h b/contrib/gcc/config/arm/symbian.h
new file mode 100644
index 0000000..af1ba9a
--- /dev/null
+++ b/contrib/gcc/config/arm/symbian.h
@@ -0,0 +1,101 @@
+/* Configuration file for Symbian OS on ARM processors.
+ Copyright (C) 2004, 2005
+ Free Software Foundation, Inc.
+ Contributed by CodeSourcery, LLC
+
+ 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.
+
+ 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. */
+
+/* Do not expand builtin functions (unless explicitly prefixed with
+ "__builtin"). Symbian OS code relies on properties of the standard
+ library that go beyond those guaranteed by the ANSI/ISO standard.
+ For example, "memcpy" works even with overlapping memory, like
+ "memmove". We cannot simply set flag_no_builtin in arm.c because
+ (a) flag_no_builtin is not declared in language-independent code,
+ and (b) that would prevent users from explicitly overriding the
+ default with -fbuiltin, which may sometimes be useful.
+
+ Make all symbols hidden by default. Symbian OS expects that all
+ exported symbols will be explicitly marked with
+ "__declspec(dllexport)".
+
+ Enumeration types use 4 bytes, even if the enumerals are small,
+ unless explicitly overridden.
+
+ The wchar_t type is a 2-byte type, unless explicitly
+ overridden. */
+#define CC1_SPEC \
+ "%{!fbuiltin:%{!fno-builtin:-fno-builtin}} " \
+ "%{!fvisibility=*:-fvisibility=hidden} " \
+ "%{!fshort-enums:%{!fno-short-enums:-fno-short-enums}} " \
+ "%{!fshort-wchar:%{!fno-short-wchar:-fshort-wchar}} "
+#define CC1PLUS_SPEC CC1_SPEC
+
+/* Symbian OS does not use crt*.o, unlike the generic unknown-elf
+ configuration. */
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC ""
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC ""
+
+/* Do not link with any libraries by default. On Symbian OS, the user
+ must supply all required libraries on the command line. */
+#undef LIB_SPEC
+#define LIB_SPEC ""
+
+/* Support the "dllimport" attribute. */
+#define TARGET_DLLIMPORT_DECL_ATTRIBUTES 1
+
+/* Symbian OS assumes ARM V5 or above. Since -march=armv5 is
+ equivalent to making the ARM 10TDMI core the default, we can set
+ SUBTARGET_CPU_DEFAULT and get an equivalent effect. */
+#undef SUBTARGET_CPU_DEFAULT
+#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm10tdmi
+
+/* The assembler should assume VFP FPU format, and armv5t. */
+#undef SUBTARGET_ASM_FLOAT_SPEC
+#define SUBTARGET_ASM_FLOAT_SPEC \
+ "%{!mfpu=*:-mfpu=vfp} %{!mcpu=*:%{!march=*:-march=armv5t}}"
+
+/* SymbianOS provides the BPABI routines in a separate library.
+ Therefore, we do not need to define any of them in libgcc. */
+#undef RENAME_LIBRARY
+#define RENAME_LIBRARY(GCC_NAME, AEABI_NAME) /* empty */
+
+/* Define the __symbian__ macro. */
+#undef TARGET_OS_CPP_BUILTINS
+#define TARGET_OS_CPP_BUILTINS() \
+ do \
+ { \
+ /* Include the default BPABI stuff. */ \
+ TARGET_BPABI_CPP_BUILTINS (); \
+ builtin_define ("__symbian__"); \
+ } \
+ while (false)
+
+/* On SymbianOS, these sections are not writable, so we use "a",
+ rather than "aw", for the section attributes. */
+#undef ARM_EABI_CTORS_SECTION_OP
+#define ARM_EABI_CTORS_SECTION_OP \
+ "\t.section\t.init_array,\"a\",%init_array"
+#undef ARM_EABI_DTORS_SECTION_OP
+#define ARM_EABI_DTORS_SECTION_OP \
+ "\t.section\t.fini_array,\"a\",%fini_array"
+
+/* SymbianOS cannot merge entities with vague linkage at runtime. */
+#define TARGET_ARM_DYNAMIC_VAGUE_LINKAGE_P false
diff --git a/contrib/gcc/config/arm/t-arm b/contrib/gcc/config/arm/t-arm
new file mode 100644
index 0000000..9fcd187
--- /dev/null
+++ b/contrib/gcc/config/arm/t-arm
@@ -0,0 +1,22 @@
+# Rules common to all arm targets
+
+MD_INCLUDES= $(srcdir)/config/arm/arm-tune.md \
+ $(srcdir)/config/arm/predicates.md \
+ $(srcdir)/config/arm/arm-generic.md \
+ $(srcdir)/config/arm/arm1020e.md \
+ $(srcdir)/config/arm/arm1026ejs.md \
+ $(srcdir)/config/arm/arm1136jfs.md \
+ $(srcdir)/config/arm/arm926ejs.md \
+ $(srcdir)/config/arm/cirrus.md \
+ $(srcdir)/config/arm/fpa.md \
+ $(srcdir)/config/arm/iwmmxt.md \
+ $(srcdir)/config/arm/vfp.md
+
+s-config s-conditions s-flags s-codes s-constants s-emit s-recog s-preds \
+ s-opinit s-extract s-peep s-attr s-attrtab s-output: $(MD_INCLUDES)
+
+$(srcdir)/config/arm/arm-tune.md: $(srcdir)/config/arm/gentune.sh \
+ $(srcdir)/config/arm/arm-cores.def
+ $(SHELL) $(srcdir)/config/arm/gentune.sh \
+ $(srcdir)/config/arm/arm-cores.def > \
+ $(srcdir)/config/arm/arm-tune.md
diff --git a/contrib/gcc/config/arm/t-arm-coff b/contrib/gcc/config/arm/t-arm-coff
index 8eef976..763add3 100644
--- a/contrib/gcc/config/arm/t-arm-coff
+++ b/contrib/gcc/config/arm/t-arm-coff
@@ -31,4 +31,4 @@ INSTALL_LIBGCC = install-multilib
# Currently there is a bug somewhere in GCC's alias analysis
# or scheduling code that is breaking _fpmul_parts in fp-bit.c.
# Disabling function inlining is a workaround for this problem.
-TARGET_LIBGCC2_CFLAGS = -Dinhibit_libc -fno-inline
+TARGET_LIBGCC2_CFLAGS = -fno-inline
diff --git a/contrib/gcc/config/arm/t-arm-elf b/contrib/gcc/config/arm/t-arm-elf
index 3f48f8b..bee4051 100644
--- a/contrib/gcc/config/arm/t-arm-elf
+++ b/contrib/gcc/config/arm/t-arm-elf
@@ -1,9 +1,10 @@
LIB1ASMSRC = arm/lib1funcs.asm
LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _bb_init_func \
_call_via_rX _interwork_call_via_rX \
+ _lshrdi3 _ashrdi3 _ashldi3 \
_negdf2 _addsubdf3 _muldivdf3 _cmpdf2 _unorddf2 _fixdfsi _fixunsdfsi \
_truncdfsf2 _negsf2 _addsubsf3 _muldivsf3 _cmpsf2 _unordsf2 \
- _fixsfsi _fixunssfsi
+ _fixsfsi _fixunssfsi _floatdidf _floatdisf _floatundidf _floatundisf
MULTILIB_OPTIONS = marm/mthumb
MULTILIB_DIRNAMES = arm thumb
@@ -13,7 +14,7 @@ MULTILIB_MATCHES =
# MULTILIB_OPTIONS += mcpu=ep9312
# MULTILIB_DIRNAMES += ep9312
# MULTILIB_EXCEPTIONS += *mthumb/*mcpu=ep9312*
-
+#
# MULTILIB_OPTIONS += mlittle-endian/mbig-endian
# MULTILIB_DIRNAMES += le be
# MULTILIB_MATCHES += mbig-endian=mbe mlittle-endian=mle
@@ -22,13 +23,8 @@ MULTILIB_MATCHES =
# MULTILIB_DIRNAMES += fpu soft
# MULTILIB_EXCEPTIONS += *mthumb/*mhard-float*
#
-# MULTILIB_OPTIONS += mapcs-32/mapcs-26
-# MULTILIB_DIRNAMES += 32bit 26bit
-# MULTILIB_EXCEPTIONS += *mthumb/*mapcs-26*
-#
# MULTILIB_OPTIONS += mno-thumb-interwork/mthumb-interwork
# MULTILIB_DIRNAMES += normal interwork
-# MULTILIB_EXCEPTIONS += *mapcs-26/*mthumb-interwork*
#
# MULTILIB_OPTIONS += fno-leading-underscore/fleading-underscore
# MULTILIB_DIRNAMES += elf under
@@ -71,7 +67,7 @@ INSTALL_LIBGCC = install-multilib
# Currently there is a bug somewhere in GCC's alias analysis
# or scheduling code that is breaking _fpmul_parts in fp-bit.c.
# Disabling function inlining is a workaround for this problem.
-TARGET_LIBGCC2_CFLAGS = -Dinhibit_libc -fno-inline
+TARGET_LIBGCC2_CFLAGS = -fno-inline
# Assemble startup files.
$(T)crti.o: $(srcdir)/config/arm/crti.asm $(GCC_PASSES)
diff --git a/contrib/gcc/config/arm/t-bpabi b/contrib/gcc/config/arm/t-bpabi
new file mode 100644
index 0000000..b5c6a0b
--- /dev/null
+++ b/contrib/gcc/config/arm/t-bpabi
@@ -0,0 +1,16 @@
+# Add the bpabi.S functions.
+LIB1ASMFUNCS += _aeabi_lcmp _aeabi_ulcmp _aeabi_ldivmod _aeabi_uldivmod
+
+# Add the BPABI C functions.
+LIB2FUNCS_EXTRA = $(srcdir)/config/arm/bpabi.c \
+ $(srcdir)/config/arm/unaligned-funcs.c
+
+UNWIND_H = $(srcdir)/config/arm/unwind-arm.h
+LIB2ADDEH = $(srcdir)/config/arm/unwind-arm.c \
+ $(srcdir)/config/arm/libunwind.S \
+ $(srcdir)/config/arm/pr-support.c $(srcdir)/unwind-c.c
+LIB2ADDEHDEP = $(UNWIND_H) $(srcdir)/config/$(LIB1ASMSRC)
+
+# Add the BPABI names.
+SHLIB_MAPFILES += $(srcdir)/config/arm/libgcc-bpabi.ver
+
diff --git a/contrib/gcc/config/arm/t-linux b/contrib/gcc/config/arm/t-linux
index 1c5f48a..b2697e6 100644
--- a/contrib/gcc/config/arm/t-linux
+++ b/contrib/gcc/config/arm/t-linux
@@ -9,11 +9,6 @@ LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_lnx
# MULTILIB_OPTIONS = mhard-float/msoft-float
# MULTILIB_DIRNAMES = hard-float soft-float
-# If you want to build both APCS variants as multilib options this is how
-# to do it.
-# MULTILIB_OPTIONS += mapcs-32/mapcs-26
-# MULTILIB_DIRNAMES += apcs-32 apcs-26
-
# EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o
# LIBGCC = stmp-multilib
diff --git a/contrib/gcc/config/arm/t-linux-eabi b/contrib/gcc/config/arm/t-linux-eabi
new file mode 100644
index 0000000..5e8d94d
--- /dev/null
+++ b/contrib/gcc/config/arm/t-linux-eabi
@@ -0,0 +1,14 @@
+# These functions are included in shared libraries.
+TARGET_LIBGCC2_CFLAGS = -fPIC
+
+# We do not build a Thumb multilib for Linux because the definition of
+# CLEAR_INSN_CACHE in linux-gas.h does not work in Thumb mode.
+MULTILIB_OPTIONS =
+MULTILIB_DIRNAMES =
+
+# Use a version of div0 which raises SIGFPE.
+LIB1ASMFUNCS := $(filter-out _dvmd_tls,$(LIB1ASMFUNCS)) _dvmd_lnx
+
+# Multilib the standard Linux files. Don't include crti.o or crtn.o,
+# which are provided by glibc.
+EXTRA_MULTILIB_PARTS=crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o
diff --git a/contrib/gcc/config/arm/t-netbsd b/contrib/gcc/config/arm/t-netbsd
index 533fab9..7d0724c 100644
--- a/contrib/gcc/config/arm/t-netbsd
+++ b/contrib/gcc/config/arm/t-netbsd
@@ -2,6 +2,7 @@
# difference. It is then pointless adding debugging.
TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer -fpic
LIBGCC2_DEBUG_CFLAGS = -g0
+LIB2FUNCS_EXTRA = $(srcdir)/config/floatunsidf.c $(srcdir)/config/floatunsisf.c
# Build a shared libgcc library.
SHLIB_EXT = .so
@@ -20,6 +21,8 @@ SHLIB_LINK = $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) -shared -nodefaultlibs \
$(LN_S) $(SHLIB_NAME) $(SHLIB_SONAME)
# $(slibdir) double quoted to protect it from expansion while building
# libgcc.mk. We want this delayed until actual install time.
-SHLIB_INSTALL = $(INSTALL_DATA) $(SHLIB_NAME) $$(DESTDIR)$$(slibdir)/$(SHLIB_SONAME); \
+SHLIB_INSTALL = \
+ $$(mkinstalldirs) $$(DESTDIR)$$(slibdir); \
+ $(INSTALL_DATA) $(SHLIB_NAME) $$(DESTDIR)$$(slibdir)/$(SHLIB_SONAME); \
rm -f $$(DESTDIR)$$(slibdir)/$(SHLIB_NAME); \
$(LN_S) $(SHLIB_SONAME) $$(DESTDIR)$$(slibdir)/$(SHLIB_NAME)
diff --git a/contrib/gcc/config/arm/t-pe b/contrib/gcc/config/arm/t-pe
index 4c20b31..741e2b8 100644
--- a/contrib/gcc/config/arm/t-pe
+++ b/contrib/gcc/config/arm/t-pe
@@ -24,9 +24,9 @@ pe.o: $(srcdir)/config/arm/pe.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(RTL_H) output.h flags.h $(TREE_H) expr.h toplev.h $(TM_P_H)
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/arm/pe.c
-MULTILIB_OPTIONS = mhard-float mthumb mapcs-32
-MULTILIB_DIRNAMES = fpu thumb apcs32
+MULTILIB_OPTIONS = mhard-float mthumb
+MULTILIB_DIRNAMES = fpu thumb
LIBGCC = stmp-multilib
INSTALL_LIBGCC = install-multilib
-TARGET_LIBGCC2_CFLAGS = -Dinhibit_libc
+TARGET_LIBGCC2_CFLAGS = \ No newline at end of file
diff --git a/contrib/gcc/config/arm/t-semi b/contrib/gcc/config/arm/t-semi
index abd642c..f5d8f1a 100644
--- a/contrib/gcc/config/arm/t-semi
+++ b/contrib/gcc/config/arm/t-semi
@@ -29,9 +29,9 @@ dp-bit.c: $(srcdir)/config/fp-bit.c
cat $(srcdir)/config/fp-bit.c >> dp-bit.c
echo '#endif' >> dp-bit.c
-MULTILIB_OPTIONS = msoft-float mapcs-26 mbig-endian mwords-little-endian
-MULTILIB_DIRNAMES = soft apcs26 big wlittle
-MULTILIB_EXCEPTIONS = *mapcs-26/*mbig-endian* mwords-little-endian *mapcs-26/mwords-little-endian msoft-float/mwords-little-endian
+MULTILIB_OPTIONS = msoft-float mbig-endian mwords-little-endian
+MULTILIB_DIRNAMES = soft big wlittle
+MULTILIB_EXCEPTIONS = mwords-little-endian msoft-float/mwords-little-endian
LIBGCC = stmp-multilib
INSTALL_LIBGCC = install-multilib
diff --git a/contrib/gcc/config/arm/t-strongarm-elf b/contrib/gcc/config/arm/t-strongarm-elf
index 46e2ac4..c819354 100644
--- a/contrib/gcc/config/arm/t-strongarm-elf
+++ b/contrib/gcc/config/arm/t-strongarm-elf
@@ -32,7 +32,7 @@ INSTALL_LIBGCC = install-multilib
# Currently there is a bug somewhere in GCC's alias analysis
# or scheduling code that is breaking _fpmul_parts in fp-bit.c.
# Disabling function inlining is a workaround for this problem.
-TARGET_LIBGCC2_CFLAGS = -Dinhibit_libc -fno-inline
+TARGET_LIBGCC2_CFLAGS = -fno-inline
# Assemble startup files.
$(T)crti.o: $(srcdir)/config/arm/crti.asm $(GCC_PASSES)
diff --git a/contrib/gcc/config/arm/t-strongarm-pe b/contrib/gcc/config/arm/t-strongarm-pe
index e401666..2e4732f 100644
--- a/contrib/gcc/config/arm/t-strongarm-pe
+++ b/contrib/gcc/config/arm/t-strongarm-pe
@@ -35,4 +35,4 @@ INSTALL_LIBGCC = install-multilib
# Currently there is a bug somewhere in GCC's alias analysis
# or scheduling code that is breaking _fpmul_parts in fp-bit.c.
# Disabling function inlining is a workaround for this problem.
-TARGET_LIBGCC2_CFLAGS = -Dinhibit_libc -fno-inline
+TARGET_LIBGCC2_CFLAGS = -fno-inline
diff --git a/contrib/gcc/config/arm/t-symbian b/contrib/gcc/config/arm/t-symbian
new file mode 100644
index 0000000..db89138
--- /dev/null
+++ b/contrib/gcc/config/arm/t-symbian
@@ -0,0 +1,32 @@
+LIB1ASMFUNCS = _bb_init_func _call_via_rX _interwork_call_via_rX
+
+# These functions have __aeabi equivalents and will never be called by GCC.
+# By putting them in LIB1ASMFUNCS, we avoid the standard libgcc2.c code being
+# used -- and we make sure that definitions are not available in lib1funcs.asm,
+# either, so they end up undefined.
+LIB1ASMFUNCS += \
+ _ashldi3 _ashrdi3 _divdi3 _floatdidf _udivmoddi4 _umoddi3 \
+ _udivdi3 _lshrdi3 _moddi3 _muldi3 _negdi2 _cmpdi2 \
+ _fixdfdi _fixsfdi _fixunsdfdi _fixunssfdi _floatdisf \
+ _negdf2 _addsubdf3 _muldivdf3 _cmpdf2 _unorddf2 _fixdfsi _fixunsdfsi \
+ _truncdfsf2 _negsf2 _addsubsf3 _muldivsf3 _cmpsf2 _unordsf2 \
+ _fixsfsi _fixunssfsi
+
+# Include the gcc personality routine
+UNWIND_H = $(srcdir)/config/arm/unwind-arm.h
+LIB2ADDEH = $(srcdir)/unwind-c.c $(srcdir)/config/arm/pr-support.c
+LIB2ADDEHDEP = $(UNWIND_H)
+
+# Create a multilib for processors with VFP floating-point, and a
+# multilib for those without -- using the soft-float ABI in both
+# cases. Symbian OS object should be compiled with interworking
+# enabled, so there are no separate thumb-mode libraries.
+MULTILIB_OPTIONS = mfloat-abi=softfp
+MULTILIB_DIRNAMES = softfp
+
+# There is no C library to link against on Symbian OS -- at least when
+# building GCC.
+SHLIB_LC =
+
+# Symbian OS provides its own startup code.
+EXTRA_MULTILIB_PARTS=
diff --git a/contrib/gcc/config/arm/t-wince-pe b/contrib/gcc/config/arm/t-wince-pe
index 9537a7f..fca9853 100644
--- a/contrib/gcc/config/arm/t-wince-pe
+++ b/contrib/gcc/config/arm/t-wince-pe
@@ -24,9 +24,9 @@ pe.o: $(srcdir)/config/arm/pe.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(RTL_H) output.h flags.h $(TREE_H) expr.h toplev.h $(TM_P_H)
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/arm/pe.c
-MULTILIB_OPTIONS = mhard-float mapcs-26
-MULTILIB_DIRNAMES = fpu apcs26
-# Note - Thumb multilib omitted because Thumb apcs32 support for
+MULTILIB_OPTIONS = mhard-float
+MULTILIB_DIRNAMES = fpu
+# Note - Thumb multilib omitted because Thumb support for
# arm-wince-pe target does not appear to be working in binutils
# yet...
# MULTILIB_OPTIONS += thumb
@@ -34,4 +34,4 @@ MULTILIB_DIRNAMES = fpu apcs26
LIBGCC = stmp-multilib
INSTALL_LIBGCC = install-multilib
-TARGET_LIBGCC2_CFLAGS = -Dinhibit_libc
+TARGET_LIBGCC2_CFLAGS =
diff --git a/contrib/gcc/config/arm/t-xscale-coff b/contrib/gcc/config/arm/t-xscale-coff
index 89f371f..e2331a0 100644
--- a/contrib/gcc/config/arm/t-xscale-coff
+++ b/contrib/gcc/config/arm/t-xscale-coff
@@ -20,19 +20,18 @@ dp-bit.c: $(srcdir)/config/fp-bit.c
echo '#endif' >> dp-bit.c
cat $(srcdir)/config/fp-bit.c >> dp-bit.c
-MULTILIB_OPTIONS = mlittle-endian/mbig-endian
-MULTILIB_DIRNAMES = le be
+MULTILIB_OPTIONS = mbig-endian
+MULTILIB_DIRNAMES = be
MULTILIB_EXCEPTIONS =
MULTILIB_MATCHES = mbig-endian=mbe mlittle-endian=mle
-# Note XScale does not support 26 bit APCS.
# Note XScale does not support hard FP
-MULTILIB_OPTIONS += mno-thumb-interwork/mthumb-interwork
-MULTILIB_DIRNAMES += normal interwork
+MULTILIB_OPTIONS += mthumb-interwork
+MULTILIB_DIRNAMES += interwork
-MULTILIB_OPTIONS += marm/mthumb
-MULTILIB_DIRNAMES += arm thumb
+MULTILIB_OPTIONS += mthumb
+MULTILIB_DIRNAMES += thumb
MULTILIB_EXCEPTIONS += *mhard-float/*mthumb*
MULTILIB_REDUNDANT_DIRS = interwork/thumb=thumb
@@ -43,4 +42,4 @@ INSTALL_LIBGCC = install-multilib
# Currently there is a bug somewhere in GCC's alias analysis
# or scheduling code that is breaking _fpmul_parts in fp-bit.c.
# Disabling function inlining is a workaround for this problem.
-TARGET_LIBGCC2_CFLAGS = -Dinhibit_libc -fno-inline
+TARGET_LIBGCC2_CFLAGS = -fno-inline
diff --git a/contrib/gcc/config/arm/t-xscale-elf b/contrib/gcc/config/arm/t-xscale-elf
index b72c21c..d7a8124 100644
--- a/contrib/gcc/config/arm/t-xscale-elf
+++ b/contrib/gcc/config/arm/t-xscale-elf
@@ -20,26 +20,31 @@ dp-bit.c: $(srcdir)/config/fp-bit.c
echo '#endif' >> dp-bit.c
cat $(srcdir)/config/fp-bit.c >> dp-bit.c
-MULTILIB_OPTIONS = mlittle-endian/mbig-endian
-MULTILIB_DIRNAMES = le be
+MULTILIB_OPTIONS = mbig-endian
+MULTILIB_DIRNAMES = be
MULTILIB_EXCEPTIONS =
MULTILIB_MATCHES = mbig-endian=mbe mlittle-endian=mle
-# Note XScale does not support 26 bit APCS.
# Note XScale does not support hard FP
-MULTILIB_OPTIONS += mno-thumb-interwork/mthumb-interwork
-MULTILIB_DIRNAMES += normal interwork
+MULTILIB_OPTIONS += mthumb-interwork
+MULTILIB_DIRNAMES += interwork
-MULTILIB_OPTIONS += marm/mthumb
-MULTILIB_DIRNAMES += arm thumb
+MULTILIB_OPTIONS += mthumb
+MULTILIB_DIRNAMES += thumb
MULTILIB_EXCEPTIONS += *mhard-float/*mthumb*
MULTILIB_REDUNDANT_DIRS = interwork/thumb=thumb
-MULTILIB_OPTIONS += mcpu=iwmmxt
-MULTILIB_DIRNAMES += iwmmxt
-MULTILIB_REDUNDANT_DIRS += interwork/thumb/iwmmxt=thumb
+# The iWMMXt multilibs are suppressed for now because gcc only
+# supports generating them with the IWMMXT or AAPCS ABIs, neither of
+# which is the default. Until GCC can generate code for an iWMMXt
+# which will work with the default ABI it is not possible to safely
+# generate these multilibs.
+#
+# MULTILIB_OPTIONS += mcpu=iwmmxt
+# MULTILIB_DIRNAMES += iwmmxt
+# MULTILIB_REDUNDANT_DIRS += interwork/thumb/iwmmxt=thumb
EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.o
@@ -49,7 +54,7 @@ INSTALL_LIBGCC = install-multilib
# Currently there is a bug somewhere in GCC's alias analysis
# or scheduling code that is breaking _fpmul_parts in fp-bit.c.
# Disabling function inlining is a workaround for this problem.
-TARGET_LIBGCC2_CFLAGS = -Dinhibit_libc -fno-inline
+TARGET_LIBGCC2_CFLAGS = -fno-inline
# Assemble startup files.
$(T)crti.o: $(srcdir)/config/arm/crti.asm $(GCC_PASSES)
diff --git a/contrib/gcc/config/arm/uclinux-elf.h b/contrib/gcc/config/arm/uclinux-elf.h
index e3cd48d..9f112cd 100644
--- a/contrib/gcc/config/arm/uclinux-elf.h
+++ b/contrib/gcc/config/arm/uclinux-elf.h
@@ -1,5 +1,5 @@
/* Definitions for ARM running ucLinux using ELF
- Copyright (C) 1999, 2001 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2001, 2004, 2005 Free Software Foundation, Inc.
Contributed by Philip Blundell <pb@nexus.co.uk>
This file is part of GCC.
@@ -16,8 +16,8 @@
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* We don't want a PLT. */
#undef NEED_PLT_RELOC
@@ -27,4 +27,48 @@
#define TARGET_VERSION fputs (" (ARM/ELF ucLinux)", stderr);
#undef TARGET_DEFAULT
-#define TARGET_DEFAULT (ARM_FLAG_APCS_32 | ARM_FLAG_MMU_TRAPS | ARM_FLAG_SINGLE_PIC_BASE)
+#define TARGET_DEFAULT (MASK_SINGLE_PIC_BASE)
+
+/* NOTE: The remaining definitions in this file are needed because uclinux
+ does not use config/linux.h. */
+
+/* Do not assume anything about header files. */
+#define NO_IMPLICIT_EXTERN_C
+
+/* The GNU C++ standard library requires that these macros be defined. */
+#undef CPLUSPLUS_CPP_SPEC
+#define CPLUSPLUS_CPP_SPEC "-D_GNU_SOURCE %(cpp)"
+
+/* Provide a STARTFILE_SPEC appropriate for GNU/Linux. Here we add
+ the GNU/Linux magical crtbegin.o file (see crtstuff.c) which
+ provides part of the support for getting C++ file-scope static
+ object constructed before entering `main'. */
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC \
+ "%{!shared: \
+ %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} \
+ %{!p:%{profile:gcrt1.o%s} \
+ %{!profile:crt1.o%s}}}} \
+ crti.o%s %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}"
+
+/* Provide a ENDFILE_SPEC appropriate for GNU/Linux. Here we tack on
+ the GNU/Linux magical crtend.o file (see crtstuff.c) which
+ provides part of the support for getting C++ file-scope static
+ object constructed before entering `main', followed by a normal
+ GNU/Linux "finalizer" file, `crtn.o'. */
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC \
+ "%{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.o%s"
+
+#undef CC1_SPEC
+#define CC1_SPEC "%{profile:-p}"
+
+#define LINK_GCC_C_SEQUENCE_SPEC \
+ "%{static:--start-group} %G %L %{static:--end-group}%{!static:%G}"
+
+/* Use --as-needed -lgcc_s for eh support. */
+#ifdef HAVE_LD_AS_NEEDED
+#define USE_LD_AS_NEEDED 1
+#endif
diff --git a/contrib/gcc/config/arm/unaligned-funcs.c b/contrib/gcc/config/arm/unaligned-funcs.c
new file mode 100644
index 0000000..66cfd3b
--- /dev/null
+++ b/contrib/gcc/config/arm/unaligned-funcs.c
@@ -0,0 +1,62 @@
+/* EABI unaligned read/write functions.
+
+ Copyright (C) 2005 Free Software Foundation, Inc.
+ Contributed by CodeSourcery, LLC.
+
+ 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, 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.)
+
+ 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 program; see the file COPYING. If not, write to
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+int __aeabi_uread4 (void *);
+int __aeabi_uwrite4 (int, void *);
+long long __aeabi_uread8 (void *);
+long long __aeabi_uwrite8 (long long, void *);
+
+struct __attribute__((packed)) u4 { int data; };
+struct __attribute__((packed)) u8 { long long data; };
+
+int
+__aeabi_uread4 (void *ptr)
+{
+ return ((struct u4 *) ptr)->data;
+}
+
+int
+__aeabi_uwrite4 (int data, void *ptr)
+{
+ ((struct u4 *) ptr)->data = data;
+ return data;
+}
+
+long long
+__aeabi_uread8 (void *ptr)
+{
+ return ((struct u8 *) ptr)->data;
+}
+
+long long
+__aeabi_uwrite8 (long long data, void *ptr)
+{
+ ((struct u8 *) ptr)->data = data;
+ return data;
+}
diff --git a/contrib/gcc/config/arm/unknown-elf.h b/contrib/gcc/config/arm/unknown-elf.h
index 1af7994..c9ad990 100644
--- a/contrib/gcc/config/arm/unknown-elf.h
+++ b/contrib/gcc/config/arm/unknown-elf.h
@@ -1,5 +1,5 @@
/* Definitions for non-Linux based ARM systems using ELF
- Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004
Free Software Foundation, Inc.
Contributed by Catherine Moore <clm@cygnus.com>
@@ -17,8 +17,8 @@
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* elfos.h should have already been included. Now just override
any conflicting definitions and add any extras. */
@@ -28,9 +28,9 @@
#define TARGET_VERSION fputs (" (ARM/ELF)", stderr);
#endif
-/* Default to using APCS-32 and software floating point. */
+/* Default to using software floating point. */
#ifndef TARGET_DEFAULT
-#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME | ARM_FLAG_MMU_TRAPS)
+#define TARGET_DEFAULT (0)
#endif
/* Now we define the strings used to build the spec file. */
@@ -58,9 +58,9 @@
do \
{ \
if (IN_NAMED_SECTION (DECL)) \
- named_section (DECL, NULL, 0); \
+ switch_to_section (get_named_section (DECL, NULL, 0)); \
else \
- bss_section (); \
+ switch_to_section (bss_section); \
\
ASM_OUTPUT_ALIGN (FILE, floor_log2 (ALIGN / BITS_PER_UNIT)); \
\
@@ -75,9 +75,9 @@
do \
{ \
if ((DECL) != NULL && IN_NAMED_SECTION (DECL)) \
- named_section (DECL, NULL, 0); \
+ switch_to_section (get_named_section (DECL, NULL, 0)); \
else \
- bss_section (); \
+ switch_to_section (bss_section); \
\
ASM_OUTPUT_ALIGN (FILE, floor_log2 (ALIGN / BITS_PER_UNIT)); \
ASM_OUTPUT_LABEL (FILE, NAME); \
@@ -85,11 +85,13 @@
} \
while (0)
-#ifndef CPP_APCS_PC_DEFAULT_SPEC
-#define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__"
-#endif
-
#ifndef SUBTARGET_CPU_DEFAULT
#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm7tdmi
#endif
+/* The libgcc udivmod functions may throw exceptions. If newlib is
+ configured to support long longs in I/O, then printf will depend on
+ udivmoddi4, which will depend on the exception unwind routines,
+ which will depend on abort, which is defined in libc. */
+#undef LINK_GCC_C_SEQUENCE_SPEC
+#define LINK_GCC_C_SEQUENCE_SPEC "--start-group %G %L --end-group"
diff --git a/contrib/gcc/config/arm/unwind-arm.c b/contrib/gcc/config/arm/unwind-arm.c
new file mode 100644
index 0000000..9d2513b
--- /dev/null
+++ b/contrib/gcc/config/arm/unwind-arm.c
@@ -0,0 +1,1016 @@
+/* ARM EABI compliant unwinding routines.
+ Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Contributed by Paul Brook
+
+ 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, 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.)
+
+ 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 program; see the file COPYING. If not, write to
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+#include "unwind.h"
+
+/* We add a prototype for abort here to avoid creating a dependency on
+ target headers. */
+extern void abort (void);
+
+/* Definitions for C++ runtime support routines. We make these weak
+ declarations to avoid pulling in libsupc++ unnecessarily. */
+typedef unsigned char bool;
+
+typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
+
+void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
+bool __attribute__((weak)) __cxa_begin_cleanup(_Unwind_Control_Block *ucbp);
+bool __attribute__((weak)) __cxa_type_match(_Unwind_Control_Block *ucbp,
+ const type_info *rttip,
+ void **matched_object);
+
+_Unwind_Ptr __attribute__((weak))
+__gnu_Unwind_Find_exidx (_Unwind_Ptr, int *);
+
+/* Misc constants. */
+#define R_IP 12
+#define R_SP 13
+#define R_LR 14
+#define R_PC 15
+
+#define EXIDX_CANTUNWIND 1
+#define uint32_highbit (((_uw) 1) << 31)
+
+#define UCB_FORCED_STOP_FN(ucbp) ((ucbp)->unwinder_cache.reserved1)
+#define UCB_PR_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved2)
+#define UCB_SAVED_CALLSITE_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved3)
+#define UCB_FORCED_STOP_ARG(ucbp) ((ucbp)->unwinder_cache.reserved4)
+
+struct core_regs
+{
+ _uw r[16];
+};
+
+/* We use normal integer types here to avoid the compiler generating
+ coprocessor instructions. */
+struct vfp_regs
+{
+ _uw64 d[16];
+ _uw pad;
+};
+
+struct fpa_reg
+{
+ _uw w[3];
+};
+
+struct fpa_regs
+{
+ struct fpa_reg f[8];
+};
+
+/* Unwind descriptors. */
+
+typedef struct
+{
+ _uw16 length;
+ _uw16 offset;
+} EHT16;
+
+typedef struct
+{
+ _uw length;
+ _uw offset;
+} EHT32;
+
+/* The ABI specifies that the unwind routines may only use core registers,
+ except when actually manipulating coprocessor state. This allows
+ us to write one implementation that works on all platforms by
+ demand-saving coprocessor registers.
+
+ During unwinding we hold the coprocessor state in the actual hardware
+ registers and allocate demand-save areas for use during phase1
+ unwinding. */
+
+typedef struct
+{
+ /* The first fields must be the same as a phase2_vrs. */
+ _uw demand_save_flags;
+ struct core_regs core;
+ _uw prev_sp; /* Only valid during forced unwinding. */
+ struct vfp_regs vfp;
+ struct fpa_regs fpa;
+} phase1_vrs;
+
+#define DEMAND_SAVE_VFP 1
+
+/* This must match the structure created by the assembly wrappers. */
+typedef struct
+{
+ _uw demand_save_flags;
+ struct core_regs core;
+} phase2_vrs;
+
+
+/* An exception index table entry. */
+
+typedef struct __EIT_entry
+{
+ _uw fnoffset;
+ _uw content;
+} __EIT_entry;
+
+/* Assembly helper functions. */
+
+/* Restore core register state. Never returns. */
+void __attribute__((noreturn)) restore_core_regs (struct core_regs *);
+
+
+/* Coprocessor register state manipulation functions. */
+
+void __gnu_Unwind_Save_VFP (struct vfp_regs * p);
+void __gnu_Unwind_Restore_VFP (struct vfp_regs * p);
+
+/* Restore coprocessor state after phase1 unwinding. */
+static void
+restore_non_core_regs (phase1_vrs * vrs)
+{
+ if ((vrs->demand_save_flags & DEMAND_SAVE_VFP) == 0)
+ __gnu_Unwind_Restore_VFP (&vrs->vfp);
+}
+
+/* A better way to do this would probably be to compare the absolute address
+ with a segment relative relocation of the same symbol. */
+
+extern int __text_start;
+extern int __data_start;
+
+/* The exception index table location. */
+extern __EIT_entry __exidx_start;
+extern __EIT_entry __exidx_end;
+
+/* ABI defined personality routines. */
+extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr0 (_Unwind_State,
+ _Unwind_Control_Block *, _Unwind_Context *);// __attribute__((weak));
+extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr1 (_Unwind_State,
+ _Unwind_Control_Block *, _Unwind_Context *) __attribute__((weak));
+extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr2 (_Unwind_State,
+ _Unwind_Control_Block *, _Unwind_Context *) __attribute__((weak));
+
+/* ABI defined routine to store a virtual register to memory. */
+
+_Unwind_VRS_Result _Unwind_VRS_Get (_Unwind_Context *context,
+ _Unwind_VRS_RegClass regclass,
+ _uw regno,
+ _Unwind_VRS_DataRepresentation representation,
+ void *valuep)
+{
+ phase1_vrs *vrs = (phase1_vrs *) context;
+
+ switch (regclass)
+ {
+ case _UVRSC_CORE:
+ if (representation != _UVRSD_UINT32
+ || regno > 15)
+ return _UVRSR_FAILED;
+ *(_uw *) valuep = vrs->core.r[regno];
+ return _UVRSR_OK;
+
+ case _UVRSC_VFP:
+ case _UVRSC_FPA:
+ case _UVRSC_WMMXD:
+ case _UVRSC_WMMXC:
+ return _UVRSR_NOT_IMPLEMENTED;
+
+ default:
+ return _UVRSR_FAILED;
+ }
+}
+
+
+/* ABI defined function to load a virtual register from memory. */
+
+_Unwind_VRS_Result _Unwind_VRS_Set (_Unwind_Context *context,
+ _Unwind_VRS_RegClass regclass,
+ _uw regno,
+ _Unwind_VRS_DataRepresentation representation,
+ void *valuep)
+{
+ phase1_vrs *vrs = (phase1_vrs *) context;
+
+ switch (regclass)
+ {
+ case _UVRSC_CORE:
+ if (representation != _UVRSD_UINT32
+ || regno > 15)
+ return _UVRSR_FAILED;
+
+ vrs->core.r[regno] = *(_uw *) valuep;
+ return _UVRSR_OK;
+
+ case _UVRSC_VFP:
+ case _UVRSC_FPA:
+ case _UVRSC_WMMXD:
+ case _UVRSC_WMMXC:
+ return _UVRSR_NOT_IMPLEMENTED;
+
+ default:
+ return _UVRSR_FAILED;
+ }
+}
+
+
+/* ABI defined function to pop registers off the stack. */
+
+_Unwind_VRS_Result _Unwind_VRS_Pop (_Unwind_Context *context,
+ _Unwind_VRS_RegClass regclass,
+ _uw discriminator,
+ _Unwind_VRS_DataRepresentation representation)
+{
+ phase1_vrs *vrs = (phase1_vrs *) context;
+
+ switch (regclass)
+ {
+ case _UVRSC_CORE:
+ {
+ _uw *ptr;
+ _uw mask;
+ int i;
+
+ if (representation != _UVRSD_UINT32)
+ return _UVRSR_FAILED;
+
+ mask = discriminator & 0xffff;
+ ptr = (_uw *) vrs->core.r[R_SP];
+ /* Pop the requested registers. */
+ for (i = 0; i < 16; i++)
+ {
+ if (mask & (1 << i))
+ vrs->core.r[i] = *(ptr++);
+ }
+ /* Writeback the stack pointer value if it wasn't restored. */
+ if ((mask & (1 << R_SP)) == 0)
+ vrs->core.r[R_SP] = (_uw) ptr;
+ }
+ return _UVRSR_OK;
+
+ case _UVRSC_VFP:
+ {
+ _uw start = discriminator >> 16;
+ _uw count = discriminator & 0xffff;
+ struct vfp_regs tmp;
+ _uw *sp;
+ _uw *dest;
+
+ if ((representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE)
+ || start + count > 16)
+ return _UVRSR_FAILED;
+
+ if (vrs->demand_save_flags & DEMAND_SAVE_VFP)
+ {
+ /* Demand-save resisters for stage1. */
+ vrs->demand_save_flags &= ~DEMAND_SAVE_VFP;
+ __gnu_Unwind_Save_VFP (&vrs->vfp);
+ }
+
+ /* Restore the registers from the stack. Do this by saving the
+ current VFP registers to a memory area, moving the in-memory
+ values into that area, and restoring from the whole area.
+ For _UVRSD_VFPX we assume FSTMX standard format 1. */
+ __gnu_Unwind_Save_VFP (&tmp);
+
+ /* The stack address is only guaranteed to be word aligned, so
+ we can't use doubleword copies. */
+ sp = (_uw *) vrs->core.r[R_SP];
+ dest = (_uw *) &tmp.d[start];
+ count *= 2;
+ while (count--)
+ *(dest++) = *(sp++);
+
+ /* Skip the pad word */
+ if (representation == _UVRSD_VFPX)
+ sp++;
+
+ /* Set the new stack pointer. */
+ vrs->core.r[R_SP] = (_uw) sp;
+
+ /* Reload the registers. */
+ __gnu_Unwind_Restore_VFP (&tmp);
+ }
+ return _UVRSR_OK;
+
+ case _UVRSC_FPA:
+ case _UVRSC_WMMXD:
+ case _UVRSC_WMMXC:
+ return _UVRSR_NOT_IMPLEMENTED;
+
+ default:
+ return _UVRSR_FAILED;
+ }
+}
+
+
+/* Core unwinding functions. */
+
+/* Calculate the address encoded by a 31-bit self-relative offset at address
+ P. */
+static inline _uw
+selfrel_offset31 (const _uw *p)
+{
+ _uw offset;
+
+ offset = *p;
+ /* Sign extend to 32 bits. */
+ if (offset & (1 << 30))
+ offset |= 1u << 31;
+ else
+ offset &= ~(1u << 31);
+
+ return offset + (_uw) p;
+}
+
+
+/* Perform a binary search for RETURN_ADDRESS in TABLE. The table contains
+ NREC entries. */
+
+static const __EIT_entry *
+search_EIT_table (const __EIT_entry * table, int nrec, _uw return_address)
+{
+ _uw next_fn;
+ _uw this_fn;
+ int n, left, right;
+
+ if (nrec == 0)
+ return (__EIT_entry *) 0;
+
+ left = 0;
+ right = nrec - 1;
+
+ while (1)
+ {
+ n = (left + right) / 2;
+ this_fn = selfrel_offset31 (&table[n].fnoffset);
+ if (n != nrec - 1)
+ next_fn = selfrel_offset31 (&table[n + 1].fnoffset) - 1;
+ else
+ next_fn = (_uw)0 - 1;
+
+ if (return_address < this_fn)
+ {
+ if (n == left)
+ return (__EIT_entry *) 0;
+ right = n - 1;
+ }
+ else if (return_address <= next_fn)
+ return &table[n];
+ else
+ left = n + 1;
+ }
+}
+
+/* Find the exception index table eintry for the given address.
+ Fill in the relevant fields of the UCB.
+ Returns _URC_FAILURE if an error occurred, _URC_OK on success. */
+
+static _Unwind_Reason_Code
+get_eit_entry (_Unwind_Control_Block *ucbp, _uw return_address)
+{
+ const __EIT_entry * eitp;
+ int nrec;
+
+ /* The return address is the address of the instruction following the
+ call instruction (plus one in thumb mode). If this was the last
+ instruction in the function the address will lie in the following
+ function. Subtract 2 from the address so that it points within the call
+ instruction itself. */
+ return_address -= 2;
+
+ if (__gnu_Unwind_Find_exidx)
+ {
+ eitp = (const __EIT_entry *) __gnu_Unwind_Find_exidx (return_address,
+ &nrec);
+ if (!eitp)
+ {
+ UCB_PR_ADDR (ucbp) = 0;
+ return _URC_FAILURE;
+ }
+ }
+ else
+ {
+ eitp = &__exidx_start;
+ nrec = &__exidx_end - &__exidx_start;
+ }
+
+ eitp = search_EIT_table (eitp, nrec, return_address);
+
+ if (!eitp)
+ {
+ UCB_PR_ADDR (ucbp) = 0;
+ return _URC_FAILURE;
+ }
+ ucbp->pr_cache.fnstart = selfrel_offset31 (&eitp->fnoffset);
+
+ /* Can this frame be unwound at all? */
+ if (eitp->content == EXIDX_CANTUNWIND)
+ {
+ UCB_PR_ADDR (ucbp) = 0;
+ return _URC_END_OF_STACK;
+ }
+
+ /* Obtain the address of the "real" __EHT_Header word. */
+
+ if (eitp->content & uint32_highbit)
+ {
+ /* It is immediate data. */
+ ucbp->pr_cache.ehtp = (_Unwind_EHT_Header *)&eitp->content;
+ ucbp->pr_cache.additional = 1;
+ }
+ else
+ {
+ /* The low 31 bits of the content field are a self-relative
+ offset to an _Unwind_EHT_Entry structure. */
+ ucbp->pr_cache.ehtp =
+ (_Unwind_EHT_Header *) selfrel_offset31 (&eitp->content);
+ ucbp->pr_cache.additional = 0;
+ }
+
+ /* Discover the personality routine address. */
+ if (*ucbp->pr_cache.ehtp & (1u << 31))
+ {
+ /* One of the predefined standard routines. */
+ _uw idx = (*(_uw *) ucbp->pr_cache.ehtp >> 24) & 0xf;
+ if (idx == 0)
+ UCB_PR_ADDR (ucbp) = (_uw) &__aeabi_unwind_cpp_pr0;
+ else if (idx == 1)
+ UCB_PR_ADDR (ucbp) = (_uw) &__aeabi_unwind_cpp_pr1;
+ else if (idx == 2)
+ UCB_PR_ADDR (ucbp) = (_uw) &__aeabi_unwind_cpp_pr2;
+ else
+ { /* Failed */
+ UCB_PR_ADDR (ucbp) = 0;
+ return _URC_FAILURE;
+ }
+ }
+ else
+ {
+ /* Execute region offset to PR */
+ UCB_PR_ADDR (ucbp) = selfrel_offset31 (ucbp->pr_cache.ehtp);
+ }
+ return _URC_OK;
+}
+
+
+/* Perform phase2 unwinding. VRS is the initial virtual register state. */
+
+static void __attribute__((noreturn))
+unwind_phase2 (_Unwind_Control_Block * ucbp, phase2_vrs * vrs)
+{
+ _Unwind_Reason_Code pr_result;
+
+ do
+ {
+ /* Find the entry for this routine. */
+ if (get_eit_entry (ucbp, vrs->core.r[R_PC]) != _URC_OK)
+ abort ();
+
+ UCB_SAVED_CALLSITE_ADDR (ucbp) = vrs->core.r[R_PC];
+
+ /* Call the pr to decide what to do. */
+ pr_result = ((personality_routine) UCB_PR_ADDR (ucbp))
+ (_US_UNWIND_FRAME_STARTING, ucbp, (_Unwind_Context *) vrs);
+ }
+ while (pr_result == _URC_CONTINUE_UNWIND);
+
+ if (pr_result != _URC_INSTALL_CONTEXT)
+ abort();
+
+ restore_core_regs (&vrs->core);
+}
+
+/* Perform phase2 forced unwinding. */
+
+static _Unwind_Reason_Code
+unwind_phase2_forced (_Unwind_Control_Block *ucbp, phase2_vrs *entry_vrs,
+ int resuming)
+{
+ _Unwind_Stop_Fn stop_fn = (_Unwind_Stop_Fn) UCB_FORCED_STOP_FN (ucbp);
+ void *stop_arg = (void *)UCB_FORCED_STOP_ARG (ucbp);
+ _Unwind_Reason_Code pr_result = 0;
+ /* We use phase1_vrs here even though we do not demand save, for the
+ prev_sp field. */
+ phase1_vrs saved_vrs, next_vrs;
+
+ /* Save the core registers. */
+ saved_vrs.core = entry_vrs->core;
+ /* We don't need to demand-save the non-core registers, because we
+ unwind in a single pass. */
+ saved_vrs.demand_save_flags = 0;
+
+ /* Unwind until we reach a propagation barrier. */
+ do
+ {
+ _Unwind_State action;
+ _Unwind_Reason_Code entry_code;
+ _Unwind_Reason_Code stop_code;
+
+ /* Find the entry for this routine. */
+ entry_code = get_eit_entry (ucbp, saved_vrs.core.r[R_PC]);
+
+ if (resuming)
+ {
+ action = _US_UNWIND_FRAME_RESUME | _US_FORCE_UNWIND;
+ resuming = 0;
+ }
+ else
+ action = _US_UNWIND_FRAME_STARTING | _US_FORCE_UNWIND;
+
+ if (entry_code == _URC_OK)
+ {
+ UCB_SAVED_CALLSITE_ADDR (ucbp) = saved_vrs.core.r[R_PC];
+
+ next_vrs = saved_vrs;
+
+ /* Call the pr to decide what to do. */
+ pr_result = ((personality_routine) UCB_PR_ADDR (ucbp))
+ (action, ucbp, (void *) &next_vrs);
+
+ saved_vrs.prev_sp = next_vrs.core.r[R_SP];
+ }
+ else
+ {
+ /* Treat any failure as the end of unwinding, to cope more
+ gracefully with missing EH information. Mixed EH and
+ non-EH within one object will usually result in failure,
+ because the .ARM.exidx tables do not indicate the end
+ of the code to which they apply; but mixed EH and non-EH
+ shared objects should return an unwind failure at the
+ entry of a non-EH shared object. */
+ action |= _US_END_OF_STACK;
+
+ saved_vrs.prev_sp = saved_vrs.core.r[R_SP];
+ }
+
+ stop_code = stop_fn (1, action, ucbp->exception_class, ucbp,
+ (void *)&saved_vrs, stop_arg);
+ if (stop_code != _URC_NO_REASON)
+ return _URC_FAILURE;
+
+ if (entry_code != _URC_OK)
+ return entry_code;
+
+ saved_vrs = next_vrs;
+ }
+ while (pr_result == _URC_CONTINUE_UNWIND);
+
+ if (pr_result != _URC_INSTALL_CONTEXT)
+ {
+ /* Some sort of failure has occurred in the pr and probably the
+ pr returned _URC_FAILURE. */
+ return _URC_FAILURE;
+ }
+
+ restore_core_regs (&saved_vrs.core);
+}
+
+/* This is a very limited implementation of _Unwind_GetCFA. It returns
+ the stack pointer as it is about to be unwound, and is only valid
+ while calling the stop function during forced unwinding. If the
+ current personality routine result is going to run a cleanup, this
+ will not be the CFA; but when the frame is really unwound, it will
+ be. */
+
+_Unwind_Word
+_Unwind_GetCFA (_Unwind_Context *context)
+{
+ return ((phase1_vrs *) context)->prev_sp;
+}
+
+/* Perform phase1 unwinding. UCBP is the exception being thrown, and
+ entry_VRS is the register state on entry to _Unwind_RaiseException. */
+
+_Unwind_Reason_Code
+__gnu_Unwind_RaiseException (_Unwind_Control_Block *, phase2_vrs *);
+
+_Unwind_Reason_Code
+__gnu_Unwind_RaiseException (_Unwind_Control_Block * ucbp,
+ phase2_vrs * entry_vrs)
+{
+ phase1_vrs saved_vrs;
+ _Unwind_Reason_Code pr_result;
+
+ /* Set the pc to the call site. */
+ entry_vrs->core.r[R_PC] = entry_vrs->core.r[R_LR];
+
+ /* Save the core registers. */
+ saved_vrs.core = entry_vrs->core;
+ /* Set demand-save flags. */
+ saved_vrs.demand_save_flags = ~(_uw) 0;
+
+ /* Unwind until we reach a propagation barrier. */
+ do
+ {
+ /* Find the entry for this routine. */
+ if (get_eit_entry (ucbp, saved_vrs.core.r[R_PC]) != _URC_OK)
+ return _URC_FAILURE;
+
+ /* Call the pr to decide what to do. */
+ pr_result = ((personality_routine) UCB_PR_ADDR (ucbp))
+ (_US_VIRTUAL_UNWIND_FRAME, ucbp, (void *) &saved_vrs);
+ }
+ while (pr_result == _URC_CONTINUE_UNWIND);
+
+ /* We've unwound as far as we want to go, so restore the original
+ register state. */
+ restore_non_core_regs (&saved_vrs);
+ if (pr_result != _URC_HANDLER_FOUND)
+ {
+ /* Some sort of failure has occurred in the pr and probably the
+ pr returned _URC_FAILURE. */
+ return _URC_FAILURE;
+ }
+
+ unwind_phase2 (ucbp, entry_vrs);
+}
+
+/* Resume unwinding after a cleanup has been run. UCBP is the exception
+ being thrown and ENTRY_VRS is the register state on entry to
+ _Unwind_Resume. */
+_Unwind_Reason_Code
+__gnu_Unwind_ForcedUnwind (_Unwind_Control_Block *,
+ _Unwind_Stop_Fn, void *, phase2_vrs *);
+
+_Unwind_Reason_Code
+__gnu_Unwind_ForcedUnwind (_Unwind_Control_Block *ucbp,
+ _Unwind_Stop_Fn stop_fn, void *stop_arg,
+ phase2_vrs *entry_vrs)
+{
+ UCB_FORCED_STOP_FN (ucbp) = (_uw) stop_fn;
+ UCB_FORCED_STOP_ARG (ucbp) = (_uw) stop_arg;
+
+ /* Set the pc to the call site. */
+ entry_vrs->core.r[R_PC] = entry_vrs->core.r[R_LR];
+
+ return unwind_phase2_forced (ucbp, entry_vrs, 0);
+}
+
+_Unwind_Reason_Code
+__gnu_Unwind_Resume (_Unwind_Control_Block *, phase2_vrs *);
+
+_Unwind_Reason_Code
+__gnu_Unwind_Resume (_Unwind_Control_Block * ucbp, phase2_vrs * entry_vrs)
+{
+ _Unwind_Reason_Code pr_result;
+
+ /* Recover the saved address. */
+ entry_vrs->core.r[R_PC] = UCB_SAVED_CALLSITE_ADDR (ucbp);
+
+ if (UCB_FORCED_STOP_FN (ucbp))
+ {
+ unwind_phase2_forced (ucbp, entry_vrs, 1);
+
+ /* We can't return failure at this point. */
+ abort ();
+ }
+
+ /* Call the cached PR. */
+ pr_result = ((personality_routine) UCB_PR_ADDR (ucbp))
+ (_US_UNWIND_FRAME_RESUME, ucbp, (_Unwind_Context *) entry_vrs);
+
+ switch (pr_result)
+ {
+ case _URC_INSTALL_CONTEXT:
+ /* Upload the registers to enter the landing pad. */
+ restore_core_regs (&entry_vrs->core);
+
+ case _URC_CONTINUE_UNWIND:
+ /* Continue unwinding the next frame. */
+ unwind_phase2 (ucbp, entry_vrs);
+
+ default:
+ abort ();
+ }
+}
+
+_Unwind_Reason_Code
+__gnu_Unwind_Resume_or_Rethrow (_Unwind_Control_Block *, phase2_vrs *);
+
+_Unwind_Reason_Code
+__gnu_Unwind_Resume_or_Rethrow (_Unwind_Control_Block * ucbp,
+ phase2_vrs * entry_vrs)
+{
+ if (!UCB_FORCED_STOP_FN (ucbp))
+ return __gnu_Unwind_RaiseException (ucbp, entry_vrs);
+
+ /* Set the pc to the call site. */
+ entry_vrs->core.r[R_PC] = entry_vrs->core.r[R_LR];
+ /* Continue unwinding the next frame. */
+ return unwind_phase2_forced (ucbp, entry_vrs, 0);
+}
+
+/* Clean up an exception object when unwinding is complete. */
+void
+_Unwind_Complete (_Unwind_Control_Block * ucbp __attribute__((unused)))
+{
+}
+
+
+/* Get the _Unwind_Control_Block from an _Unwind_Context. */
+
+static inline _Unwind_Control_Block *
+unwind_UCB_from_context (_Unwind_Context * context)
+{
+ return (_Unwind_Control_Block *) _Unwind_GetGR (context, R_IP);
+}
+
+
+/* Free an exception. */
+
+void
+_Unwind_DeleteException (_Unwind_Exception * exc)
+{
+ if (exc->exception_cleanup)
+ (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc);
+}
+
+
+/* Common implementation for ARM ABI defined personality routines.
+ ID is the index of the personality routine, other arguments are as defined
+ by __aeabi_unwind_cpp_pr{0,1,2}. */
+
+static _Unwind_Reason_Code
+__gnu_unwind_pr_common (_Unwind_State state,
+ _Unwind_Control_Block *ucbp,
+ _Unwind_Context *context,
+ int id)
+{
+ __gnu_unwind_state uws;
+ _uw *data;
+ _uw offset;
+ _uw len;
+ _uw rtti_count;
+ int phase2_call_unexpected_after_unwind = 0;
+ int in_range = 0;
+ int forced_unwind = state & _US_FORCE_UNWIND;
+
+ state &= _US_ACTION_MASK;
+
+ data = (_uw *) ucbp->pr_cache.ehtp;
+ uws.data = *(data++);
+ uws.next = data;
+ if (id == 0)
+ {
+ uws.data <<= 8;
+ uws.words_left = 0;
+ uws.bytes_left = 3;
+ }
+ else
+ {
+ uws.words_left = (uws.data >> 16) & 0xff;
+ uws.data <<= 16;
+ uws.bytes_left = 2;
+ data += uws.words_left;
+ }
+
+ /* Restore the saved pointer. */
+ if (state == _US_UNWIND_FRAME_RESUME)
+ data = (_uw *) ucbp->cleanup_cache.bitpattern[0];
+
+ if ((ucbp->pr_cache.additional & 1) == 0)
+ {
+ /* Process descriptors. */
+ while (*data)
+ {
+ _uw addr;
+ _uw fnstart;
+
+ if (id == 2)
+ {
+ len = ((EHT32 *) data)->length;
+ offset = ((EHT32 *) data)->offset;
+ data += 2;
+ }
+ else
+ {
+ len = ((EHT16 *) data)->length;
+ offset = ((EHT16 *) data)->offset;
+ data++;
+ }
+
+ fnstart = ucbp->pr_cache.fnstart + (offset & ~1);
+ addr = _Unwind_GetGR (context, R_PC);
+ in_range = (fnstart <= addr && addr < fnstart + (len & ~1));
+
+ switch (((offset & 1) << 1) | (len & 1))
+ {
+ case 0:
+ /* Cleanup. */
+ if (state != _US_VIRTUAL_UNWIND_FRAME
+ && in_range)
+ {
+ /* Cleanup in range, and we are running cleanups. */
+ _uw lp;
+
+ /* Landing pad address is 31-bit pc-relative offset. */
+ lp = selfrel_offset31 (data);
+ data++;
+ /* Save the exception data pointer. */
+ ucbp->cleanup_cache.bitpattern[0] = (_uw) data;
+ if (!__cxa_begin_cleanup (ucbp))
+ return _URC_FAILURE;
+ /* Setup the VRS to enter the landing pad. */
+ _Unwind_SetGR (context, R_PC, lp);
+ return _URC_INSTALL_CONTEXT;
+ }
+ /* Cleanup not in range, or we are in stage 1. */
+ data++;
+ break;
+
+ case 1:
+ /* Catch handler. */
+ if (state == _US_VIRTUAL_UNWIND_FRAME)
+ {
+ if (in_range)
+ {
+ /* Check for a barrier. */
+ _uw rtti;
+ void *matched;
+
+ /* Check for no-throw areas. */
+ if (data[1] == (_uw) -2)
+ return _URC_FAILURE;
+
+ /* The thrown object immediately follows the ECB. */
+ matched = (void *)(ucbp + 1);
+ if (data[1] != (_uw) -1)
+ {
+ /* Match a catch specification. */
+ rtti = _Unwind_decode_target2 ((_uw) &data[1]);
+ if (!__cxa_type_match (ucbp, (type_info *) rtti,
+ &matched))
+ matched = (void *)0;
+ }
+
+ if (matched)
+ {
+ ucbp->barrier_cache.sp =
+ _Unwind_GetGR (context, R_SP);
+ ucbp->barrier_cache.bitpattern[0] = (_uw) matched;
+ ucbp->barrier_cache.bitpattern[1] = (_uw) data;
+ return _URC_HANDLER_FOUND;
+ }
+ }
+ /* Handler out of range, or not matched. */
+ }
+ else if (ucbp->barrier_cache.sp == _Unwind_GetGR (context, R_SP)
+ && ucbp->barrier_cache.bitpattern[1] == (_uw) data)
+ {
+ /* Matched a previous propagation barrier. */
+ _uw lp;
+
+ /* Setup for entry to the handler. */
+ lp = selfrel_offset31 (data);
+ _Unwind_SetGR (context, R_PC, lp);
+ _Unwind_SetGR (context, 0, (_uw) ucbp);
+ return _URC_INSTALL_CONTEXT;
+ }
+ /* Catch handler not matched. Advance to the next descriptor. */
+ data += 2;
+ break;
+
+ case 2:
+ rtti_count = data[0] & 0x7fffffff;
+ /* Exception specification. */
+ if (state == _US_VIRTUAL_UNWIND_FRAME)
+ {
+ if (in_range && (!forced_unwind || !rtti_count))
+ {
+ /* Match against the exception specification. */
+ _uw i;
+ _uw rtti;
+ void *matched;
+
+ for (i = 0; i < rtti_count; i++)
+ {
+ matched = (void *)(ucbp + 1);
+ rtti = _Unwind_decode_target2 ((_uw) &data[i + 1]);
+ if (__cxa_type_match (ucbp, (type_info *) rtti,
+ &matched))
+ break;
+ }
+
+ if (i == rtti_count)
+ {
+ /* Exception does not match the spec. */
+ ucbp->barrier_cache.sp =
+ _Unwind_GetGR (context, R_SP);
+ ucbp->barrier_cache.bitpattern[0] = (_uw) matched;
+ ucbp->barrier_cache.bitpattern[1] = (_uw) data;
+ return _URC_HANDLER_FOUND;
+ }
+ }
+ /* Handler out of range, or exception is permitted. */
+ }
+ else if (ucbp->barrier_cache.sp == _Unwind_GetGR (context, R_SP)
+ && ucbp->barrier_cache.bitpattern[1] == (_uw) data)
+ {
+ /* Matched a previous propagation barrier. */
+ _uw lp;
+ /* Record the RTTI list for __cxa_call_unexpected. */
+ ucbp->barrier_cache.bitpattern[1] = rtti_count;
+ ucbp->barrier_cache.bitpattern[2] = 0;
+ ucbp->barrier_cache.bitpattern[3] = 4;
+ ucbp->barrier_cache.bitpattern[4] = (_uw) &data[1];
+
+ if (data[0] & uint32_highbit)
+ phase2_call_unexpected_after_unwind = 1;
+ else
+ {
+ data += rtti_count + 1;
+ /* Setup for entry to the handler. */
+ lp = selfrel_offset31 (data);
+ data++;
+ _Unwind_SetGR (context, R_PC, lp);
+ _Unwind_SetGR (context, 0, (_uw) ucbp);
+ return _URC_INSTALL_CONTEXT;
+ }
+ }
+ if (data[0] & uint32_highbit)
+ data++;
+ data += rtti_count + 1;
+ break;
+
+ default:
+ /* Should never happen. */
+ return _URC_FAILURE;
+ }
+ /* Finished processing this descriptor. */
+ }
+ }
+
+ if (__gnu_unwind_execute (context, &uws) != _URC_OK)
+ return _URC_FAILURE;
+
+ if (phase2_call_unexpected_after_unwind)
+ {
+ /* Enter __cxa_unexpected as if called from the call site. */
+ _Unwind_SetGR (context, R_LR, _Unwind_GetGR (context, R_PC));
+ _Unwind_SetGR (context, R_PC, (_uw) &__cxa_call_unexpected);
+ return _URC_INSTALL_CONTEXT;
+ }
+
+ return _URC_CONTINUE_UNWIND;
+}
+
+
+/* ABI defined personality routine entry points. */
+
+_Unwind_Reason_Code
+__aeabi_unwind_cpp_pr0 (_Unwind_State state,
+ _Unwind_Control_Block *ucbp,
+ _Unwind_Context *context)
+{
+ return __gnu_unwind_pr_common (state, ucbp, context, 0);
+}
+
+_Unwind_Reason_Code
+__aeabi_unwind_cpp_pr1 (_Unwind_State state,
+ _Unwind_Control_Block *ucbp,
+ _Unwind_Context *context)
+{
+ return __gnu_unwind_pr_common (state, ucbp, context, 1);
+}
+
+_Unwind_Reason_Code
+__aeabi_unwind_cpp_pr2 (_Unwind_State state,
+ _Unwind_Control_Block *ucbp,
+ _Unwind_Context *context)
+{
+ return __gnu_unwind_pr_common (state, ucbp, context, 2);
+}
+
+/* These two should never be used. */
+_Unwind_Ptr
+_Unwind_GetDataRelBase (_Unwind_Context *context __attribute__ ((unused)))
+{
+ abort ();
+}
+
+_Unwind_Ptr
+_Unwind_GetTextRelBase (_Unwind_Context *context __attribute__ ((unused)))
+{
+ abort ();
+}
diff --git a/contrib/gcc/config/arm/unwind-arm.h b/contrib/gcc/config/arm/unwind-arm.h
new file mode 100644
index 0000000..a3040d7
--- /dev/null
+++ b/contrib/gcc/config/arm/unwind-arm.h
@@ -0,0 +1,271 @@
+/* Header file for the ARM EABI unwinder
+ Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ Contributed by Paul Brook
+
+ 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, 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.)
+
+ 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 program; see the file COPYING. If not, write to
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* Language-independent unwinder header public defines. This contains both
+ ABI defined objects, and GNU support routines. */
+
+#ifndef UNWIND_ARM_H
+#define UNWIND_ARM_H
+
+#define __ARM_EABI_UNWINDER__ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ typedef unsigned _Unwind_Word __attribute__((__mode__(__word__)));
+ typedef signed _Unwind_Sword __attribute__((__mode__(__word__)));
+ typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)));
+ typedef unsigned _Unwind_Internal_Ptr __attribute__((__mode__(__pointer__)));
+ typedef _Unwind_Word _uw;
+ typedef unsigned _uw64 __attribute__((mode(__DI__)));
+ typedef unsigned _uw16 __attribute__((mode(__HI__)));
+ typedef unsigned _uw8 __attribute__((mode(__QI__)));
+
+ typedef enum
+ {
+ _URC_OK = 0, /* operation completed successfully */
+ _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+ _URC_END_OF_STACK = 5,
+ _URC_HANDLER_FOUND = 6,
+ _URC_INSTALL_CONTEXT = 7,
+ _URC_CONTINUE_UNWIND = 8,
+ _URC_FAILURE = 9 /* unspecified failure of some kind */
+ }
+ _Unwind_Reason_Code;
+
+ typedef enum
+ {
+ _US_VIRTUAL_UNWIND_FRAME = 0,
+ _US_UNWIND_FRAME_STARTING = 1,
+ _US_UNWIND_FRAME_RESUME = 2,
+ _US_ACTION_MASK = 3,
+ _US_FORCE_UNWIND = 8,
+ _US_END_OF_STACK = 16
+ }
+ _Unwind_State;
+
+ /* Provided only for for compatibility with existing code. */
+ typedef int _Unwind_Action;
+#define _UA_SEARCH_PHASE 1
+#define _UA_CLEANUP_PHASE 2
+#define _UA_HANDLER_FRAME 4
+#define _UA_FORCE_UNWIND 8
+#define _UA_END_OF_STACK 16
+#define _URC_NO_REASON _URC_OK
+
+ typedef struct _Unwind_Control_Block _Unwind_Control_Block;
+ typedef struct _Unwind_Context _Unwind_Context;
+ typedef _uw _Unwind_EHT_Header;
+
+
+ /* UCB: */
+
+ struct _Unwind_Control_Block
+ {
+ char exception_class[8];
+ void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block *);
+ /* Unwinder cache, private fields for the unwinder's use */
+ struct
+ {
+ _uw reserved1; /* Forced unwind stop fn, 0 if not forced */
+ _uw reserved2; /* Personality routine address */
+ _uw reserved3; /* Saved callsite address */
+ _uw reserved4; /* Forced unwind stop arg */
+ _uw reserved5;
+ }
+ unwinder_cache;
+ /* Propagation barrier cache (valid after phase 1): */
+ struct
+ {
+ _uw sp;
+ _uw bitpattern[5];
+ }
+ barrier_cache;
+ /* Cleanup cache (preserved over cleanup): */
+ struct
+ {
+ _uw bitpattern[4];
+ }
+ cleanup_cache;
+ /* Pr cache (for pr's benefit): */
+ struct
+ {
+ _uw fnstart; /* function start address */
+ _Unwind_EHT_Header *ehtp; /* pointer to EHT entry header word */
+ _uw additional; /* additional data */
+ _uw reserved1;
+ }
+ pr_cache;
+ long long int :0; /* Force alignment to 8-byte boundary */
+ };
+
+ /* Virtual Register Set*/
+
+ typedef enum
+ {
+ _UVRSC_CORE = 0, /* integer register */
+ _UVRSC_VFP = 1, /* vfp */
+ _UVRSC_FPA = 2, /* fpa */
+ _UVRSC_WMMXD = 3, /* Intel WMMX data register */
+ _UVRSC_WMMXC = 4 /* Intel WMMX control register */
+ }
+ _Unwind_VRS_RegClass;
+
+ typedef enum
+ {
+ _UVRSD_UINT32 = 0,
+ _UVRSD_VFPX = 1,
+ _UVRSD_FPAX = 2,
+ _UVRSD_UINT64 = 3,
+ _UVRSD_FLOAT = 4,
+ _UVRSD_DOUBLE = 5
+ }
+ _Unwind_VRS_DataRepresentation;
+
+ typedef enum
+ {
+ _UVRSR_OK = 0,
+ _UVRSR_NOT_IMPLEMENTED = 1,
+ _UVRSR_FAILED = 2
+ }
+ _Unwind_VRS_Result;
+
+ /* Frame unwinding state. */
+ typedef struct
+ {
+ /* The current word (bytes packed msb first). */
+ _uw data;
+ /* Pointer to the next word of data. */
+ _uw *next;
+ /* The number of bytes left in this word. */
+ _uw8 bytes_left;
+ /* The number of words pointed to by ptr. */
+ _uw8 words_left;
+ }
+ __gnu_unwind_state;
+
+ typedef _Unwind_Reason_Code (*personality_routine) (_Unwind_State,
+ _Unwind_Control_Block *, _Unwind_Context *);
+
+ _Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *, _Unwind_VRS_RegClass,
+ _uw, _Unwind_VRS_DataRepresentation,
+ void *);
+
+ _Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *, _Unwind_VRS_RegClass,
+ _uw, _Unwind_VRS_DataRepresentation,
+ void *);
+
+ _Unwind_VRS_Result _Unwind_VRS_Pop(_Unwind_Context *, _Unwind_VRS_RegClass,
+ _uw, _Unwind_VRS_DataRepresentation);
+
+
+ /* Support functions for the PR. */
+#define _Unwind_Exception _Unwind_Control_Block
+ typedef char _Unwind_Exception_Class[8];
+
+ void * _Unwind_GetLanguageSpecificData (_Unwind_Context *);
+ _Unwind_Ptr _Unwind_GetRegionStart (_Unwind_Context *);
+
+ /* These two should never be used. */
+ _Unwind_Ptr _Unwind_GetDataRelBase (_Unwind_Context *);
+ _Unwind_Ptr _Unwind_GetTextRelBase (_Unwind_Context *);
+
+ /* Interface functions: */
+ _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Control_Block *ucbp);
+ void __attribute__((noreturn)) _Unwind_Resume(_Unwind_Control_Block *ucbp);
+ _Unwind_Reason_Code _Unwind_Resume_or_Rethrow (_Unwind_Control_Block *ucbp);
+
+ typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
+ (int, _Unwind_Action, _Unwind_Exception_Class,
+ _Unwind_Control_Block *, struct _Unwind_Context *, void *);
+ _Unwind_Reason_Code _Unwind_ForcedUnwind (_Unwind_Control_Block *,
+ _Unwind_Stop_Fn, void *);
+ _Unwind_Word _Unwind_GetCFA (struct _Unwind_Context *);
+ void _Unwind_Complete(_Unwind_Control_Block *ucbp);
+ void _Unwind_DeleteException (_Unwind_Exception *);
+
+ _Unwind_Reason_Code __gnu_unwind_frame (_Unwind_Control_Block *,
+ _Unwind_Context *);
+ _Unwind_Reason_Code __gnu_unwind_execute (_Unwind_Context *,
+ __gnu_unwind_state *);
+
+ /* Decode an R_ARM_TARGET2 relocation. */
+ static inline _Unwind_Word
+ _Unwind_decode_target2 (_Unwind_Word ptr)
+ {
+ _Unwind_Word tmp;
+
+ tmp = *(_Unwind_Word *) ptr;
+ /* Zero values are always NULL. */
+ if (!tmp)
+ return 0;
+
+#if defined(linux) || defined(__NetBSD__)
+ /* Pc-relative indirect. */
+ tmp += ptr;
+ tmp = *(_Unwind_Word *) tmp;
+#elif defined(__symbian__)
+ /* Absolute pointer. Nothing more to do. */
+#else
+ /* Pc-relative pointer. */
+ tmp += ptr;
+#endif
+ return tmp;
+ }
+
+ static inline _Unwind_Word
+ _Unwind_GetGR (_Unwind_Context *context, int regno)
+ {
+ _uw val;
+ _Unwind_VRS_Get (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val);
+ return val;
+ }
+
+ /* Return the address of the instruction, not the actual IP value. */
+#define _Unwind_GetIP(context) \
+ (_Unwind_GetGR (context, 15) & ~(_Unwind_Word)1)
+
+#define _Unwind_GetIPInfo(context, ip_before_insn) \
+ (*ip_before_insn = 0, _Unwind_GetGR (context, 15) & ~(_Unwind_Word)1)
+
+ static inline void
+ _Unwind_SetGR (_Unwind_Context *context, int regno, _Unwind_Word val)
+ {
+ _Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val);
+ }
+
+ /* The dwarf unwinder doesn't understand arm/thumb state. We assume the
+ landing pad uses the same instruction set as the call site. */
+#define _Unwind_SetIP(context, val) \
+ _Unwind_SetGR (context, 15, val | (_Unwind_GetGR (context, 15) & 1))
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* defined UNWIND_ARM_H */
diff --git a/contrib/gcc/config/arm/vfp.md b/contrib/gcc/config/arm/vfp.md
new file mode 100644
index 0000000..2380c83
--- /dev/null
+++ b/contrib/gcc/config/arm/vfp.md
@@ -0,0 +1,841 @@
+;; ARM VFP coprocessor Machine Description
+;; Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+;; Written by CodeSourcery, LLC.
+;;
+;; 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.
+;;
+;; 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. */
+
+;; Additional register numbers
+(define_constants
+ [(VFPCC_REGNUM 95)]
+)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Pipeline description
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define_automaton "vfp11")
+
+;; There are 3 pipelines in the VFP11 unit.
+;;
+;; - A 8-stage FMAC pipeline (7 execute + writeback) with forward from
+;; fourth stage for simple operations.
+;;
+;; - A 5-stage DS pipeline (4 execute + writeback) for divide/sqrt insns.
+;; These insns also uses first execute stage of FMAC pipeline.
+;;
+;; - A 4-stage LS pipeline (execute + 2 memory + writeback) with forward from
+;; second memory stage for loads.
+
+;; We do not model Write-After-Read hazards.
+;; We do not do write scheduling with the arm core, so it is only necessary
+;; to model the first stage of each pipeline
+;; ??? Need to model LS pipeline properly for load/store multiple?
+;; We do not model fmstat properly. This could be done by modeling pipelines
+;; properly and defining an absence set between a dummy fmstat unit and all
+;; other vfp units.
+
+(define_cpu_unit "fmac" "vfp11")
+
+(define_cpu_unit "ds" "vfp11")
+
+(define_cpu_unit "vfp_ls" "vfp11")
+
+(define_cpu_unit "fmstat" "vfp11")
+
+(exclusion_set "fmac,ds" "fmstat")
+
+;; The VFP "type" attributes differ from those used in the FPA model.
+;; ffarith Fast floating point insns, e.g. abs, neg, cpy, cmp.
+;; farith Most arithmetic insns.
+;; fmul Double precision multiply.
+;; fdivs Single precision sqrt or division.
+;; fdivd Double precision sqrt or division.
+;; f_flag fmstat operation
+;; f_load[sd] Floating point load from memory.
+;; f_store[sd] Floating point store to memory.
+;; f_2_r Transfer vfp to arm reg.
+;; r_2_f Transfer arm to vfp reg.
+;; f_cvt Convert floating<->integral
+
+(define_insn_reservation "vfp_ffarith" 4
+ (and (eq_attr "generic_vfp" "yes")
+ (eq_attr "type" "ffarith"))
+ "fmac")
+
+(define_insn_reservation "vfp_farith" 8
+ (and (eq_attr "generic_vfp" "yes")
+ (eq_attr "type" "farith,f_cvt"))
+ "fmac")
+
+(define_insn_reservation "vfp_fmul" 9
+ (and (eq_attr "generic_vfp" "yes")
+ (eq_attr "type" "fmul"))
+ "fmac*2")
+
+(define_insn_reservation "vfp_fdivs" 19
+ (and (eq_attr "generic_vfp" "yes")
+ (eq_attr "type" "fdivs"))
+ "ds*15")
+
+(define_insn_reservation "vfp_fdivd" 33
+ (and (eq_attr "generic_vfp" "yes")
+ (eq_attr "type" "fdivd"))
+ "fmac+ds*29")
+
+;; Moves to/from arm regs also use the load/store pipeline.
+(define_insn_reservation "vfp_fload" 4
+ (and (eq_attr "generic_vfp" "yes")
+ (eq_attr "type" "f_loads,f_loadd,r_2_f"))
+ "vfp_ls")
+
+(define_insn_reservation "vfp_fstore" 4
+ (and (eq_attr "generic_vfp" "yes")
+ (eq_attr "type" "f_stores,f_stored,f_2_r"))
+ "vfp_ls")
+
+(define_insn_reservation "vfp_to_cpsr" 4
+ (and (eq_attr "generic_vfp" "yes")
+ (eq_attr "type" "f_flag"))
+ "fmstat,vfp_ls*3")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Insn pattern
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; SImode moves
+;; ??? For now do not allow loading constants into vfp regs. This causes
+;; problems because small constants get converted into adds.
+(define_insn "*arm_movsi_vfp"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r ,m,*w,r,*w,*w, *Uv")
+ (match_operand:SI 1 "general_operand" "rI,K,mi,r,r,*w,*w,*Uvi,*w"))]
+ "TARGET_ARM && TARGET_VFP && TARGET_HARD_FLOAT
+ && ( s_register_operand (operands[0], SImode)
+ || s_register_operand (operands[1], SImode))"
+ "@
+ mov%?\\t%0, %1
+ mvn%?\\t%0, #%B1
+ ldr%?\\t%0, %1
+ str%?\\t%1, %0
+ fmsr%?\\t%0, %1\\t%@ int
+ fmrs%?\\t%0, %1\\t%@ int
+ fcpys%?\\t%0, %1\\t%@ int
+ flds%?\\t%0, %1\\t%@ int
+ fsts%?\\t%1, %0\\t%@ int"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "*,*,load1,store1,r_2_f,f_2_r,ffarith,f_loads,f_stores")
+ (set_attr "pool_range" "*,*,4096,*,*,*,*,1020,*")
+ (set_attr "neg_pool_range" "*,*,4084,*,*,*,*,1008,*")]
+)
+
+
+;; DImode moves
+
+(define_insn "*arm_movdi_vfp"
+ [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r, r,m,w,r,w,w, Uv")
+ (match_operand:DI 1 "di_operand" "rIK,mi,r,r,w,w,Uvi,w"))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP
+ && ( register_operand (operands[0], DImode)
+ || register_operand (operands[1], DImode))"
+ "*
+ switch (which_alternative)
+ {
+ case 0:
+ return \"#\";
+ case 1:
+ case 2:
+ return output_move_double (operands);
+ case 3:
+ return \"fmdrr%?\\t%P0, %Q1, %R1\\t%@ int\";
+ case 4:
+ return \"fmrrd%?\\t%Q0, %R0, %P1\\t%@ int\";
+ case 5:
+ return \"fcpyd%?\\t%P0, %P1\\t%@ int\";
+ case 6:
+ return \"fldd%?\\t%P0, %1\\t%@ int\";
+ case 7:
+ return \"fstd%?\\t%P1, %0\\t%@ int\";
+ default:
+ gcc_unreachable ();
+ }
+ "
+ [(set_attr "type" "*,load2,store2,r_2_f,f_2_r,ffarith,f_loadd,f_stored")
+ (set_attr "length" "8,8,8,4,4,4,4,4")
+ (set_attr "pool_range" "*,1020,*,*,*,*,1020,*")
+ (set_attr "neg_pool_range" "*,1008,*,*,*,*,1008,*")]
+)
+
+
+;; SFmode moves
+;; Disparage the w<->r cases because reloading an invalid address is
+;; preferable to loading the value via integer registers.
+
+(define_insn "*movsf_vfp"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=w,?r,w ,Uv,r ,m,w,r")
+ (match_operand:SF 1 "general_operand" " ?r,w,UvE,w, mE,r,w,r"))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP
+ && ( s_register_operand (operands[0], SFmode)
+ || s_register_operand (operands[1], SFmode))"
+ "@
+ fmsr%?\\t%0, %1
+ fmrs%?\\t%0, %1
+ flds%?\\t%0, %1
+ fsts%?\\t%1, %0
+ ldr%?\\t%0, %1\\t%@ float
+ str%?\\t%1, %0\\t%@ float
+ fcpys%?\\t%0, %1
+ mov%?\\t%0, %1\\t%@ float"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "r_2_f,f_2_r,ffarith,*,f_loads,f_stores,load1,store1")
+ (set_attr "pool_range" "*,*,1020,*,4096,*,*,*")
+ (set_attr "neg_pool_range" "*,*,1008,*,4080,*,*,*")]
+)
+
+
+;; DFmode moves
+
+(define_insn "*movdf_vfp"
+ [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=w,?r,r, m,w ,Uv,w,r")
+ (match_operand:DF 1 "soft_df_operand" " ?r,w,mF,r,UvF,w, w,r"))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP
+ && ( register_operand (operands[0], DFmode)
+ || register_operand (operands[1], DFmode))"
+ "*
+ {
+ switch (which_alternative)
+ {
+ case 0:
+ return \"fmdrr%?\\t%P0, %Q1, %R1\";
+ case 1:
+ return \"fmrrd%?\\t%Q0, %R0, %P1\";
+ case 2: case 3:
+ return output_move_double (operands);
+ case 4:
+ return \"fldd%?\\t%P0, %1\";
+ case 5:
+ return \"fstd%?\\t%P1, %0\";
+ case 6:
+ return \"fcpyd%?\\t%P0, %P1\";
+ case 7:
+ return \"#\";
+ default:
+ gcc_unreachable ();
+ }
+ }
+ "
+ [(set_attr "type" "r_2_f,f_2_r,ffarith,*,load2,store2,f_loadd,f_stored")
+ (set_attr "length" "4,4,8,8,4,4,4,8")
+ (set_attr "pool_range" "*,*,1020,*,1020,*,*,*")
+ (set_attr "neg_pool_range" "*,*,1008,*,1008,*,*,*")]
+)
+
+
+;; Conditional move patterns
+
+(define_insn "*movsfcc_vfp"
+ [(set (match_operand:SF 0 "s_register_operand" "=w,w,w,w,w,w,?r,?r,?r")
+ (if_then_else:SF
+ (match_operator 3 "arm_comparison_operator"
+ [(match_operand 4 "cc_register" "") (const_int 0)])
+ (match_operand:SF 1 "s_register_operand" "0,w,w,0,?r,?r,0,w,w")
+ (match_operand:SF 2 "s_register_operand" "w,0,w,?r,0,?r,w,0,w")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "@
+ fcpys%D3\\t%0, %2
+ fcpys%d3\\t%0, %1
+ fcpys%D3\\t%0, %2\;fcpys%d3\\t%0, %1
+ fmsr%D3\\t%0, %2
+ fmsr%d3\\t%0, %1
+ fmsr%D3\\t%0, %2\;fmsr%d3\\t%0, %1
+ fmrs%D3\\t%0, %2
+ fmrs%d3\\t%0, %1
+ fmrs%D3\\t%0, %2\;fmrs%d3\\t%0, %1"
+ [(set_attr "conds" "use")
+ (set_attr "length" "4,4,8,4,4,8,4,4,8")
+ (set_attr "type" "ffarith,ffarith,ffarith,r_2_f,r_2_f,r_2_f,f_2_r,f_2_r,f_2_r")]
+)
+
+(define_insn "*movdfcc_vfp"
+ [(set (match_operand:DF 0 "s_register_operand" "=w,w,w,w,w,w,?r,?r,?r")
+ (if_then_else:DF
+ (match_operator 3 "arm_comparison_operator"
+ [(match_operand 4 "cc_register" "") (const_int 0)])
+ (match_operand:DF 1 "s_register_operand" "0,w,w,0,?r,?r,0,w,w")
+ (match_operand:DF 2 "s_register_operand" "w,0,w,?r,0,?r,w,0,w")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "@
+ fcpyd%D3\\t%P0, %P2
+ fcpyd%d3\\t%P0, %P1
+ fcpyd%D3\\t%P0, %P2\;fcpyd%d3\\t%P0, %P1
+ fmdrr%D3\\t%P0, %Q2, %R2
+ fmdrr%d3\\t%P0, %Q1, %R1
+ fmdrr%D3\\t%P0, %Q2, %R2\;fmdrr%d3\\t%P0, %Q1, %R1
+ fmrrd%D3\\t%Q0, %R0, %P2
+ fmrrd%d3\\t%Q0, %R0, %P1
+ fmrrd%D3\\t%Q0, %R0, %P2\;fmrrd%d3\\t%Q0, %R0, %P1"
+ [(set_attr "conds" "use")
+ (set_attr "length" "4,4,8,4,4,8,4,4,8")
+ (set_attr "type" "ffarith,ffarith,ffarith,r_2_f,r_2_f,r_2_f,f_2_r,f_2_r,f_2_r")]
+)
+
+
+;; Sign manipulation functions
+
+(define_insn "*abssf2_vfp"
+ [(set (match_operand:SF 0 "s_register_operand" "=w")
+ (abs:SF (match_operand:SF 1 "s_register_operand" "w")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fabss%?\\t%0, %1"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "ffarith")]
+)
+
+(define_insn "*absdf2_vfp"
+ [(set (match_operand:DF 0 "s_register_operand" "=w")
+ (abs:DF (match_operand:DF 1 "s_register_operand" "w")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fabsd%?\\t%P0, %P1"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "ffarith")]
+)
+
+(define_insn "*negsf2_vfp"
+ [(set (match_operand:SF 0 "s_register_operand" "=w,?r")
+ (neg:SF (match_operand:SF 1 "s_register_operand" "w,r")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "@
+ fnegs%?\\t%0, %1
+ eor%?\\t%0, %1, #-2147483648"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "ffarith")]
+)
+
+(define_insn_and_split "*negdf2_vfp"
+ [(set (match_operand:DF 0 "s_register_operand" "=w,?r,?r")
+ (neg:DF (match_operand:DF 1 "s_register_operand" "w,0,r")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "@
+ fnegd%?\\t%P0, %P1
+ #
+ #"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP && reload_completed
+ && arm_general_register_operand (operands[0], DFmode)"
+ [(set (match_dup 0) (match_dup 1))]
+ "
+ if (REGNO (operands[0]) == REGNO (operands[1]))
+ {
+ operands[0] = gen_highpart (SImode, operands[0]);
+ operands[1] = gen_rtx_XOR (SImode, operands[0], GEN_INT (0x80000000));
+ }
+ else
+ {
+ rtx in_hi, in_lo, out_hi, out_lo;
+
+ in_hi = gen_rtx_XOR (SImode, gen_highpart (SImode, operands[1]),
+ GEN_INT (0x80000000));
+ in_lo = gen_lowpart (SImode, operands[1]);
+ out_hi = gen_highpart (SImode, operands[0]);
+ out_lo = gen_lowpart (SImode, operands[0]);
+
+ if (REGNO (in_lo) == REGNO (out_hi))
+ {
+ emit_insn (gen_rtx_SET (SImode, out_lo, in_lo));
+ operands[0] = out_hi;
+ operands[1] = in_hi;
+ }
+ else
+ {
+ emit_insn (gen_rtx_SET (SImode, out_hi, in_hi));
+ operands[0] = out_lo;
+ operands[1] = in_lo;
+ }
+ }
+ "
+ [(set_attr "predicable" "yes")
+ (set_attr "length" "4,4,8")
+ (set_attr "type" "ffarith")]
+)
+
+
+;; Arithmetic insns
+
+(define_insn "*addsf3_vfp"
+ [(set (match_operand:SF 0 "s_register_operand" "=w")
+ (plus:SF (match_operand:SF 1 "s_register_operand" "w")
+ (match_operand:SF 2 "s_register_operand" "w")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fadds%?\\t%0, %1, %2"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "farith")]
+)
+
+(define_insn "*adddf3_vfp"
+ [(set (match_operand:DF 0 "s_register_operand" "=w")
+ (plus:DF (match_operand:DF 1 "s_register_operand" "w")
+ (match_operand:DF 2 "s_register_operand" "w")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "faddd%?\\t%P0, %P1, %P2"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "farith")]
+)
+
+
+(define_insn "*subsf3_vfp"
+ [(set (match_operand:SF 0 "s_register_operand" "=w")
+ (minus:SF (match_operand:SF 1 "s_register_operand" "w")
+ (match_operand:SF 2 "s_register_operand" "w")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fsubs%?\\t%0, %1, %2"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "farith")]
+)
+
+(define_insn "*subdf3_vfp"
+ [(set (match_operand:DF 0 "s_register_operand" "=w")
+ (minus:DF (match_operand:DF 1 "s_register_operand" "w")
+ (match_operand:DF 2 "s_register_operand" "w")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fsubd%?\\t%P0, %P1, %P2"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "farith")]
+)
+
+
+;; Division insns
+
+(define_insn "*divsf3_vfp"
+ [(set (match_operand:SF 0 "s_register_operand" "+w")
+ (div:SF (match_operand:SF 1 "s_register_operand" "w")
+ (match_operand:SF 2 "s_register_operand" "w")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fdivs%?\\t%0, %1, %2"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "fdivs")]
+)
+
+(define_insn "*divdf3_vfp"
+ [(set (match_operand:DF 0 "s_register_operand" "+w")
+ (div:DF (match_operand:DF 1 "s_register_operand" "w")
+ (match_operand:DF 2 "s_register_operand" "w")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fdivd%?\\t%P0, %P1, %P2"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "fdivd")]
+)
+
+
+;; Multiplication insns
+
+(define_insn "*mulsf3_vfp"
+ [(set (match_operand:SF 0 "s_register_operand" "+w")
+ (mult:SF (match_operand:SF 1 "s_register_operand" "w")
+ (match_operand:SF 2 "s_register_operand" "w")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fmuls%?\\t%0, %1, %2"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "farith")]
+)
+
+(define_insn "*muldf3_vfp"
+ [(set (match_operand:DF 0 "s_register_operand" "+w")
+ (mult:DF (match_operand:DF 1 "s_register_operand" "w")
+ (match_operand:DF 2 "s_register_operand" "w")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fmuld%?\\t%P0, %P1, %P2"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "fmul")]
+)
+
+
+(define_insn "*mulsf3negsf_vfp"
+ [(set (match_operand:SF 0 "s_register_operand" "+w")
+ (mult:SF (neg:SF (match_operand:SF 1 "s_register_operand" "w"))
+ (match_operand:SF 2 "s_register_operand" "w")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fnmuls%?\\t%0, %1, %2"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "farith")]
+)
+
+(define_insn "*muldf3negdf_vfp"
+ [(set (match_operand:DF 0 "s_register_operand" "+w")
+ (mult:DF (neg:DF (match_operand:DF 1 "s_register_operand" "w"))
+ (match_operand:DF 2 "s_register_operand" "w")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fnmuld%?\\t%P0, %P1, %P2"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "fmul")]
+)
+
+
+;; Multiply-accumulate insns
+
+;; 0 = 1 * 2 + 0
+(define_insn "*mulsf3addsf_vfp"
+ [(set (match_operand:SF 0 "s_register_operand" "=w")
+ (plus:SF (mult:SF (match_operand:SF 2 "s_register_operand" "w")
+ (match_operand:SF 3 "s_register_operand" "w"))
+ (match_operand:SF 1 "s_register_operand" "0")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fmacs%?\\t%0, %2, %3"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "farith")]
+)
+
+(define_insn "*muldf3adddf_vfp"
+ [(set (match_operand:DF 0 "s_register_operand" "=w")
+ (plus:DF (mult:DF (match_operand:DF 2 "s_register_operand" "w")
+ (match_operand:DF 3 "s_register_operand" "w"))
+ (match_operand:DF 1 "s_register_operand" "0")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fmacd%?\\t%P0, %P2, %P3"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "fmul")]
+)
+
+;; 0 = 1 * 2 - 0
+(define_insn "*mulsf3subsf_vfp"
+ [(set (match_operand:SF 0 "s_register_operand" "=w")
+ (minus:SF (mult:SF (match_operand:SF 2 "s_register_operand" "w")
+ (match_operand:SF 3 "s_register_operand" "w"))
+ (match_operand:SF 1 "s_register_operand" "0")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fmscs%?\\t%0, %2, %3"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "farith")]
+)
+
+(define_insn "*muldf3subdf_vfp"
+ [(set (match_operand:DF 0 "s_register_operand" "=w")
+ (minus:DF (mult:DF (match_operand:DF 2 "s_register_operand" "w")
+ (match_operand:DF 3 "s_register_operand" "w"))
+ (match_operand:DF 1 "s_register_operand" "0")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fmscd%?\\t%P0, %P2, %P3"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "fmul")]
+)
+
+;; 0 = -(1 * 2) + 0
+(define_insn "*mulsf3negsfaddsf_vfp"
+ [(set (match_operand:SF 0 "s_register_operand" "=w")
+ (minus:SF (match_operand:SF 1 "s_register_operand" "0")
+ (mult:SF (match_operand:SF 2 "s_register_operand" "w")
+ (match_operand:SF 3 "s_register_operand" "w"))))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fnmacs%?\\t%0, %2, %3"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "farith")]
+)
+
+(define_insn "*fmuldf3negdfadddf_vfp"
+ [(set (match_operand:DF 0 "s_register_operand" "=w")
+ (minus:DF (match_operand:DF 1 "s_register_operand" "0")
+ (mult:DF (match_operand:DF 2 "s_register_operand" "w")
+ (match_operand:DF 3 "s_register_operand" "w"))))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fnmacd%?\\t%P0, %P2, %P3"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "fmul")]
+)
+
+
+;; 0 = -(1 * 2) - 0
+(define_insn "*mulsf3negsfsubsf_vfp"
+ [(set (match_operand:SF 0 "s_register_operand" "=w")
+ (minus:SF (mult:SF
+ (neg:SF (match_operand:SF 2 "s_register_operand" "w"))
+ (match_operand:SF 3 "s_register_operand" "w"))
+ (match_operand:SF 1 "s_register_operand" "0")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fnmscs%?\\t%0, %2, %3"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "farith")]
+)
+
+(define_insn "*muldf3negdfsubdf_vfp"
+ [(set (match_operand:DF 0 "s_register_operand" "=w")
+ (minus:DF (mult:DF
+ (neg:DF (match_operand:DF 2 "s_register_operand" "w"))
+ (match_operand:DF 3 "s_register_operand" "w"))
+ (match_operand:DF 1 "s_register_operand" "0")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fnmscd%?\\t%P0, %P2, %P3"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "fmul")]
+)
+
+
+;; Conversion routines
+
+(define_insn "*extendsfdf2_vfp"
+ [(set (match_operand:DF 0 "s_register_operand" "=w")
+ (float_extend:DF (match_operand:SF 1 "s_register_operand" "w")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fcvtds%?\\t%P0, %1"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "f_cvt")]
+)
+
+(define_insn "*truncdfsf2_vfp"
+ [(set (match_operand:SF 0 "s_register_operand" "=w")
+ (float_truncate:SF (match_operand:DF 1 "s_register_operand" "w")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fcvtsd%?\\t%0, %P1"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "f_cvt")]
+)
+
+(define_insn "*truncsisf2_vfp"
+ [(set (match_operand:SI 0 "s_register_operand" "=w")
+ (fix:SI (fix:SF (match_operand:SF 1 "s_register_operand" "w"))))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "ftosizs%?\\t%0, %1"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "f_cvt")]
+)
+
+(define_insn "*truncsidf2_vfp"
+ [(set (match_operand:SI 0 "s_register_operand" "=w")
+ (fix:SI (fix:DF (match_operand:DF 1 "s_register_operand" "w"))))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "ftosizd%?\\t%0, %P1"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "f_cvt")]
+)
+
+
+(define_insn "fixuns_truncsfsi2"
+ [(set (match_operand:SI 0 "s_register_operand" "=w")
+ (unsigned_fix:SI (fix:SF (match_operand:SF 1 "s_register_operand" "w"))))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "ftouizs%?\\t%0, %1"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "f_cvt")]
+)
+
+(define_insn "fixuns_truncdfsi2"
+ [(set (match_operand:SI 0 "s_register_operand" "=w")
+ (unsigned_fix:SI (fix:DF (match_operand:DF 1 "s_register_operand" "w"))))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "ftouizd%?\\t%0, %P1"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "f_cvt")]
+)
+
+
+(define_insn "*floatsisf2_vfp"
+ [(set (match_operand:SF 0 "s_register_operand" "=w")
+ (float:SF (match_operand:SI 1 "s_register_operand" "w")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fsitos%?\\t%0, %1"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "f_cvt")]
+)
+
+(define_insn "*floatsidf2_vfp"
+ [(set (match_operand:DF 0 "s_register_operand" "=w")
+ (float:DF (match_operand:SI 1 "s_register_operand" "w")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fsitod%?\\t%P0, %1"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "f_cvt")]
+)
+
+
+(define_insn "floatunssisf2"
+ [(set (match_operand:SF 0 "s_register_operand" "=w")
+ (unsigned_float:SF (match_operand:SI 1 "s_register_operand" "w")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fuitos%?\\t%0, %1"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "f_cvt")]
+)
+
+(define_insn "floatunssidf2"
+ [(set (match_operand:DF 0 "s_register_operand" "=w")
+ (unsigned_float:DF (match_operand:SI 1 "s_register_operand" "w")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fuitod%?\\t%P0, %1"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "f_cvt")]
+)
+
+
+;; Sqrt insns.
+
+(define_insn "*sqrtsf2_vfp"
+ [(set (match_operand:SF 0 "s_register_operand" "=w")
+ (sqrt:SF (match_operand:SF 1 "s_register_operand" "w")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fsqrts%?\\t%0, %1"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "fdivs")]
+)
+
+(define_insn "*sqrtdf2_vfp"
+ [(set (match_operand:DF 0 "s_register_operand" "=w")
+ (sqrt:DF (match_operand:DF 1 "s_register_operand" "w")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fsqrtd%?\\t%P0, %P1"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "fdivd")]
+)
+
+
+;; Patterns to split/copy vfp condition flags.
+
+(define_insn "*movcc_vfp"
+ [(set (reg CC_REGNUM)
+ (reg VFPCC_REGNUM))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "fmstat%?"
+ [(set_attr "conds" "set")
+ (set_attr "type" "f_flag")]
+)
+
+(define_insn_and_split "*cmpsf_split_vfp"
+ [(set (reg:CCFP CC_REGNUM)
+ (compare:CCFP (match_operand:SF 0 "s_register_operand" "w")
+ (match_operand:SF 1 "vfp_compare_operand" "wG")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "#"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ [(set (reg:CCFP VFPCC_REGNUM)
+ (compare:CCFP (match_dup 0)
+ (match_dup 1)))
+ (set (reg:CCFP CC_REGNUM)
+ (reg:CCFP VFPCC_REGNUM))]
+ ""
+)
+
+(define_insn_and_split "*cmpsf_trap_split_vfp"
+ [(set (reg:CCFPE CC_REGNUM)
+ (compare:CCFPE (match_operand:SF 0 "s_register_operand" "w")
+ (match_operand:SF 1 "vfp_compare_operand" "wG")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "#"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ [(set (reg:CCFPE VFPCC_REGNUM)
+ (compare:CCFPE (match_dup 0)
+ (match_dup 1)))
+ (set (reg:CCFPE CC_REGNUM)
+ (reg:CCFPE VFPCC_REGNUM))]
+ ""
+)
+
+(define_insn_and_split "*cmpdf_split_vfp"
+ [(set (reg:CCFP CC_REGNUM)
+ (compare:CCFP (match_operand:DF 0 "s_register_operand" "w")
+ (match_operand:DF 1 "vfp_compare_operand" "wG")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "#"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ [(set (reg:CCFP VFPCC_REGNUM)
+ (compare:CCFP (match_dup 0)
+ (match_dup 1)))
+ (set (reg:CCFP CC_REGNUM)
+ (reg:CCFPE VFPCC_REGNUM))]
+ ""
+)
+
+(define_insn_and_split "*cmpdf_trap_split_vfp"
+ [(set (reg:CCFPE CC_REGNUM)
+ (compare:CCFPE (match_operand:DF 0 "s_register_operand" "w")
+ (match_operand:DF 1 "vfp_compare_operand" "wG")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "#"
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ [(set (reg:CCFPE VFPCC_REGNUM)
+ (compare:CCFPE (match_dup 0)
+ (match_dup 1)))
+ (set (reg:CCFPE CC_REGNUM)
+ (reg:CCFPE VFPCC_REGNUM))]
+ ""
+)
+
+
+;; Comparison patterns
+
+(define_insn "*cmpsf_vfp"
+ [(set (reg:CCFP VFPCC_REGNUM)
+ (compare:CCFP (match_operand:SF 0 "s_register_operand" "w,w")
+ (match_operand:SF 1 "vfp_compare_operand" "w,G")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "@
+ fcmps%?\\t%0, %1
+ fcmpzs%?\\t%0"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "ffarith")]
+)
+
+(define_insn "*cmpsf_trap_vfp"
+ [(set (reg:CCFPE VFPCC_REGNUM)
+ (compare:CCFPE (match_operand:SF 0 "s_register_operand" "w,w")
+ (match_operand:SF 1 "vfp_compare_operand" "w,G")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "@
+ fcmpes%?\\t%0, %1
+ fcmpezs%?\\t%0"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "ffarith")]
+)
+
+(define_insn "*cmpdf_vfp"
+ [(set (reg:CCFP VFPCC_REGNUM)
+ (compare:CCFP (match_operand:DF 0 "s_register_operand" "w,w")
+ (match_operand:DF 1 "vfp_compare_operand" "w,G")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "@
+ fcmpd%?\\t%P0, %P1
+ fcmpzd%?\\t%P0"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "ffarith")]
+)
+
+(define_insn "*cmpdf_trap_vfp"
+ [(set (reg:CCFPE VFPCC_REGNUM)
+ (compare:CCFPE (match_operand:DF 0 "s_register_operand" "w,w")
+ (match_operand:DF 1 "vfp_compare_operand" "w,G")))]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "@
+ fcmped%?\\t%P0, %P1
+ fcmpezd%?\\t%P0"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "ffarith")]
+)
+
+
+;; Store multiple insn used in function prologue.
+
+(define_insn "*push_multi_vfp"
+ [(match_parallel 2 "multi_register_push"
+ [(set (match_operand:BLK 0 "memory_operand" "=m")
+ (unspec:BLK [(match_operand:DF 1 "s_register_operand" "w")]
+ UNSPEC_PUSH_MULT))])]
+ "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+ "* return vfp_output_fstmx (operands);"
+ [(set_attr "type" "f_stored")]
+)
+
+
+;; Unimplemented insns:
+;; fldm*
+;; fstm*
+;; fmdhr et al (VFPv1)
+;; Support for xD (single precision only) variants.
+;; fmrrs, fmsrr
diff --git a/contrib/gcc/config/arm/vxworks.h b/contrib/gcc/config/arm/vxworks.h
index afe6b70..319c1e8 100644
--- a/contrib/gcc/config/arm/vxworks.h
+++ b/contrib/gcc/config/arm/vxworks.h
@@ -1,6 +1,6 @@
/* Definitions of target machine for GCC,
for ARM with targetting the VXWorks run time environment.
- Copyright (C) 1999, 2000, 2003 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2000, 2003, 2004 Free Software Foundation, Inc.
Contributed by: Mike Stump <mrs@wrs.com>
Brought up to date by CodeSourcery, LLC.
@@ -19,8 +19,8 @@ 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#define TARGET_OS_CPP_BUILTINS() \
@@ -46,16 +46,16 @@ Boston, MA 02111-1307, USA. */
#undef CC1_SPEC
#define CC1_SPEC \
-"%{t4: -mapcs-32 -mlittle-endian -march=armv4 ; \
- t4be: -mapcs-32 -mbig-endian -march=armv4 ; \
+"%{t4: -mlittle-endian -march=armv4 ; \
+ t4be: -mbig-endian -march=armv4 ; \
t4t: -mthumb -mthumb-interwork -mlittle-endian -march=armv4t ; \
t4tbe: -mthumb -mthumb-interwork -mbig-endian -march=armv4t ; \
- t5: -mapcs-32 -mlittle-endian -march=armv5 ; \
- t5be: -mapcs-32 -mbig-endian -march=armv5 ; \
+ t5: -mlittle-endian -march=armv5 ; \
+ t5be: -mbig-endian -march=armv5 ; \
t5t: -mthumb -mthumb-interwork -mlittle-endian -march=armv5 ; \
t5tbe: -mthumb -mthumb-interwork -mbig-endian -march=armv5 ; \
- txscale: -mapcs-32 -mlittle-endian -mcpu=xscale ; \
- txscalebe: -mapcs-32 -mbig-endian -mcpu=xscale ; \
+ txscale: -mlittle-endian -mcpu=xscale ; \
+ txscalebe: -mbig-endian -mcpu=xscale ; \
: -march=armv4}"
/* The -Q options from svr4.h aren't understood and must be removed. */
diff --git a/contrib/gcc/config/arm/wince-pe.h b/contrib/gcc/config/arm/wince-pe.h
index fb47485..530340f 100644
--- a/contrib/gcc/config/arm/wince-pe.h
+++ b/contrib/gcc/config/arm/wince-pe.h
@@ -1,5 +1,5 @@
/* Definitions of target machine for GNU compiler, for ARM with WINCE-PE obj format.
- Copyright (C) 2003 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
Contributed by Nick Clifton <nickc@redhat.com>
This file is part of GCC.
@@ -16,14 +16,12 @@
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, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
-
-/* Override arm/pe.h's default apcs26 support. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#undef TARGET_DEFAULT
-#define TARGET_DEFAULT (ARM_FLAG_APCS_32 | ARM_FLAG_SOFT_FLOAT | TARGET_FLAG_NOP_FUN | ARM_FLAG_MMU_TRAPS)
+#define TARGET_DEFAULT (MASK_NOP_FUN_DLLIMPORT)
#undef MULTILIB_DEFAULTS
#define MULTILIB_DEFAULTS \
- { "marm", "mlittle-endian", "msoft-float", "mapcs-32", "mno-thumb-interwork" }
+ { "marm", "mlittle-endian", "msoft-float", "mno-thumb-interwork" }
diff --git a/contrib/gcc/config/arm/xscale-coff.h b/contrib/gcc/config/arm/xscale-coff.h
index d8fee7d..e275943 100644
--- a/contrib/gcc/config/arm/xscale-coff.h
+++ b/contrib/gcc/config/arm/xscale-coff.h
@@ -16,8 +16,8 @@
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
- MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301, USA. */
/* Run-time Target Specification. */
#undef SUBTARGET_CPU_DEFAULT
diff --git a/contrib/gcc/config/arm/xscale-elf.h b/contrib/gcc/config/arm/xscale-elf.h
index aea8360..be7be08 100644
--- a/contrib/gcc/config/arm/xscale-elf.h
+++ b/contrib/gcc/config/arm/xscale-elf.h
@@ -16,8 +16,8 @@
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* Run-time Target Specification. */
#ifndef TARGET_VERSION
OpenPOWER on IntegriCloud