diff options
author | Cary Coutant <ccoutant@google.com> | 2009-09-23 21:57:28 +0000 |
---|---|---|
committer | Cary Coutant <ccoutant@google.com> | 2009-09-23 21:57:28 +0000 |
commit | ebd9739bcfd2dc4c6409fb0b96d95894191b2c28 (patch) | |
tree | 64c4afc5e42d0dc9438e2d23f625cb3160e1e0a4 /gcc/config/bfin | |
parent | 0639e5c9f75c6391211dc74a4a47e9d83c88e8f4 (diff) |
Merged revs 144680:151949 from trunk
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/dwarf4@152102 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/bfin')
-rw-r--r-- | gcc/config/bfin/bfin-protos.h | 58 | ||||
-rw-r--r-- | gcc/config/bfin/bfin.c | 878 | ||||
-rw-r--r-- | gcc/config/bfin/bfin.h | 157 | ||||
-rw-r--r-- | gcc/config/bfin/bfin.md | 646 | ||||
-rw-r--r-- | gcc/config/bfin/crti.s | 20 | ||||
-rw-r--r-- | gcc/config/bfin/crtlibid.s | 20 | ||||
-rw-r--r-- | gcc/config/bfin/crtn.s | 20 | ||||
-rw-r--r-- | gcc/config/bfin/elf.h | 23 | ||||
-rw-r--r-- | gcc/config/bfin/lib1funcs.asm | 21 | ||||
-rw-r--r-- | gcc/config/bfin/libgcc-bfin.ver | 19 | ||||
-rw-r--r-- | gcc/config/bfin/linux-unwind.h | 24 | ||||
-rw-r--r-- | gcc/config/bfin/linux.h | 26 | ||||
-rw-r--r-- | gcc/config/bfin/predicates.md | 44 | ||||
-rw-r--r-- | gcc/config/bfin/sync.md | 178 | ||||
-rw-r--r-- | gcc/config/bfin/t-bfin | 18 | ||||
-rw-r--r-- | gcc/config/bfin/t-bfin-elf | 29 | ||||
-rw-r--r-- | gcc/config/bfin/t-bfin-linux | 29 | ||||
-rw-r--r-- | gcc/config/bfin/t-bfin-uclinux | 29 | ||||
-rw-r--r-- | gcc/config/bfin/uclinux.h | 26 |
19 files changed, 1437 insertions, 828 deletions
diff --git a/gcc/config/bfin/bfin-protos.h b/gcc/config/bfin/bfin-protos.h index 3e9ae4317c3..b2d3d8c2dbd 100644 --- a/gcc/config/bfin/bfin-protos.h +++ b/gcc/config/bfin/bfin-protos.h @@ -1,5 +1,5 @@ /* Prototypes for Blackfin functions used in the md file & elsewhere. - Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc. + Copyright (C) 2005, 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GNU CC. @@ -22,44 +22,6 @@ #ifndef GCC_BFIN_PROTOS_H #define GCC_BFIN_PROTOS_H -/* CPU type. */ -typedef enum bfin_cpu_type -{ - BFIN_CPU_UNKNOWN, - BFIN_CPU_BF512, - BFIN_CPU_BF514, - BFIN_CPU_BF516, - BFIN_CPU_BF518, - BFIN_CPU_BF522, - BFIN_CPU_BF523, - BFIN_CPU_BF524, - BFIN_CPU_BF525, - BFIN_CPU_BF526, - BFIN_CPU_BF527, - BFIN_CPU_BF531, - BFIN_CPU_BF532, - BFIN_CPU_BF533, - BFIN_CPU_BF534, - BFIN_CPU_BF536, - BFIN_CPU_BF537, - BFIN_CPU_BF538, - BFIN_CPU_BF539, - BFIN_CPU_BF542, - BFIN_CPU_BF544, - BFIN_CPU_BF547, - BFIN_CPU_BF548, - BFIN_CPU_BF549, - BFIN_CPU_BF561 -} bfin_cpu_t; - -/* Value of -mcpu= */ -extern bfin_cpu_t bfin_cpu_type; - -/* Value of -msi-revision= */ -extern int bfin_si_revision; - -extern unsigned int bfin_workarounds; - /* For the anomaly 05-00-0245 */ #define WA_SPECULATIVE_LOADS 0x00000001 #define ENABLE_WA_SPECULATIVE_LOADS \ @@ -80,18 +42,27 @@ extern unsigned int bfin_workarounds; #define ENABLE_WA_INDIRECT_CALLS \ ((bfin_workarounds & WA_INDIRECT_CALLS) && !TARGET_ICPLB) -#define WA_05000257 0x00000040 +#define WA_05000257 0x00000010 #define ENABLE_WA_05000257 \ (bfin_workarounds & WA_05000257) -#define WA_05000283 0x00000010 +#define WA_05000283 0x00000020 #define ENABLE_WA_05000283 \ (bfin_workarounds & WA_05000283) -#define WA_05000315 0x00000020 +#define WA_05000315 0x00000040 #define ENABLE_WA_05000315 \ (bfin_workarounds & WA_05000315) +/* For the anomaly 05-00-0312 */ +#define WA_LOAD_LCREGS 0x00000080 +#define ENABLE_WA_LOAD_LCREGS \ + (bfin_workarounds & WA_LOAD_LCREGS) + +#define WA_05000074 0x00000100 +#define ENABLE_WA_05000074 \ + (bfin_workarounds & WA_05000074) + #define Mmode enum machine_mode extern rtx function_arg (CUMULATIVE_ARGS *, Mmode, tree, int); @@ -104,11 +75,9 @@ extern char *bfin_asm_long (void); extern char *bfin_asm_short (void); extern int log2constp (unsigned HOST_WIDE_INT); -extern rtx legitimize_address (rtx, rtx, Mmode); extern bool bfin_legitimate_constant_p (rtx); extern int hard_regno_mode_ok (int, Mmode); extern void init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx); -extern int bfin_frame_pointer_required (void); extern HOST_WIDE_INT bfin_initial_elimination_offset (int, int); extern int effective_address_32bit_p (rtx, Mmode); @@ -142,7 +111,6 @@ extern rtx bfin_gen_compare (rtx, Mmode); extern int bfin_local_alignment (tree, int); extern void initialize_trampoline (rtx, rtx, rtx); -extern bool bfin_legitimate_address_p (Mmode, rtx, int); extern rtx bfin_va_arg (tree, tree); extern void bfin_expand_prologue (void); diff --git a/gcc/config/bfin/bfin.c b/gcc/config/bfin/bfin.c index f4f9d45e321..92aaf5770c4 100644 --- a/gcc/config/bfin/bfin.c +++ b/gcc/config/bfin/bfin.c @@ -58,19 +58,16 @@ /* A C structure for machine-specific, per-function data. This is added to the cfun structure. */ -struct machine_function GTY(()) +struct GTY(()) machine_function { /* Set if we are notified by the doloop pass that a hardware loop was created. */ int has_hardware_loops; + /* Set if we create a memcpy pattern that uses loop registers. */ int has_loopreg_clobber; }; -/* Test and compare insns in bfin.md store the information needed to - generate branch and scc insns here. */ -rtx bfin_compare_op0, bfin_compare_op1; - /* RTX for condition code flag register and RETS register */ extern GTY(()) rtx bfin_cc_rtx; extern GTY(()) rtx bfin_rets_rtx; @@ -85,6 +82,7 @@ const char *dregs_pair_names[] = DREGS_PAIR_NAMES; const char *byte_reg_names[] = BYTE_REGISTER_NAMES; static int arg_regs[] = FUNCTION_ARG_REGISTERS; +static int ret_regs[] = FUNCTION_RETURN_REGISTERS; /* Nonzero if -mshared-library-id was given. */ static int bfin_lib_id_given; @@ -119,188 +117,228 @@ struct bfin_cpu struct bfin_cpu bfin_cpus[] = { {"bf512", BFIN_CPU_BF512, 0x0000, - WA_SPECULATIVE_LOADS}, + WA_SPECULATIVE_LOADS | WA_05000074}, {"bf514", BFIN_CPU_BF514, 0x0000, - WA_SPECULATIVE_LOADS}, + WA_SPECULATIVE_LOADS | WA_05000074}, {"bf516", BFIN_CPU_BF516, 0x0000, - WA_SPECULATIVE_LOADS}, + WA_SPECULATIVE_LOADS | WA_05000074}, {"bf518", BFIN_CPU_BF518, 0x0000, - WA_SPECULATIVE_LOADS}, + WA_SPECULATIVE_LOADS | WA_05000074}, {"bf522", BFIN_CPU_BF522, 0x0002, - WA_SPECULATIVE_LOADS}, + WA_SPECULATIVE_LOADS | WA_05000074}, {"bf522", BFIN_CPU_BF522, 0x0001, - WA_SPECULATIVE_LOADS | WA_RETS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074}, {"bf522", BFIN_CPU_BF522, 0x0000, - WA_SPECULATIVE_LOADS | WA_RETS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074}, {"bf523", BFIN_CPU_BF523, 0x0002, - WA_SPECULATIVE_LOADS}, + WA_SPECULATIVE_LOADS | WA_05000074}, {"bf523", BFIN_CPU_BF523, 0x0001, - WA_SPECULATIVE_LOADS | WA_RETS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074}, {"bf523", BFIN_CPU_BF523, 0x0000, - WA_SPECULATIVE_LOADS | WA_RETS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074}, {"bf524", BFIN_CPU_BF524, 0x0002, - WA_SPECULATIVE_LOADS}, + WA_SPECULATIVE_LOADS | WA_05000074}, {"bf524", BFIN_CPU_BF524, 0x0001, - WA_SPECULATIVE_LOADS | WA_RETS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074}, {"bf524", BFIN_CPU_BF524, 0x0000, - WA_SPECULATIVE_LOADS | WA_RETS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074}, {"bf525", BFIN_CPU_BF525, 0x0002, - WA_SPECULATIVE_LOADS}, + WA_SPECULATIVE_LOADS | WA_05000074}, {"bf525", BFIN_CPU_BF525, 0x0001, - WA_SPECULATIVE_LOADS | WA_RETS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074}, {"bf525", BFIN_CPU_BF525, 0x0000, - WA_SPECULATIVE_LOADS | WA_RETS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074}, {"bf526", BFIN_CPU_BF526, 0x0002, - WA_SPECULATIVE_LOADS}, + WA_SPECULATIVE_LOADS | WA_05000074}, {"bf526", BFIN_CPU_BF526, 0x0001, - WA_SPECULATIVE_LOADS | WA_RETS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074}, {"bf526", BFIN_CPU_BF526, 0x0000, - WA_SPECULATIVE_LOADS | WA_RETS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074}, {"bf527", BFIN_CPU_BF527, 0x0002, - WA_SPECULATIVE_LOADS}, + WA_SPECULATIVE_LOADS | WA_05000074}, {"bf527", BFIN_CPU_BF527, 0x0001, - WA_SPECULATIVE_LOADS | WA_RETS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074}, {"bf527", BFIN_CPU_BF527, 0x0000, - WA_SPECULATIVE_LOADS | WA_RETS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074}, {"bf531", BFIN_CPU_BF531, 0x0006, - WA_SPECULATIVE_LOADS}, + WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS | WA_05000074}, {"bf531", BFIN_CPU_BF531, 0x0005, - WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315 + | WA_LOAD_LCREGS | WA_05000074}, {"bf531", BFIN_CPU_BF531, 0x0004, WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS - | WA_05000283 | WA_05000257 | WA_05000315}, + | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS + | WA_05000074}, {"bf531", BFIN_CPU_BF531, 0x0003, WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS - | WA_05000283 | WA_05000257 | WA_05000315}, + | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS + | WA_05000074}, {"bf532", BFIN_CPU_BF532, 0x0006, - WA_SPECULATIVE_LOADS}, + WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS | WA_05000074}, {"bf532", BFIN_CPU_BF532, 0x0005, - WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315 + | WA_LOAD_LCREGS | WA_05000074}, {"bf532", BFIN_CPU_BF532, 0x0004, WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS - | WA_05000283 | WA_05000257 | WA_05000315}, + | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS + | WA_05000074}, {"bf532", BFIN_CPU_BF532, 0x0003, WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS - | WA_05000283 | WA_05000257 | WA_05000315}, + | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS + | WA_05000074}, {"bf533", BFIN_CPU_BF533, 0x0006, - WA_SPECULATIVE_LOADS}, + WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS | WA_05000074}, {"bf533", BFIN_CPU_BF533, 0x0005, - WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315 + | WA_LOAD_LCREGS | WA_05000074}, {"bf533", BFIN_CPU_BF533, 0x0004, WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS - | WA_05000283 | WA_05000257 | WA_05000315}, + | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS + | WA_05000074}, {"bf533", BFIN_CPU_BF533, 0x0003, WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS - | WA_05000283 | WA_05000257 | WA_05000315}, + | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS + | WA_05000074}, {"bf534", BFIN_CPU_BF534, 0x0003, - WA_SPECULATIVE_LOADS | WA_RETS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS | WA_05000074}, {"bf534", BFIN_CPU_BF534, 0x0002, WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS - | WA_05000283 | WA_05000257 | WA_05000315}, + | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS + | WA_05000074}, {"bf534", BFIN_CPU_BF534, 0x0001, WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS - | WA_05000283 | WA_05000257 | WA_05000315}, + | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS + | WA_05000074}, {"bf536", BFIN_CPU_BF536, 0x0003, - WA_SPECULATIVE_LOADS | WA_RETS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS | WA_05000074}, {"bf536", BFIN_CPU_BF536, 0x0002, WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS - | WA_05000283 | WA_05000257 | WA_05000315}, + | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS + | WA_05000074}, {"bf536", BFIN_CPU_BF536, 0x0001, WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS - | WA_05000283 | WA_05000257 | WA_05000315}, + | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS + | WA_05000074}, {"bf537", BFIN_CPU_BF537, 0x0003, - WA_SPECULATIVE_LOADS | WA_RETS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS | WA_05000074}, {"bf537", BFIN_CPU_BF537, 0x0002, WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS - | WA_05000283 | WA_05000257 | WA_05000315}, + | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS + | WA_05000074}, {"bf537", BFIN_CPU_BF537, 0x0001, WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS - | WA_05000283 | WA_05000257 | WA_05000315}, + | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS + | WA_05000074}, {"bf538", BFIN_CPU_BF538, 0x0005, - WA_SPECULATIVE_LOADS}, + WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS | WA_05000074}, {"bf538", BFIN_CPU_BF538, 0x0004, - WA_SPECULATIVE_LOADS | WA_RETS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS | WA_05000074}, {"bf538", BFIN_CPU_BF538, 0x0003, WA_SPECULATIVE_LOADS | WA_RETS - | WA_05000283 | WA_05000315}, + | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS | WA_05000074}, {"bf538", BFIN_CPU_BF538, 0x0002, - WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000257 | WA_05000315}, + WA_SPECULATIVE_LOADS | WA_RETS + | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS + | WA_05000074}, {"bf539", BFIN_CPU_BF539, 0x0005, - WA_SPECULATIVE_LOADS}, + WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS | WA_05000074}, {"bf539", BFIN_CPU_BF539, 0x0004, - WA_SPECULATIVE_LOADS | WA_RETS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS | WA_05000074}, {"bf539", BFIN_CPU_BF539, 0x0003, WA_SPECULATIVE_LOADS | WA_RETS - | WA_05000283 | WA_05000315}, + | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS | WA_05000074}, {"bf539", BFIN_CPU_BF539, 0x0002, WA_SPECULATIVE_LOADS | WA_RETS - | WA_05000283 | WA_05000257 | WA_05000315}, + | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS + | WA_05000074}, + + {"bf542m", BFIN_CPU_BF542M, 0x0003, + WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074}, {"bf542", BFIN_CPU_BF542, 0x0002, - WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS}, + WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074}, {"bf542", BFIN_CPU_BF542, 0x0001, - WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_05000074}, {"bf542", BFIN_CPU_BF542, 0x0000, - WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS + | WA_05000074}, + + {"bf544m", BFIN_CPU_BF544M, 0x0003, + WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074}, {"bf544", BFIN_CPU_BF544, 0x0002, - WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS}, + WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074}, {"bf544", BFIN_CPU_BF544, 0x0001, - WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_05000074}, {"bf544", BFIN_CPU_BF544, 0x0000, - WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS + | WA_05000074}, + + {"bf547m", BFIN_CPU_BF547M, 0x0003, + WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074}, {"bf547", BFIN_CPU_BF547, 0x0002, - WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS}, + WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074}, {"bf547", BFIN_CPU_BF547, 0x0001, - WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_05000074}, {"bf547", BFIN_CPU_BF547, 0x0000, - WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS + | WA_05000074}, + + {"bf548m", BFIN_CPU_BF548M, 0x0003, + WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074}, {"bf548", BFIN_CPU_BF548, 0x0002, - WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS}, + WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074}, {"bf548", BFIN_CPU_BF548, 0x0001, - WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_05000074}, {"bf548", BFIN_CPU_BF548, 0x0000, - WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS + | WA_05000074}, + + {"bf549m", BFIN_CPU_BF549M, 0x0003, + WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074}, {"bf549", BFIN_CPU_BF549, 0x0002, - WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS}, + WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074}, {"bf549", BFIN_CPU_BF549, 0x0001, - WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_05000074}, {"bf549", BFIN_CPU_BF549, 0x0000, - WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS}, + WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS + | WA_05000074}, {"bf561", BFIN_CPU_BF561, 0x0005, WA_RETS - | WA_05000283 | WA_05000315}, + | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS | WA_05000074}, {"bf561", BFIN_CPU_BF561, 0x0003, WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS - | WA_05000283 | WA_05000257 | WA_05000315}, + | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS + | WA_05000074}, {"bf561", BFIN_CPU_BF561, 0x0002, WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS - | WA_05000283 | WA_05000257 | WA_05000315}, + | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS + | WA_05000074}, {NULL, 0, 0, 0} }; -int splitting_for_sched; +int splitting_for_sched, splitting_loops; static void bfin_globalize_label (FILE *stream, const char *name) @@ -535,7 +573,14 @@ n_pregs_to_save (bool is_inthandler, bool consecutive) static bool must_save_fp_p (void) { - return frame_pointer_needed || df_regs_ever_live_p (REG_FP); + return df_regs_ever_live_p (REG_FP); +} + +/* Determine if we are going to save the RETS register. */ +static bool +must_save_rets_p (void) +{ + return df_regs_ever_live_p (REG_RETS); } static bool @@ -815,20 +860,20 @@ setup_incoming_varargs (CUMULATIVE_ARGS *cum, Zero means the frame pointer need not be set up (and parms may be accessed via the stack pointer) in functions that seem suitable. */ -int +static bool bfin_frame_pointer_required (void) { e_funkind fkind = funkind (TREE_TYPE (current_function_decl)); if (fkind != SUBROUTINE) - return 1; + return true; /* We turn on -fomit-frame-pointer if -momit-leaf-frame-pointer is used, so we have to override it for non-leaf functions. */ if (TARGET_OMIT_LEAF_FRAME_POINTER && ! current_function_is_leaf) - return 1; + return true; - return 0; + return false; } /* Return the number of registers pushed during the prologue. */ @@ -847,13 +892,12 @@ n_regs_saved_by_prologue (void) int i; if (all || stack_frame_needed_p ()) - /* We use a LINK instruction in this case. */ n += 2; else { if (must_save_fp_p ()) n++; - if (! current_function_is_leaf) + if (must_save_rets_p ()) n++; } @@ -886,6 +930,17 @@ n_regs_saved_by_prologue (void) return n; } +/* Given FROM and TO register numbers, say whether this elimination is + allowed. Frame pointer elimination is automatically handled. + + All other eliminations are valid. */ + +static bool +bfin_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to) +{ + return (to == STACK_POINTER_REGNUM ? ! frame_pointer_needed : true); +} + /* Return the offset between two registers, one to be eliminated, and the other its replacement, at the start of a routine. */ @@ -1084,12 +1139,13 @@ do_link (rtx spreg, HOST_WIDE_INT frame_size, bool all) { frame_size += arg_area_size (); - if (all || stack_frame_needed_p () - || (must_save_fp_p () && ! current_function_is_leaf)) + if (all + || stack_frame_needed_p () + || (must_save_rets_p () && must_save_fp_p ())) emit_link_insn (spreg, frame_size); else { - if (! current_function_is_leaf) + if (must_save_rets_p ()) { rtx pat = gen_movsi (gen_rtx_MEM (Pmode, gen_rtx_PRE_DEC (Pmode, spreg)), @@ -1119,20 +1175,20 @@ do_unlink (rtx spreg, HOST_WIDE_INT frame_size, bool all, int epilogue_p) { frame_size += arg_area_size (); - if (all || stack_frame_needed_p ()) + if (stack_frame_needed_p ()) emit_insn (gen_unlink ()); else { rtx postinc = gen_rtx_MEM (Pmode, gen_rtx_POST_INC (Pmode, spreg)); add_to_reg (spreg, frame_size, 0, epilogue_p); - if (must_save_fp_p ()) + if (all || must_save_fp_p ()) { rtx fpreg = gen_rtx_REG (Pmode, REG_FP); emit_move_insn (fpreg, postinc); emit_use (fpreg); } - if (! current_function_is_leaf) + if (all || must_save_rets_p ()) { emit_move_insn (bfin_rets_rtx, postinc); emit_use (bfin_rets_rtx); @@ -1186,9 +1242,7 @@ expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind, bool all) if (lookup_attribute ("nesting", attrs)) { - rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX - : fkind == NMI_HANDLER ? REG_RETN - : REG_RETI)); + rtx srcreg = gen_rtx_REG (Pmode, ret_regs[fkind]); insn = emit_move_insn (predec, srcreg); RTX_FRAME_RELATED_P (insn) = 1; } @@ -1230,9 +1284,7 @@ expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind, bool all) if (lookup_attribute ("nesting", attrs)) { - rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX - : fkind == NMI_HANDLER ? REG_RETN - : REG_RETI)); + rtx srcreg = gen_rtx_REG (Pmode, ret_regs[fkind]); emit_move_insn (srcreg, postinc); } @@ -1248,7 +1300,7 @@ expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind, bool all) if (fkind == EXCPT_HANDLER) emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (12))); - emit_jump_insn (gen_return_internal (GEN_INT (fkind))); + emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, ret_regs[fkind]))); } /* Used while emitting the prologue to generate code to load the correct value @@ -1344,7 +1396,7 @@ bfin_expand_prologue (void) } expand_prologue_reg_save (spreg, all, false); - do_link (spreg, frame_size, false); + do_link (spreg, frame_size, all); if (TARGET_ID_SHARED_LIBRARY && !TARGET_SEP_DATA @@ -1373,7 +1425,7 @@ bfin_expand_epilogue (int need_return, int eh_return, bool sibcall_p) return; } - do_unlink (spreg, get_frame_size (), false, e); + do_unlink (spreg, get_frame_size (), all, e); expand_epilogue_reg_restore (spreg, all, false); @@ -1384,7 +1436,7 @@ bfin_expand_epilogue (int need_return, int eh_return, bool sibcall_p) if (eh_return) emit_insn (gen_addsi3 (spreg, spreg, gen_rtx_REG (Pmode, REG_P2))); - emit_jump_insn (gen_return_internal (GEN_INT (SUBROUTINE))); + emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, REG_RETS))); } /* Return nonzero if register OLD_REG can be renamed to register NEW_REG. */ @@ -1417,22 +1469,6 @@ bfin_return_addr_rtx (int count) return get_hard_reg_initial_val (Pmode, REG_RETS); } -/* Try machine-dependent ways of modifying an illegitimate address X - to be legitimate. If we find one, return the new, valid address, - otherwise return NULL_RTX. - - OLDX is the address as it was before break_out_memory_refs was called. - In some cases it is useful to look at this to decide what needs to be done. - - MODE is the mode of the memory reference. */ - -rtx -legitimize_address (rtx x ATTRIBUTE_UNUSED, rtx oldx ATTRIBUTE_UNUSED, - enum machine_mode mode ATTRIBUTE_UNUSED) -{ - return NULL_RTX; -} - static rtx bfin_delegitimize_address (rtx orig_x) { @@ -2183,6 +2219,8 @@ bool bfin_longcall_p (rtx op, int call_cookie) { gcc_assert (GET_CODE (op) == SYMBOL_REF); + if (SYMBOL_REF_WEAK (op)) + return 1; if (call_cookie & CALL_SHORT) return 0; if (call_cookie & CALL_LONG) @@ -2201,9 +2239,10 @@ bfin_expand_call (rtx retval, rtx fnaddr, rtx callarg1, rtx cookie, int sibcall) { rtx use = NULL, call; rtx callee = XEXP (fnaddr, 0); - int nelts = 2 + !!sibcall; + int nelts = 3; rtx pat; rtx picreg = get_hard_reg_initial_val (SImode, FDPIC_REGNO); + rtx retsreg = gen_rtx_REG (Pmode, REG_RETS); int n; /* In an untyped call, we can get NULL for operand 2. */ @@ -2218,28 +2257,38 @@ bfin_expand_call (rtx retval, rtx fnaddr, rtx callarg1, rtx cookie, int sibcall) if (TARGET_FDPIC) { - int caller_has_l1_text, callee_has_l1_text; + int caller_in_sram, callee_in_sram; - caller_has_l1_text = callee_has_l1_text = 0; + /* 0 is not in sram, 1 is in L1 sram, 2 is in L2 sram. */ + caller_in_sram = callee_in_sram = 0; if (lookup_attribute ("l1_text", DECL_ATTRIBUTES (cfun->decl)) != NULL_TREE) - caller_has_l1_text = 1; + caller_in_sram = 1; + else if (lookup_attribute ("l2", + DECL_ATTRIBUTES (cfun->decl)) != NULL_TREE) + caller_in_sram = 2; if (GET_CODE (callee) == SYMBOL_REF - && SYMBOL_REF_DECL (callee) && DECL_P (SYMBOL_REF_DECL (callee)) - && lookup_attribute - ("l1_text", - DECL_ATTRIBUTES (SYMBOL_REF_DECL (callee))) != NULL_TREE) - callee_has_l1_text = 1; + && SYMBOL_REF_DECL (callee) && DECL_P (SYMBOL_REF_DECL (callee))) + { + if (lookup_attribute + ("l1_text", + DECL_ATTRIBUTES (SYMBOL_REF_DECL (callee))) != NULL_TREE) + callee_in_sram = 1; + else if (lookup_attribute + ("l2", + DECL_ATTRIBUTES (SYMBOL_REF_DECL (callee))) != NULL_TREE) + callee_in_sram = 2; + } if (GET_CODE (callee) != SYMBOL_REF || bfin_longcall_p (callee, INTVAL (cookie)) || (GET_CODE (callee) == SYMBOL_REF && !SYMBOL_REF_LOCAL_P (callee) && TARGET_INLINE_PLT) - || caller_has_l1_text != callee_has_l1_text - || (caller_has_l1_text && callee_has_l1_text + || caller_in_sram != callee_in_sram + || (caller_in_sram && callee_in_sram && (GET_CODE (callee) != SYMBOL_REF || !SYMBOL_REF_LOCAL_P (callee)))) { @@ -2280,6 +2329,8 @@ bfin_expand_call (rtx retval, rtx fnaddr, rtx callarg1, rtx cookie, int sibcall) XVECEXP (pat, 0, n++) = gen_rtx_USE (VOIDmode, cookie); if (sibcall) XVECEXP (pat, 0, n++) = gen_rtx_RETURN (VOIDmode); + else + XVECEXP (pat, 0, n++) = gen_rtx_CLOBBER (VOIDmode, retsreg); call = emit_call_insn (pat); if (use) CALL_INSN_FUNCTION_USAGE (call) = use; @@ -2331,20 +2382,14 @@ bfin_register_move_cost (enum machine_mode mode, enum reg_class class1, enum reg_class class2) { /* These need secondary reloads, so they're more expensive. */ - if ((class1 == CCREGS && class2 != DREGS) - || (class1 != DREGS && class2 == CCREGS)) + if ((class1 == CCREGS && !reg_class_subset_p (class2, DREGS)) + || (class2 == CCREGS && !reg_class_subset_p (class1, DREGS))) return 4; /* If optimizing for size, always prefer reg-reg over reg-memory moves. */ if (optimize_size) return 2; - /* There are some stalls involved when moving from a DREG to a different - class reg, and using the value in one of the following instructions. - Attempt to model this by slightly discouraging such moves. */ - if (class1 == DREGS && class2 != DREGS) - return 2 * 2; - if (GET_MODE_CLASS (mode) == MODE_INT) { /* Discourage trying to use the accumulators. */ @@ -2735,7 +2780,7 @@ rtx bfin_gen_compare (rtx cmp, enum machine_mode mode ATTRIBUTE_UNUSED) { enum rtx_code code1, code2; - rtx op0 = bfin_compare_op0, op1 = bfin_compare_op1; + rtx op0 = XEXP (cmp, 0), op1 = XEXP (cmp, 1); rtx tem = bfin_cc_rtx; enum rtx_code code = GET_CODE (cmp); @@ -2763,7 +2808,7 @@ bfin_gen_compare (rtx cmp, enum machine_mode mode ATTRIBUTE_UNUSED) code2 = EQ; break; } - emit_insn (gen_rtx_SET (BImode, tem, + emit_insn (gen_rtx_SET (VOIDmode, tem, gen_rtx_fmt_ee (code1, BImode, op0, op1))); } @@ -2920,8 +2965,26 @@ bfin_valid_reg_p (unsigned int regno, int strict, enum machine_mode mode, return REGNO_OK_FOR_BASE_NONSTRICT_P (regno, mode, outer_code, SCRATCH); } -bool -bfin_legitimate_address_p (enum machine_mode mode, rtx x, int strict) +/* Recognize 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. + + Blackfin addressing modes are as follows: + + [preg] + [preg + imm16] + + B [ Preg + uimm15 ] + W [ Preg + uimm16m2 ] + [ Preg + uimm17m4 ] + + [preg++] + [preg--] + [--sp] +*/ + +static bool +bfin_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) { switch (GET_CODE (x)) { case REG: @@ -3610,7 +3673,7 @@ DEF_VEC_ALLOC_P (loop_info,heap); /* Information about a loop we have found (or are in the process of finding). */ -struct loop_info GTY (()) +struct GTY (()) loop_info { /* loop number, for dumps */ int loop_no; @@ -3646,12 +3709,6 @@ struct loop_info GTY (()) /* The iteration register. */ rtx iter_reg; - /* The new initialization insn. */ - rtx init; - - /* The new initialization instruction. */ - rtx loop_init; - /* The new label placed at the beginning of the loop. */ rtx start_label; @@ -3779,7 +3836,7 @@ length_for_loop (rtx insn) length = 4; } - if (INSN_P (insn)) + if (NONDEBUG_INSN_P (insn)) length += get_attr_length (insn); return length; @@ -3792,10 +3849,10 @@ bfin_optimize_loop (loop_info loop) { basic_block bb; loop_info inner; - rtx insn, init_insn, last_insn, nop_insn; + rtx insn, last_insn; rtx loop_init, start_label, end_label; rtx reg_lc0, reg_lc1, reg_lt0, reg_lt1, reg_lb0, reg_lb1; - rtx iter_reg; + rtx iter_reg, scratchreg, scratch_init, scratch_init_insn; rtx lc_reg, lt_reg, lb_reg; rtx seq, seq_end; int length; @@ -3841,24 +3898,68 @@ bfin_optimize_loop (loop_info loop) /* Get the loop iteration register. */ iter_reg = loop->iter_reg; - if (!DPREG_P (iter_reg)) + if (!REG_P (iter_reg)) { if (dump_file) - fprintf (dump_file, ";; loop %d iteration count NOT in PREG or DREG\n", + fprintf (dump_file, ";; loop %d iteration count not in a register\n", loop->loop_no); goto bad_loop; } + scratchreg = NULL_RTX; + scratch_init = iter_reg; + scratch_init_insn = NULL_RTX; + if (!PREG_P (iter_reg) && loop->incoming_src) + { + basic_block bb_in = loop->incoming_src; + int i; + for (i = REG_P0; i <= REG_P5; i++) + if ((df_regs_ever_live_p (i) + || (funkind (TREE_TYPE (current_function_decl)) == SUBROUTINE + && call_used_regs[i])) + && !REGNO_REG_SET_P (df_get_live_out (bb_in), i)) + { + scratchreg = gen_rtx_REG (SImode, i); + break; + } + for (insn = BB_END (bb_in); insn != BB_HEAD (bb_in); + insn = PREV_INSN (insn)) + { + rtx set; + if (NOTE_P (insn) || BARRIER_P (insn)) + continue; + set = single_set (insn); + if (set && rtx_equal_p (SET_DEST (set), iter_reg)) + { + if (CONSTANT_P (SET_SRC (set))) + { + scratch_init = SET_SRC (set); + scratch_init_insn = insn; + } + break; + } + else if (reg_mentioned_p (iter_reg, PATTERN (insn))) + break; + } + } if (loop->incoming_src) { /* Make sure the predecessor is before the loop start label, as required by the LSETUP instruction. */ length = 0; - for (insn = BB_END (loop->incoming_src); - insn && insn != loop->start_label; - insn = NEXT_INSN (insn)) + insn = BB_END (loop->incoming_src); + /* If we have to insert the LSETUP before a jump, count that jump in the + length. */ + if (VEC_length (edge, loop->incoming) > 1 + || !(VEC_last (edge, loop->incoming)->flags & EDGE_FALLTHRU)) + { + gcc_assert (JUMP_P (insn)); + insn = PREV_INSN (insn); + } + + for (; insn && insn != loop->start_label; insn = NEXT_INSN (insn)) length += length_for_loop (insn); - + if (!insn) { if (dump_file) @@ -3867,6 +3968,11 @@ bfin_optimize_loop (loop_info loop) goto bad_loop; } + /* Account for the pop of a scratch register where necessary. */ + if (!PREG_P (iter_reg) && scratchreg == NULL_RTX + && ENABLE_WA_LOAD_LCREGS) + length += 2; + if (length > MAX_LSETUP_DISTANCE) { if (dump_file) @@ -3967,13 +4073,14 @@ bfin_optimize_loop (loop_info loop) { for (; last_insn != BB_HEAD (bb); last_insn = find_prev_insn_start (last_insn)) - if (INSN_P (last_insn)) + if (NONDEBUG_INSN_P (last_insn)) break; if (last_insn != BB_HEAD (bb)) break; if (single_pred_p (bb) + && single_pred_edge (bb)->flags & EDGE_FALLTHRU && single_pred (bb) != ENTRY_BLOCK_PTR) { bb = single_pred (bb); @@ -3995,42 +4102,34 @@ bfin_optimize_loop (loop_info loop) goto bad_loop; } - if (JUMP_P (last_insn)) + if (JUMP_P (last_insn) && !any_condjump_p (last_insn)) { - loop_info inner = (loop_info) bb->aux; - if (inner - && inner->outer == loop - && inner->loop_end == last_insn - && inner->depth == 1) - /* This jump_insn is the exact loop_end of an inner loop - and to be optimized away. So use the inner's last_insn. */ - last_insn = inner->last_insn; - else + if (dump_file) + fprintf (dump_file, ";; loop %d has bad last instruction\n", + loop->loop_no); + goto bad_loop; + } + /* In all other cases, try to replace a bad last insn with a nop. */ + else if (JUMP_P (last_insn) + || CALL_P (last_insn) + || get_attr_type (last_insn) == TYPE_SYNC + || get_attr_type (last_insn) == TYPE_CALL + || get_attr_seq_insns (last_insn) == SEQ_INSNS_MULTI + || recog_memoized (last_insn) == CODE_FOR_return_internal + || GET_CODE (PATTERN (last_insn)) == ASM_INPUT + || asm_noperands (PATTERN (last_insn)) >= 0) + { + if (loop->length + 2 > MAX_LOOP_LENGTH) { if (dump_file) - fprintf (dump_file, ";; loop %d has bad last instruction\n", - loop->loop_no); + fprintf (dump_file, ";; loop %d too long\n", loop->loop_no); goto bad_loop; } - } - else if (CALL_P (last_insn) - || (GET_CODE (PATTERN (last_insn)) != SEQUENCE - && get_attr_type (last_insn) == TYPE_SYNC) - || recog_memoized (last_insn) == CODE_FOR_return_internal) - { if (dump_file) - fprintf (dump_file, ";; loop %d has bad last instruction\n", + fprintf (dump_file, ";; loop %d has bad last insn; replace with nop\n", loop->loop_no); - goto bad_loop; - } - if (GET_CODE (PATTERN (last_insn)) == ASM_INPUT - || asm_noperands (PATTERN (last_insn)) >= 0 - || (GET_CODE (PATTERN (last_insn)) != SEQUENCE - && get_attr_seq_insns (last_insn) == SEQ_INSNS_MULTI)) - { - nop_insn = emit_insn_after (gen_nop (), last_insn); - last_insn = nop_insn; + last_insn = emit_insn_after (gen_forced_nop (), last_insn); } loop->last_insn = last_insn; @@ -4055,46 +4154,71 @@ bfin_optimize_loop (loop_info loop) loop->clobber_loop0 = 1; } - /* If iter_reg is a DREG, we need generate an instruction to load - the loop count into LC register. */ - if (D_REGNO_P (REGNO (iter_reg))) + loop->end_label = end_label; + + /* Create a sequence containing the loop setup. */ + start_sequence (); + + /* LSETUP only accepts P registers. If we have one, we can use it, + otherwise there are several ways of working around the problem. + If we're not affected by anomaly 312, we can load the LC register + from any iteration register, and use LSETUP without initialization. + If we've found a P scratch register that's not live here, we can + instead copy the iter_reg into that and use an initializing LSETUP. + If all else fails, push and pop P0 and use it as a scratch. */ + if (P_REGNO_P (REGNO (iter_reg))) { - init_insn = gen_movsi (lc_reg, iter_reg); + loop_init = gen_lsetup_with_autoinit (lt_reg, start_label, + lb_reg, end_label, + lc_reg, iter_reg); + seq_end = emit_insn (loop_init); + } + else if (!ENABLE_WA_LOAD_LCREGS && DPREG_P (iter_reg)) + { + emit_insn (gen_movsi (lc_reg, iter_reg)); loop_init = gen_lsetup_without_autoinit (lt_reg, start_label, lb_reg, end_label, lc_reg); + seq_end = emit_insn (loop_init); } - else if (P_REGNO_P (REGNO (iter_reg))) + else if (scratchreg != NULL_RTX) { - init_insn = NULL_RTX; + emit_insn (gen_movsi (scratchreg, scratch_init)); loop_init = gen_lsetup_with_autoinit (lt_reg, start_label, lb_reg, end_label, - lc_reg, iter_reg); + lc_reg, scratchreg); + seq_end = emit_insn (loop_init); + if (scratch_init_insn != NULL_RTX) + delete_insn (scratch_init_insn); } else - gcc_unreachable (); - - loop->init = init_insn; - loop->end_label = end_label; - loop->loop_init = loop_init; + { + rtx p0reg = gen_rtx_REG (SImode, REG_P0); + rtx push = gen_frame_mem (SImode, + gen_rtx_PRE_DEC (SImode, stack_pointer_rtx)); + rtx pop = gen_frame_mem (SImode, + gen_rtx_POST_INC (SImode, stack_pointer_rtx)); + emit_insn (gen_movsi (push, p0reg)); + emit_insn (gen_movsi (p0reg, scratch_init)); + loop_init = gen_lsetup_with_autoinit (lt_reg, start_label, + lb_reg, end_label, + lc_reg, p0reg); + emit_insn (loop_init); + seq_end = emit_insn (gen_movsi (p0reg, pop)); + if (scratch_init_insn != NULL_RTX) + delete_insn (scratch_init_insn); + } if (dump_file) { fprintf (dump_file, ";; replacing loop %d initializer with\n", loop->loop_no); - print_rtl_single (dump_file, loop->loop_init); + print_rtl_single (dump_file, loop_init); fprintf (dump_file, ";; replacing loop %d terminator with\n", loop->loop_no); print_rtl_single (dump_file, loop->loop_end); } - /* Create a sequence containing the loop setup. */ - start_sequence (); - - if (loop->init != NULL_RTX) - emit_insn (loop->init); - seq_end = emit_insn (loop->loop_init); - /* If the loop isn't entered at the top, also create a jump to the entry point. */ if (!loop->incoming_src && loop->head != loop->incoming_dest) @@ -4112,7 +4236,10 @@ bfin_optimize_loop (loop_info loop) seq_end = emit_insn (copy_rtx (PATTERN (last_insn))); } else - seq_end = emit_insn (gen_jump (label)); + { + emit_jump_insn (gen_jump (label)); + seq_end = emit_barrier (); + } } seq = get_insns (); @@ -4160,8 +4287,9 @@ bfin_optimize_loop (loop_info loop) else redirect_edge_succ (e, new_bb); } + e = make_edge (new_bb, loop->head, 0); } - + delete_insn (loop->loop_end); /* Insert the loop end label before the last instruction of the loop. */ emit_label_before (loop->end_label, loop->last_insn); @@ -4179,17 +4307,17 @@ bfin_optimize_loop (loop_info loop) { /* If loop->iter_reg is a DREG or PREG, we can split it here without scratch register. */ - rtx insn; + rtx insn, test; emit_insn_before (gen_addsi3 (loop->iter_reg, loop->iter_reg, constm1_rtx), loop->loop_end); - emit_insn_before (gen_cmpsi (loop->iter_reg, const0_rtx), - loop->loop_end); - - insn = emit_jump_insn_before (gen_bne (loop->start_label), + test = gen_rtx_NE (VOIDmode, loop->iter_reg, const0_rtx); + insn = emit_jump_insn_before (gen_cbranchsi4 (test, + loop->iter_reg, const0_rtx, + loop->start_label), loop->loop_end); JUMP_LABEL (insn) = loop->start_label; @@ -4222,7 +4350,6 @@ bfin_discover_loop (loop_info loop, basic_block tail_bb, rtx tail_insn) loop->outer = NULL; loop->loops = NULL; loop->incoming = VEC_alloc (edge, gc, 2); - loop->init = loop->loop_init = NULL_RTX; loop->start_label = XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (tail_insn), 0, 0)), 1), 0); loop->end_label = NULL_RTX; loop->bad = 0; @@ -4596,7 +4723,7 @@ bfin_reorg_loops (FILE *dump_file) fprintf (dump_file, ";; All loops found:\n\n"); bfin_dump_loops (loops); } - + /* Now apply the optimizations. */ for (loop = loops; loop; loop = loop->next) bfin_optimize_loop (loop); @@ -4614,6 +4741,17 @@ bfin_reorg_loops (FILE *dump_file) FOR_EACH_BB (bb) bb->aux = NULL; + + splitting_loops = 1; + FOR_EACH_BB (bb) + { + rtx insn = BB_END (bb); + if (!JUMP_P (insn)) + continue; + + try_split (PATTERN (insn), insn, 1); + } + splitting_loops = 0; } /* Possibly generate a SEQUENCE out of three insns found in SLOT. @@ -4697,15 +4835,27 @@ bfin_gen_bundles (void) for (insn = BB_HEAD (bb);; insn = next) { int at_end; - if (INSN_P (insn)) + rtx delete_this = NULL_RTX; + + if (NONDEBUG_INSN_P (insn)) { - if (get_attr_type (insn) == TYPE_DSP32) - slot[0] = insn; - else if (slot[1] == NULL_RTX) - slot[1] = insn; + enum attr_type type = get_attr_type (insn); + + if (type == TYPE_STALL) + { + gcc_assert (n_filled == 0); + delete_this = insn; + } else - slot[2] = insn; - n_filled++; + { + if (type == TYPE_DSP32 || type == TYPE_DSP32SHIFTIMM) + slot[0] = insn; + else if (slot[1] == NULL_RTX) + slot[1] = insn; + else + slot[2] = insn; + n_filled++; + } } next = NEXT_INSN (insn); @@ -4720,7 +4870,7 @@ bfin_gen_bundles (void) /* BB_END can change due to emitting extra NOPs, so check here. */ at_end = insn == BB_END (bb); - if (at_end || GET_MODE (next) == TImode) + if (delete_this == NULL_RTX && (at_end || GET_MODE (next) == TImode)) { if ((n_filled < 2 || !gen_one_bundle (slot)) @@ -4739,6 +4889,8 @@ bfin_gen_bundles (void) n_filled = 0; slot[0] = slot[1] = slot[2] = NULL_RTX; } + if (delete_this != NULL_RTX) + delete_insn (delete_this); if (at_end) break; } @@ -4899,28 +5051,38 @@ type_for_anomaly (rtx insn) return get_attr_type (insn); } -/* Return nonzero if INSN contains any loads that may trap. It handles - SEQUENCEs correctly. */ - +/* Return true iff the address found in MEM is based on the register + NP_REG and optionally has a positive offset. */ static bool -trapping_loads_p (rtx insn) +harmless_null_pointer_p (rtx mem, int np_reg) { - rtx pat = PATTERN (insn); - if (GET_CODE (pat) == SEQUENCE) + mem = XEXP (mem, 0); + if (GET_CODE (mem) == POST_INC || GET_CODE (mem) == POST_DEC) + mem = XEXP (mem, 0); + if (REG_P (mem) && REGNO (mem) == np_reg) + return true; + if (GET_CODE (mem) == PLUS + && REG_P (XEXP (mem, 0)) && REGNO (XEXP (mem, 0)) == np_reg) { - enum attr_type t; - t = get_attr_type (XVECEXP (pat, 0, 1)); - if (t == TYPE_MCLD - && may_trap_p (SET_SRC (PATTERN (XVECEXP (pat, 0, 1))))) + mem = XEXP (mem, 1); + if (GET_CODE (mem) == CONST_INT && INTVAL (mem) > 0) return true; - t = get_attr_type (XVECEXP (pat, 0, 2)); - if (t == TYPE_MCLD - && may_trap_p (SET_SRC (PATTERN (XVECEXP (pat, 0, 2))))) - return true; - return false; } - else - return may_trap_p (SET_SRC (single_set (insn))); + return false; +} + +/* Return nonzero if INSN contains any loads that may trap. */ + +static bool +trapping_loads_p (rtx insn, int np_reg, bool after_np_branch) +{ + rtx pat = PATTERN (insn); + rtx mem = SET_SRC (single_set (insn)); + + if (!after_np_branch) + np_reg = -1; + return ((np_reg == -1 || !harmless_null_pointer_p (mem, np_reg)) + && may_trap_p (mem)); } /* Return INSN if it is of TYPE_MCLD. Alternatively, if INSN is the start of @@ -4929,6 +5091,8 @@ trapping_loads_p (rtx insn) static rtx find_load (rtx insn) { + if (!NONDEBUG_INSN_P (insn)) + return NULL_RTX; if (get_attr_type (insn) == TYPE_MCLD) return insn; if (GET_MODE (insn) != SImode) @@ -4958,6 +5122,24 @@ indirect_call_p (rtx pat) return REG_P (pat); } +/* During workaround_speculation, track whether we're in the shadow of a + conditional branch that tests a P register for NULL. If so, we can omit + emitting NOPs if we see a load from that P register, since a speculative + access at address 0 isn't a problem, and the load is executed in all other + cases anyway. + Global for communication with note_np_check_stores through note_stores. + */ +int np_check_regno = -1; +bool np_after_branch = false; + +/* Subroutine of workaround_speculation, called through note_stores. */ +static void +note_np_check_stores (rtx x, const_rtx pat, void *data ATTRIBUTE_UNUSED) +{ + if (REG_P (x) && (REGNO (x) == REG_CC || REGNO (x) == np_check_regno)) + np_check_regno = -1; +} + static void workaround_speculation (void) { @@ -4979,17 +5161,38 @@ workaround_speculation (void) next = find_next_insn_start (insn); - if (NOTE_P (insn) || BARRIER_P (insn) || LABEL_P (insn)) + if (NOTE_P (insn) || BARRIER_P (insn)) continue; + if (LABEL_P (insn)) + { + np_check_regno = -1; + continue; + } + pat = PATTERN (insn); if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER - || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC - || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0) + || GET_CODE (pat) == ADDR_VEC || GET_CODE (pat) == ADDR_DIFF_VEC) continue; + + if (GET_CODE (pat) == ASM_INPUT || asm_noperands (pat) >= 0) + { + np_check_regno = -1; + continue; + } if (JUMP_P (insn)) { + /* Is this a condjump based on a null pointer comparison we saw + earlier? */ + if (np_check_regno != -1 + && recog_memoized (insn) == CODE_FOR_cbranchbi4) + { + rtx op = XEXP (SET_SRC (PATTERN (insn)), 0); + gcc_assert (GET_CODE (op) == EQ || GET_CODE (op) == NE); + if (GET_CODE (op) == NE) + np_after_branch = true; + } if (any_condjump_p (insn) && ! cbranch_predicted_taken_p (insn)) { @@ -5002,6 +5205,7 @@ workaround_speculation (void) } else if (CALL_P (insn)) { + np_check_regno = -1; if (cycles_since_jump < INT_MAX) cycles_since_jump++; if (indirect_call_p (pat) && ENABLE_WA_INDIRECT_CALLS) @@ -5009,7 +5213,7 @@ workaround_speculation (void) delay_needed = 3; } } - else if (INSN_P (insn)) + else if (NONDEBUG_INSN_P (insn)) { rtx load_insn = find_load (insn); enum attr_type type = type_for_anomaly (insn); @@ -5017,13 +5221,44 @@ workaround_speculation (void) if (cycles_since_jump < INT_MAX) cycles_since_jump++; + /* Detect a comparison of a P register with zero. If we later + see a condjump based on it, we have found a null pointer + check. */ + if (recog_memoized (insn) == CODE_FOR_compare_eq) + { + rtx src = SET_SRC (PATTERN (insn)); + if (REG_P (XEXP (src, 0)) + && P_REGNO_P (REGNO (XEXP (src, 0))) + && XEXP (src, 1) == const0_rtx) + { + np_check_regno = REGNO (XEXP (src, 0)); + np_after_branch = false; + } + else + np_check_regno = -1; + } + if (load_insn && ENABLE_WA_SPECULATIVE_LOADS) { - if (trapping_loads_p (load_insn)) + if (trapping_loads_p (load_insn, np_check_regno, + np_after_branch)) delay_needed = 4; } else if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS) delay_needed = 3; + + /* See if we need to forget about a null pointer comparison + we found earlier. */ + if (recog_memoized (insn) != CODE_FOR_compare_eq) + { + note_stores (PATTERN (insn), note_np_check_stores, NULL); + if (np_check_regno != -1) + { + if (find_regno_note (insn, REG_INC, np_check_regno)) + np_check_regno = -1; + } + } + } if (delay_needed > cycles_since_jump @@ -5091,7 +5326,7 @@ workaround_speculation (void) || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0) continue; - if (INSN_P (target)) + if (NONDEBUG_INSN_P (target)) { rtx load_insn = find_load (target); enum attr_type type = type_for_anomaly (target); @@ -5101,7 +5336,7 @@ workaround_speculation (void) if (load_insn && ENABLE_WA_SPECULATIVE_LOADS) { - if (trapping_loads_p (load_insn)) + if (trapping_loads_p (load_insn, -1, false)) delay_needed = 2; } else if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS) @@ -5139,6 +5374,65 @@ workaround_speculation (void) } } +/* Called just before the final scheduling pass. If we need to insert NOPs + later on to work around speculative loads, insert special placeholder + insns that cause loads to be delayed for as many cycles as necessary + (and possible). This reduces the number of NOPs we need to add. + The dummy insns we generate are later removed by bfin_gen_bundles. */ +static void +add_sched_insns_for_speculation (void) +{ + rtx insn; + + if (! ENABLE_WA_SPECULATIVE_LOADS && ! ENABLE_WA_SPECULATIVE_SYNCS + && ! ENABLE_WA_INDIRECT_CALLS) + return; + + /* First pass: find predicted-false branches; if something after them + needs nops, insert them or change the branch to predict true. */ + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + rtx pat; + + if (NOTE_P (insn) || BARRIER_P (insn) || LABEL_P (insn)) + continue; + + pat = PATTERN (insn); + if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER + || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC + || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0) + continue; + + if (JUMP_P (insn)) + { + if (any_condjump_p (insn) + && !cbranch_predicted_taken_p (insn)) + { + rtx n = next_real_insn (insn); + emit_insn_before (gen_stall (GEN_INT (3)), n); + } + } + } + + /* Second pass: for predicted-true branches, see if anything at the + branch destination needs extra nops. */ + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + if (JUMP_P (insn) + && any_condjump_p (insn) + && (cbranch_predicted_taken_p (insn))) + { + rtx target = JUMP_LABEL (insn); + rtx next = next_real_insn (target); + + if (GET_CODE (PATTERN (next)) == UNSPEC_VOLATILE + && get_attr_type (next) == TYPE_STALL) + continue; + emit_insn_before (gen_stall (GEN_INT (1)), next); + } + } +} + /* We use the machine specific reorg pass for emitting CSYNC instructions after conditional branches as needed. @@ -5172,6 +5466,8 @@ bfin_reorg (void) split_all_insns (); splitting_for_sched = 0; + add_sched_insns_for_speculation (); + timevar_push (TV_SCHED2); schedule_insns (); timevar_pop (TV_SCHED2); @@ -5217,8 +5513,8 @@ handle_int_attribute (tree *node, tree name, if (TREE_CODE (x) != FUNCTION_TYPE) { - warning (OPT_Wattributes, "%qs attribute only applies to functions", - IDENTIFIER_POINTER (name)); + warning (OPT_Wattributes, "%qE attribute only applies to functions", + name); *no_add_attrs = true; } else if (funkind (x) != SUBROUTINE) @@ -5278,8 +5574,8 @@ bfin_handle_longcall_attribute (tree *node, tree name, && TREE_CODE (*node) != FIELD_DECL && TREE_CODE (*node) != TYPE_DECL) { - warning (OPT_Wattributes, "`%s' attribute only applies to functions", - IDENTIFIER_POINTER (name)); + warning (OPT_Wattributes, "%qE attribute only applies to functions", + name); *no_add_attrs = true; } @@ -5307,8 +5603,8 @@ bfin_handle_l1_text_attribute (tree *node, tree name, tree ARG_UNUSED (args), if (TREE_CODE (decl) != FUNCTION_DECL) { - error ("`%s' attribute only applies to functions", - IDENTIFIER_POINTER (name)); + error ("%qE attribute only applies to functions", + name); *no_add_attrs = true; } @@ -5339,15 +5635,15 @@ bfin_handle_l1_data_attribute (tree *node, tree name, tree ARG_UNUSED (args), if (TREE_CODE (decl) != VAR_DECL) { - error ("`%s' attribute only applies to variables", - IDENTIFIER_POINTER (name)); + error ("%qE attribute only applies to variables", + name); *no_add_attrs = true; } else if (current_function_decl != NULL_TREE && !TREE_STATIC (decl)) { - error ("`%s' attribute cannot be specified for local variables", - IDENTIFIER_POINTER (name)); + error ("%qE attribute cannot be specified for local variables", + name); *no_add_attrs = true; } else @@ -5381,8 +5677,47 @@ bfin_handle_l1_data_attribute (tree *node, tree name, tree ARG_UNUSED (args), return NULL_TREE; } +/* Handle a "l2" attribute; arguments as in struct attribute_spec.handler. */ + +static tree +bfin_handle_l2_attribute (tree *node, tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool *no_add_attrs) +{ + tree decl = *node; + + if (TREE_CODE (decl) == FUNCTION_DECL) + { + if (DECL_SECTION_NAME (decl) != NULL_TREE + && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)), + ".l2.text") != 0) + { + error ("section of %q+D conflicts with previous declaration", + decl); + *no_add_attrs = true; + } + else + DECL_SECTION_NAME (decl) = build_string (9, ".l2.text"); + } + else if (TREE_CODE (decl) == VAR_DECL) + { + if (DECL_SECTION_NAME (decl) != NULL_TREE + && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)), + ".l2.data") != 0) + { + error ("section of %q+D conflicts with previous declaration", + decl); + *no_add_attrs = true; + } + else + DECL_SECTION_NAME (decl) = build_string (9, ".l2.data"); + } + + return NULL_TREE; +} + /* Table of valid machine attributes. */ -const struct attribute_spec bfin_attribute_table[] = +static const struct attribute_spec bfin_attribute_table[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ { "interrupt_handler", 0, 0, false, true, true, handle_int_attribute }, @@ -5397,6 +5732,7 @@ const struct attribute_spec bfin_attribute_table[] = { "l1_data", 0, 0, true, false, false, bfin_handle_l1_data_attribute }, { "l1_data_A", 0, 0, true, false, false, bfin_handle_l1_data_attribute }, { "l1_data_B", 0, 0, true, false, false, bfin_handle_l1_data_attribute }, + { "l2", 0, 0, true, false, false, bfin_handle_l2_attribute }, { NULL, 0, 0, false, false, false, NULL } }; @@ -6008,6 +6344,10 @@ bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, if (! target || !register_operand (target, SImode)) target = gen_reg_rtx (SImode); + if (! register_operand (op0, SImode)) + op0 = copy_to_mode_reg (SImode, op0); + if (! register_operand (op1, SImode)) + op1 = copy_to_mode_reg (SImode, op1); a1reg = gen_rtx_REG (PDImode, REG_A1); a0reg = gen_rtx_REG (PDImode, REG_A0); @@ -6061,6 +6401,7 @@ bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); accvec = gen_reg_rtx (V2PDImode); + icode = CODE_FOR_flag_macv2hi_parts; if (! target || GET_MODE (target) != V2HImode @@ -6097,6 +6438,7 @@ bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0); accvec = gen_reg_rtx (V2PDImode); + icode = CODE_FOR_flag_macv2hi_parts; if (! target || GET_MODE (target) != V2HImode @@ -6161,15 +6503,14 @@ bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, emit_insn (gen_flag_mulv2hi (tmp1, op0, op0, GEN_INT (MACFLAG_NONE))); - emit_insn (gen_flag_mulhi_parts (tmp2, op0, op0, const0_rtx, + emit_insn (gen_flag_mulhi_parts (gen_lowpart (HImode, tmp2), op0, op0, const0_rtx, const1_rtx, GEN_INT (MACFLAG_NONE))); - emit_insn (gen_ssaddhi3_parts (target, tmp2, tmp2, const1_rtx, - const0_rtx, const0_rtx)); - - emit_insn (gen_sssubhi3_parts (target, tmp1, tmp1, const0_rtx, - const0_rtx, const1_rtx)); + emit_insn (gen_ssaddhi3_high_parts (target, tmp2, tmp2, tmp2, const0_rtx, + const0_rtx)); + emit_insn (gen_sssubhi3_low_parts (target, target, tmp1, tmp1, + const0_rtx, const1_rtx)); return target; @@ -6233,12 +6574,8 @@ bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, #undef TARGET_SCHED_ISSUE_RATE #define TARGET_SCHED_ISSUE_RATE bfin_issue_rate -#undef TARGET_PROMOTE_PROTOTYPES -#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true -#undef TARGET_PROMOTE_FUNCTION_ARGS -#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true -#undef TARGET_PROMOTE_FUNCTION_RETURN -#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true +#undef TARGET_PROMOTE_FUNCTION_MODE +#define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote #undef TARGET_ARG_PARTIAL_BYTES #define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes @@ -6273,4 +6610,13 @@ bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, #undef TARGET_RETURN_IN_MEMORY #define TARGET_RETURN_IN_MEMORY bfin_return_in_memory +#undef TARGET_LEGITIMATE_ADDRESS_P +#define TARGET_LEGITIMATE_ADDRESS_P bfin_legitimate_address_p + +#undef TARGET_FRAME_POINTER_REQUIRED +#define TARGET_FRAME_POINTER_REQUIRED bfin_frame_pointer_required + +#undef TARGET_CAN_ELIMINATE +#define TARGET_CAN_ELIMINATE bfin_can_eliminate + struct gcc_target targetm = TARGET_INITIALIZER; diff --git a/gcc/config/bfin/bfin.h b/gcc/config/bfin/bfin.h index 8193ff3a747..34032b28225 100644 --- a/gcc/config/bfin/bfin.h +++ b/gcc/config/bfin/bfin.h @@ -1,5 +1,5 @@ /* Definitions for the Blackfin port. - Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc. + Copyright (C) 2005, 2007, 2008, 2009 Free Software Foundation, Inc. Contributed by Analog Devices. This file is part of GCC. @@ -26,6 +26,49 @@ #define BRT 1 #define BRF 0 +/* CPU type. */ +typedef enum bfin_cpu_type +{ + BFIN_CPU_UNKNOWN, + BFIN_CPU_BF512, + BFIN_CPU_BF514, + BFIN_CPU_BF516, + BFIN_CPU_BF518, + BFIN_CPU_BF522, + BFIN_CPU_BF523, + BFIN_CPU_BF524, + BFIN_CPU_BF525, + BFIN_CPU_BF526, + BFIN_CPU_BF527, + BFIN_CPU_BF531, + BFIN_CPU_BF532, + BFIN_CPU_BF533, + BFIN_CPU_BF534, + BFIN_CPU_BF536, + BFIN_CPU_BF537, + BFIN_CPU_BF538, + BFIN_CPU_BF539, + BFIN_CPU_BF542, + BFIN_CPU_BF542M, + BFIN_CPU_BF544, + BFIN_CPU_BF544M, + BFIN_CPU_BF547, + BFIN_CPU_BF547M, + BFIN_CPU_BF548, + BFIN_CPU_BF548M, + BFIN_CPU_BF549, + BFIN_CPU_BF549M, + BFIN_CPU_BF561 +} bfin_cpu_t; + +/* Value of -mcpu= */ +extern bfin_cpu_t bfin_cpu_type; + +/* Value of -msi-revision= */ +extern int bfin_si_revision; + +extern unsigned int bfin_workarounds; + /* Print subsidiary information on the compiler version in use. */ #define TARGET_VERSION fprintf (stderr, " (BlackFin bfin)") @@ -109,22 +152,32 @@ extern int target_flags; case BFIN_CPU_BF539: \ builtin_define ("__ADSPBF539__"); \ break; \ + case BFIN_CPU_BF542M: \ + builtin_define ("__ADSPBF542M__"); \ case BFIN_CPU_BF542: \ builtin_define ("__ADSPBF542__"); \ builtin_define ("__ADSPBF54x__"); \ break; \ + case BFIN_CPU_BF544M: \ + builtin_define ("__ADSPBF544M__"); \ case BFIN_CPU_BF544: \ builtin_define ("__ADSPBF544__"); \ builtin_define ("__ADSPBF54x__"); \ break; \ - case BFIN_CPU_BF548: \ - builtin_define ("__ADSPBF548__"); \ - builtin_define ("__ADSPBF54x__"); \ - break; \ + case BFIN_CPU_BF547M: \ + builtin_define ("__ADSPBF547M__"); \ case BFIN_CPU_BF547: \ builtin_define ("__ADSPBF547__"); \ builtin_define ("__ADSPBF54x__"); \ break; \ + case BFIN_CPU_BF548M: \ + builtin_define ("__ADSPBF548M__"); \ + case BFIN_CPU_BF548: \ + builtin_define ("__ADSPBF548__"); \ + builtin_define ("__ADSPBF54x__"); \ + break; \ + case BFIN_CPU_BF549M: \ + builtin_define ("__ADSPBF549M__"); \ case BFIN_CPU_BF549: \ builtin_define ("__ADSPBF549__"); \ builtin_define ("__ADSPBF54x__"); \ @@ -313,13 +366,6 @@ extern const char *bfin_library_id_string; found in the variable crtl->outgoing_args_size. */ #define ACCUMULATE_OUTGOING_ARGS 1 -/* 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. - This is computed in `reload', in reload1.c. -*/ -#define FRAME_POINTER_REQUIRED (bfin_frame_pointer_required ()) - /*#define DATA_ALIGNMENT(TYPE, BASIC-ALIGN) for arrays.. */ /* If defined, a C expression to compute the alignment for a local @@ -383,14 +429,6 @@ extern const char *bfin_library_id_string; { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}} \ -/* Given FROM and TO register numbers, say whether this elimination is - allowed. Frame pointer elimination is automatically handled. - - All other eliminations are valid. */ - -#define CAN_ELIMINATE(FROM, TO) \ - ((TO) == STACK_POINTER_REGNUM ? ! frame_pointer_needed : 1) - /* Define the offset between two registers, one to be eliminated, and the other its replacement, at the start of a routine. */ @@ -809,6 +847,7 @@ enum reg_class typedef enum { SUBROUTINE, INTERRUPT_HANDLER, EXCPT_HANDLER, NMI_HANDLER } e_funkind; +#define FUNCTION_RETURN_REGISTERS { REG_RETS, REG_RETI, REG_RETX, REG_RETN } #define FUNCTION_ARG_REGISTERS { REG_R0, REG_R1, REG_R2, -1 } @@ -908,65 +947,13 @@ typedef struct { /* A number, the maximum number of registers that can appear in a valid memory address. Note that it is up to you to specify a - value equal to the maximum number that `GO_IF_LEGITIMATE_ADDRESS' + value equal to the maximum number that `TARGET_LEGITIMATE_ADDRESS_P' would ever accept. */ #define MAX_REGS_PER_ADDRESS 1 -/* 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. - - Blackfin addressing modes are as follows: - - [preg] - [preg + imm16] - - B [ Preg + uimm15 ] - W [ Preg + uimm16m2 ] - [ Preg + uimm17m4 ] - - [preg++] - [preg--] - [--sp] -*/ - #define LEGITIMATE_MODE_FOR_AUTOINC_P(MODE) \ (GET_MODE_SIZE (MODE) <= 4 || (MODE) == PDImode) -#ifdef REG_OK_STRICT -#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, WIN) \ - do { \ - if (bfin_legitimate_address_p (MODE, X, 1)) \ - goto WIN; \ - } while (0); -#else -#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, WIN) \ - do { \ - if (bfin_legitimate_address_p (MODE, X, 0)) \ - goto WIN; \ - } while (0); -#endif - -/* Try machine-dependent ways of modifying an illegitimate address - to be legitimate. If we find one, return the new, valid address. - This macro is used in only one place: `memory_address' in explow.c. - - OLDX is the address as it was before break_out_memory_refs was called. - In some cases it is useful to look at this to decide what needs to be done. - - MODE and WIN are passed so that this macro can use - GO_IF_LEGITIMATE_ADDRESS. - - It is always safe for this macro to do nothing. It exists to recognize - opportunities to optimize the output. - */ -#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \ -do { \ - rtx _q = legitimize_address(X, OLDX, MODE); \ - if (_q) { X = _q; goto WIN; } \ -} while (0) - #define HAVE_POST_INCREMENT 1 #define HAVE_POST_DECREMENT 1 #define HAVE_PRE_DECREMENT 1 @@ -986,23 +973,6 @@ do { \ || GET_CODE (X) == LABEL_REF \ || (GET_CODE (X) == CONST && symbolic_reference_mentioned_p (X))) -/* - A C statement or compound statement with a conditional `goto - LABEL;' executed if memory address X (an RTX) can have different - meanings depending on the machine mode of the memory reference it - is used for or if the address is valid for some modes but not - others. - - Autoincrement and autodecrement addresses typically have - mode-dependent effects because the amount of the increment or - decrement is the size of the operand being addressed. Some - machines have other mode-dependent addresses. Many RISC machines - have no mode-dependent addresses. - - You may assume that ADDR is a valid address for the machine. -*/ -#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) - #define NOTICE_UPDATE_CC(EXPR, INSN) 0 /* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits @@ -1328,7 +1298,6 @@ do { \ #define ASM_OUTPUT_REG_PUSH(FILE, REGNO) fprintf (FILE, "[SP--] = %s;\n", reg_names[REGNO]) #define ASM_OUTPUT_REG_POP(FILE, REGNO) fprintf (FILE, "%s = [SP++];\n", reg_names[REGNO]) -extern struct rtx_def *bfin_compare_op0, *bfin_compare_op1; extern struct rtx_def *bfin_cc_rtx, *bfin_rets_rtx; /* This works for GAS and some other assemblers. */ @@ -1339,8 +1308,12 @@ extern struct rtx_def *bfin_cc_rtx, *bfin_rets_rtx; #define SIZE_ASM_OP "\t.size\t" -extern int splitting_for_sched; +extern int splitting_for_sched, splitting_loops; #define PRINT_OPERAND_PUNCT_VALID_P(CHAR) ((CHAR) == '!') +#ifndef TARGET_SUPPORTS_SYNC_CALLS +#define TARGET_SUPPORTS_SYNC_CALLS 0 +#endif + #endif /* _BFIN_CONFIG */ diff --git a/gcc/config/bfin/bfin.md b/gcc/config/bfin/bfin.md index 516a2052f78..3fac01ca564 100644 --- a/gcc/config/bfin/bfin.md +++ b/gcc/config/bfin/bfin.md @@ -138,15 +138,16 @@ ;; Distinguish a 32-bit version of an insn from a 16-bit version. (UNSPEC_32BIT 11) (UNSPEC_NOP 12) - (UNSPEC_ONES 12)]) + (UNSPEC_ONES 13) + (UNSPEC_ATOMIC 14)]) (define_constants - [(UNSPEC_VOLATILE_EH_RETURN 0) - (UNSPEC_VOLATILE_CSYNC 1) + [(UNSPEC_VOLATILE_CSYNC 1) (UNSPEC_VOLATILE_SSYNC 2) (UNSPEC_VOLATILE_LOAD_FUNCDESC 3) (UNSPEC_VOLATILE_STORE_EH_HANDLER 4) - (UNSPEC_VOLATILE_DUMMY 5)]) + (UNSPEC_VOLATILE_DUMMY 5) + (UNSPEC_VOLATILE_STALL 6)]) (define_constants [(MACFLAG_NONE 0) @@ -163,28 +164,42 @@ (MACFLAG_IH 11)]) (define_attr "type" - "move,movcc,mvi,mcld,mcst,dsp32,mult,alu0,shft,brcc,br,call,misc,sync,compare,dummy" + "move,movcc,mvi,mcld,mcst,dsp32,dsp32shiftimm,mult,alu0,shft,brcc,br,call,misc,sync,compare,dummy,stall" (const_string "misc")) -(define_attr "addrtype" "32bit,preg,ireg" +(define_attr "addrtype" "32bit,preg,spreg,ireg" (cond [(and (eq_attr "type" "mcld") - (and (match_operand 0 "d_register_operand" "") + (and (match_operand 0 "dp_register_operand" "") (match_operand 1 "mem_p_address_operand" ""))) (const_string "preg") (and (eq_attr "type" "mcld") - (and (match_operand 0 "d_register_operand" "") + (and (match_operand 0 "dp_register_operand" "") + (match_operand 1 "mem_spfp_address_operand" ""))) + (const_string "spreg") + (and (eq_attr "type" "mcld") + (and (match_operand 0 "dp_register_operand" "") (match_operand 1 "mem_i_address_operand" ""))) (const_string "ireg") (and (eq_attr "type" "mcst") - (and (match_operand 1 "d_register_operand" "") + (and (match_operand 1 "dp_register_operand" "") (match_operand 0 "mem_p_address_operand" ""))) (const_string "preg") (and (eq_attr "type" "mcst") - (and (match_operand 1 "d_register_operand" "") + (and (match_operand 1 "dp_register_operand" "") + (match_operand 0 "mem_spfp_address_operand" ""))) + (const_string "spreg") + (and (eq_attr "type" "mcst") + (and (match_operand 1 "dp_register_operand" "") (match_operand 0 "mem_i_address_operand" ""))) (const_string "ireg")] (const_string "32bit"))) +(define_attr "storereg" "preg,other" + (cond [(and (eq_attr "type" "mcst") + (match_operand 1 "p_register_operand" "")) + (const_string "preg")] + (const_string "other"))) + ;; Scheduling definitions (define_automaton "bfin") @@ -199,6 +214,13 @@ (define_cpu_unit "store" "bfin") (define_cpu_unit "pregs" "bfin") +;; A dummy unit used to delay scheduling of loads after a conditional +;; branch. +(define_cpu_unit "load" "bfin") + +;; A logical unit used to work around anomaly 05000074. +(define_cpu_unit "anomaly_05000074" "bfin") + (define_reservation "core" "slot0+slot1+slot2") (define_insn_reservation "alu" 1 @@ -213,20 +235,37 @@ (eq_attr "type" "dsp32") "slot0") +(define_insn_reservation "dsp32shiftimm" 1 + (and (eq_attr "type" "dsp32shiftimm") + (eq (symbol_ref "ENABLE_WA_05000074") + (const_int 0))) + "slot0") + +(define_insn_reservation "dsp32shiftimm_anomaly_05000074" 1 + (and (eq_attr "type" "dsp32shiftimm") + (ne (symbol_ref "ENABLE_WA_05000074") + (const_int 0))) + "slot0+anomaly_05000074") + (define_insn_reservation "load32" 1 (and (not (eq_attr "seq_insns" "multi")) (and (eq_attr "type" "mcld") (eq_attr "addrtype" "32bit"))) - "core") + "core+load") (define_insn_reservation "loadp" 1 (and (not (eq_attr "seq_insns" "multi")) (and (eq_attr "type" "mcld") (eq_attr "addrtype" "preg"))) - "(slot1|slot2)+pregs") + "slot1+pregs+load") + +(define_insn_reservation "loadsp" 1 + (and (not (eq_attr "seq_insns" "multi")) + (and (eq_attr "type" "mcld") (eq_attr "addrtype" "spreg"))) + "slot1+pregs") (define_insn_reservation "loadi" 1 (and (not (eq_attr "seq_insns" "multi")) (and (eq_attr "type" "mcld") (eq_attr "addrtype" "ireg"))) - "(slot1|slot2)") + "(slot1|slot2)+load") (define_insn_reservation "store32" 1 (and (not (eq_attr "seq_insns" "multi")) @@ -234,19 +273,55 @@ "core") (define_insn_reservation "storep" 1 - (and (not (eq_attr "seq_insns" "multi")) - (and (eq_attr "type" "mcst") (eq_attr "addrtype" "preg"))) - "(slot1|slot2)+pregs+store") + (and (and (not (eq_attr "seq_insns" "multi")) + (and (eq_attr "type" "mcst") + (ior (eq_attr "addrtype" "preg") + (eq_attr "addrtype" "spreg")))) + (ior (eq (symbol_ref "ENABLE_WA_05000074") + (const_int 0)) + (eq_attr "storereg" "other"))) + "slot1+pregs+store") + +(define_insn_reservation "storep_anomaly_05000074" 1 + (and (and (not (eq_attr "seq_insns" "multi")) + (and (eq_attr "type" "mcst") + (ior (eq_attr "addrtype" "preg") + (eq_attr "addrtype" "spreg")))) + (and (ne (symbol_ref "ENABLE_WA_05000074") + (const_int 0)) + (eq_attr "storereg" "preg"))) + "slot1+anomaly_05000074+pregs+store") (define_insn_reservation "storei" 1 - (and (not (eq_attr "seq_insns" "multi")) - (and (eq_attr "type" "mcst") (eq_attr "addrtype" "ireg"))) + (and (and (not (eq_attr "seq_insns" "multi")) + (and (eq_attr "type" "mcst") (eq_attr "addrtype" "ireg"))) + (ior (eq (symbol_ref "ENABLE_WA_05000074") + (const_int 0)) + (eq_attr "storereg" "other"))) "(slot1|slot2)+store") +(define_insn_reservation "storei_anomaly_05000074" 1 + (and (and (not (eq_attr "seq_insns" "multi")) + (and (eq_attr "type" "mcst") (eq_attr "addrtype" "ireg"))) + (and (ne (symbol_ref "ENABLE_WA_05000074") + (const_int 0)) + (eq_attr "storereg" "preg"))) + "((slot1+anomaly_05000074)|slot2)+store") + (define_insn_reservation "multi" 2 (eq_attr "seq_insns" "multi") "core") +(define_insn_reservation "load_stall1" 1 + (and (eq_attr "type" "stall") + (match_operand 0 "const1_operand" "")) + "core+load*2") + +(define_insn_reservation "load_stall3" 1 + (and (eq_attr "type" "stall") + (match_operand 0 "const3_operand" "")) + "core+load*4") + (absence_set "slot0" "slot1,slot2") (absence_set "slot1" "slot2") @@ -303,6 +378,7 @@ (eq_attr "type" "move") (const_int 2) (eq_attr "type" "dsp32") (const_int 4) + (eq_attr "type" "dsp32shiftimm") (const_int 4) (eq_attr "type" "call") (const_int 4) (eq_attr "type" "br") @@ -532,20 +608,22 @@ ;; with a PLUS. We generally require fewer secondary reloads this way. (define_insn "*movsi_insn" - [(set (match_operand:SI 0 "nonimmediate_operand" "=da,x*y,da,x,x,x,da,mr") - (match_operand:SI 1 "general_operand" "da,x*y,xKs7,xKsh,xKuh,ix,mr,da"))] + [(set (match_operand:SI 0 "nonimmediate_operand" "=da,x,da,y,da,x,x,x,da,mr") + (match_operand:SI 1 "general_operand" "da,x,y,da,xKs7,xKsh,xKuh,ix,mr,da"))] "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) == REG" "@ %0 = %1; %0 = %1; + %0 = %1; + %0 = %1; %0 = %1 (X); %0 = %1 (X); %0 = %1 (Z); # %0 = %1%! %0 = %1%!" - [(set_attr "type" "move,move,mvi,mvi,mvi,*,mcld,mcst") - (set_attr "length" "2,2,2,4,4,*,*,*")]) + [(set_attr "type" "move,move,move,move,mvi,mvi,mvi,*,mcld,mcst") + (set_attr "length" "2,2,2,2,2,4,4,*,*,*")]) (define_insn "*movsi_insn32" [(set (match_operand:SI 0 "register_operand" "=d,d") @@ -554,7 +632,7 @@ "@ %0 = ROT %1 BY 0%! %0 = %0 -|- %0%!" - [(set_attr "type" "dsp32")]) + [(set_attr "type" "dsp32shiftimm,dsp32")]) (define_split [(set (match_operand:SI 0 "d_register_operand" "") @@ -677,7 +755,7 @@ "@ %d0 = %h1 << 0%! %d0 = %1;" - [(set_attr "type" "dsp32,mvi")]) + [(set_attr "type" "dsp32shiftimm,mvi")]) (define_expand "insv" [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "") @@ -1587,7 +1665,7 @@ [(set (match_dup 0) (ashift:SI (match_dup 1) (const_int 2))) (set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 3)))] "operands[3] = GEN_INT (INTVAL (operands[2]) - 2);" - [(set_attr "type" "shft,dsp32,shft,shft,*")]) + [(set_attr "type" "shft,dsp32shiftimm,shft,shft,*")]) (define_insn "ashrsi3" [(set (match_operand:SI 0 "register_operand" "=d,d") @@ -1597,7 +1675,7 @@ "@ %0 >>>= %2; %0 = %1 >>> %2%!" - [(set_attr "type" "shft,dsp32")]) + [(set_attr "type" "shft,dsp32shiftimm")]) (define_insn "rotl16" [(set (match_operand:SI 0 "register_operand" "=d") @@ -1638,7 +1716,7 @@ (zero_extract:BI (match_dup 1) (const_int 1) (const_int 0)))] "" "%0 = ROT %1 BY -1%!" - [(set_attr "type" "dsp32")]) + [(set_attr "type" "dsp32shiftimm")]) (define_insn "rol_one" [(set (match_operand:SI 0 "register_operand" "+d") @@ -1648,7 +1726,7 @@ (zero_extract:BI (match_dup 1) (const_int 31) (const_int 0)))] "" "%0 = ROT %1 BY 1%!" - [(set_attr "type" "dsp32")]) + [(set_attr "type" "dsp32shiftimm")]) (define_expand "lshrdi3" [(set (match_operand:DI 0 "register_operand" "") @@ -1723,7 +1801,7 @@ %0 >>= %2; %0 = %1 >> %2%! %0 = %1 >> %2;" - [(set_attr "type" "shft,dsp32,shft")]) + [(set_attr "type" "shft,dsp32shiftimm,shft")]) (define_insn "lshrpdi3" [(set (match_operand:PDI 0 "register_operand" "=e") @@ -1731,7 +1809,7 @@ (match_operand:SI 2 "nonmemory_operand" "Ku5")))] "" "%0 = %1 >> %2%!" - [(set_attr "type" "dsp32")]) + [(set_attr "type" "dsp32shiftimm")]) (define_insn "ashrpdi3" [(set (match_operand:PDI 0 "register_operand" "=e") @@ -1739,7 +1817,7 @@ (match_operand:SI 2 "nonmemory_operand" "Ku5")))] "" "%0 = %1 >>> %2%!" - [(set_attr "type" "dsp32")]) + [(set_attr "type" "dsp32shiftimm")]) ;; A pattern to reload the equivalent of ;; (set (Dreg) (plus (FP) (large_constant))) @@ -1763,9 +1841,11 @@ DONE; }) -(define_insn "reload_inpdi" - [(set (match_operand:PDI 0 "register_operand" "=e") - (match_operand:PDI 1 "memory_operand" "m")) +(define_mode_iterator AREG [PDI V2PDI]) + +(define_insn "reload_in<mode>" + [(set (match_operand:AREG 0 "register_operand" "=e") + (match_operand:AREG 1 "memory_operand" "m")) (clobber (match_operand:SI 2 "register_operand" "=d"))] "" { @@ -1783,9 +1863,9 @@ (set_attr "type" "mcld") (set_attr "length" "12")]) -(define_insn "reload_outpdi" - [(set (match_operand:PDI 0 "memory_operand" "=m") - (match_operand:PDI 1 "register_operand" "e")) +(define_insn "reload_out<mode>" + [(set (match_operand:AREG 0 "memory_operand" "=m") + (match_operand:AREG 1 "register_operand" "e")) (clobber (match_operand:SI 2 "register_operand" "=d"))] "" { @@ -1908,7 +1988,7 @@ (const_int -1))) (unspec [(const_int 0)] UNSPEC_LSETUP_END) (clobber (match_scratch:SI 2 "=&r"))] - "reload_completed" + "splitting_loops" [(set (match_dup 2) (match_dup 0)) (set (match_dup 2) (plus:SI (match_dup 2) (const_int -1))) (set (match_dup 0) (match_dup 2)) @@ -2004,7 +2084,8 @@ [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" "Q")) (match_operand 1 "general_operand" "g")) (use (match_operand:SI 2 "register_operand" "Z")) - (use (match_operand 3 "" ""))] + (use (match_operand 3 "" "")) + (clobber (reg:SI REG_RETS))] "! SIBLING_CALL_P (insn) && GET_CODE (operands[0]) == SYMBOL_REF && !bfin_longcall_p (operands[0], INTVAL (operands[3]))" @@ -2030,7 +2111,8 @@ (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" "Q")) (match_operand 2 "general_operand" "g"))) (use (match_operand:SI 3 "register_operand" "Z")) - (use (match_operand 4 "" ""))] + (use (match_operand 4 "" "")) + (clobber (reg:SI REG_RETS))] "! SIBLING_CALL_P (insn) && GET_CODE (operands[1]) == SYMBOL_REF && !bfin_longcall_p (operands[1], INTVAL (operands[4]))" @@ -2056,7 +2138,8 @@ [(call (mem:SI (match_operand:SI 0 "register_no_elim_operand" "Y")) (match_operand 1 "general_operand" "g")) (use (match_operand:SI 2 "register_operand" "Z")) - (use (match_operand 3 "" ""))] + (use (match_operand 3 "" "")) + (clobber (reg:SI REG_RETS))] "! SIBLING_CALL_P (insn)" "call (%0);" [(set_attr "type" "call") @@ -2078,7 +2161,8 @@ (call (mem:SI (match_operand:SI 1 "register_no_elim_operand" "Y")) (match_operand 2 "general_operand" "g"))) (use (match_operand:SI 3 "register_operand" "Z")) - (use (match_operand 4 "" ""))] + (use (match_operand 4 "" "")) + (clobber (reg:SI REG_RETS))] "! SIBLING_CALL_P (insn)" "call (%1);" [(set_attr "type" "call") @@ -2099,7 +2183,8 @@ (define_insn "*call_symbol" [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" "Q")) (match_operand 1 "general_operand" "g")) - (use (match_operand 2 "" ""))] + (use (match_operand 2 "" "")) + (clobber (reg:SI REG_RETS))] "! SIBLING_CALL_P (insn) && (!TARGET_ID_SHARED_LIBRARY || TARGET_LEAF_ID_SHARED_LIBRARY) && GET_CODE (operands[0]) == SYMBOL_REF @@ -2125,7 +2210,8 @@ [(set (match_operand 0 "register_operand" "=d") (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" "Q")) (match_operand 2 "general_operand" "g"))) - (use (match_operand 3 "" ""))] + (use (match_operand 3 "" "")) + (clobber (reg:SI REG_RETS))] "! SIBLING_CALL_P (insn) && (!TARGET_ID_SHARED_LIBRARY || TARGET_LEAF_ID_SHARED_LIBRARY) && GET_CODE (operands[1]) == SYMBOL_REF @@ -2151,7 +2237,8 @@ (define_insn "*call_insn" [(call (mem:SI (match_operand:SI 0 "register_no_elim_operand" "a")) (match_operand 1 "general_operand" "g")) - (use (match_operand 2 "" ""))] + (use (match_operand 2 "" "")) + (clobber (reg:SI REG_RETS))] "! SIBLING_CALL_P (insn)" "call (%0);" [(set_attr "type" "call") @@ -2171,7 +2258,8 @@ [(set (match_operand 0 "register_operand" "=d") (call (mem:SI (match_operand:SI 1 "register_no_elim_operand" "a")) (match_operand 2 "general_operand" "g"))) - (use (match_operand 3 "" ""))] + (use (match_operand 3 "" "")) + (clobber (reg:SI REG_RETS))] "! SIBLING_CALL_P (insn)" "call (%1);" [(set_attr "type" "call") @@ -2253,29 +2341,6 @@ ;; Conditional branch patterns ;; The Blackfin has only few condition codes: eq, lt, lte, ltu, leu -;; The only outcome of this pattern is that global variables -;; bfin_compare_op[01] are set for use in bcond patterns. - -(define_expand "cmpbi" - [(set (cc0) (compare (match_operand:BI 0 "register_operand" "") - (match_operand:BI 1 "immediate_operand" "")))] - "" -{ - bfin_compare_op0 = operands[0]; - bfin_compare_op1 = operands[1]; - DONE; -}) - -(define_expand "cmpsi" - [(set (cc0) (compare (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "reg_or_const_int_operand" "")))] - "" -{ - bfin_compare_op0 = operands[0]; - bfin_compare_op1 = operands[1]; - DONE; -}) - (define_insn "compare_eq" [(set (match_operand:BI 0 "register_operand" "=C,C") (eq:BI (match_operand:SI 1 "register_operand" "d,a") @@ -2324,106 +2389,6 @@ "cc =%1<%2 (iu);" [(set_attr "type" "compare")]) -(define_expand "beq" - [(set (match_dup 1) (match_dup 2)) - (set (pc) - (if_then_else (match_dup 3) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" -{ - rtx op0 = bfin_compare_op0, op1 = bfin_compare_op1; - operands[1] = bfin_cc_rtx; /* hard register: CC */ - operands[2] = gen_rtx_EQ (BImode, op0, op1); - /* If we have a BImode input, then we already have a compare result, and - do not need to emit another comparison. */ - if (GET_MODE (bfin_compare_op0) == BImode) - { - gcc_assert (bfin_compare_op1 == const0_rtx); - emit_insn (gen_cbranchbi4 (operands[2], op0, op1, operands[0])); - DONE; - } - - operands[3] = gen_rtx_NE (BImode, operands[1], const0_rtx); -}) - -(define_expand "bne" - [(set (match_dup 1) (match_dup 2)) - (set (pc) - (if_then_else (match_dup 3) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" -{ - rtx op0 = bfin_compare_op0, op1 = bfin_compare_op1; - /* If we have a BImode input, then we already have a compare result, and - do not need to emit another comparison. */ - if (GET_MODE (bfin_compare_op0) == BImode) - { - rtx cmp = gen_rtx_NE (BImode, op0, op1); - - gcc_assert (bfin_compare_op1 == const0_rtx); - emit_insn (gen_cbranchbi4 (cmp, op0, op1, operands[0])); - DONE; - } - - operands[1] = bfin_cc_rtx; /* hard register: CC */ - operands[2] = gen_rtx_EQ (BImode, op0, op1); - operands[3] = gen_rtx_EQ (BImode, operands[1], const0_rtx); -}) - -(define_expand "bgt" - [(set (match_dup 1) (match_dup 2)) - (set (pc) - (if_then_else (match_dup 3) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" -{ - operands[1] = bfin_cc_rtx; - operands[2] = gen_rtx_LE (BImode, bfin_compare_op0, bfin_compare_op1); - operands[3] = gen_rtx_EQ (BImode, operands[1], const0_rtx); -}) - -(define_expand "bgtu" - [(set (match_dup 1) (match_dup 2)) - (set (pc) - (if_then_else (match_dup 3) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" -{ - operands[1] = bfin_cc_rtx; - operands[2] = gen_rtx_LEU (BImode, bfin_compare_op0, bfin_compare_op1); - operands[3] = gen_rtx_EQ (BImode, operands[1], const0_rtx); -}) - -(define_expand "blt" - [(set (match_dup 1) (match_dup 2)) - (set (pc) - (if_then_else (match_dup 3) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" -{ - operands[1] = bfin_cc_rtx; - operands[2] = gen_rtx_LT (BImode, bfin_compare_op0, bfin_compare_op1); - operands[3] = gen_rtx_NE (BImode, operands[1], const0_rtx); -}) - -(define_expand "bltu" - [(set (match_dup 1) (match_dup 2)) - (set (pc) - (if_then_else (match_dup 3) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" -{ - operands[1] = bfin_cc_rtx; - operands[2] = gen_rtx_LTU (BImode, bfin_compare_op0, bfin_compare_op1); - operands[3] = gen_rtx_NE (BImode, operands[1], const0_rtx); -}) - ;; Same as above, but and CC with the overflow bit generated by the first ;; multiplication. (define_insn "flag_mul_macv2hi_parts_acconly_andcc0" @@ -2488,63 +2453,25 @@ (set_attr "length" "6") (set_attr "seq_insns" "multi")]) -(define_expand "bge" - [(set (match_dup 1) (match_dup 2)) - (set (pc) - (if_then_else (match_dup 3) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" -{ - operands[1] = bfin_cc_rtx; - operands[2] = gen_rtx_LT (BImode, bfin_compare_op0, bfin_compare_op1); - operands[3] = gen_rtx_EQ (BImode, operands[1], const0_rtx); -}) - -(define_expand "bgeu" - [(set (match_dup 1) (match_dup 2)) - (set (pc) - (if_then_else (match_dup 3) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" -{ - operands[1] = bfin_cc_rtx; - operands[2] = gen_rtx_LTU (BImode, bfin_compare_op0, bfin_compare_op1); - operands[3] = gen_rtx_EQ (BImode, operands[1], const0_rtx); -}) - -(define_expand "ble" - [(set (match_dup 1) (match_dup 2)) - (set (pc) - (if_then_else (match_dup 3) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" -{ - operands[1] = bfin_cc_rtx; - operands[2] = gen_rtx_LE (BImode, bfin_compare_op0, bfin_compare_op1); - operands[3] = gen_rtx_NE (BImode, operands[1], const0_rtx); -}) - -(define_expand "bleu" - [(set (match_dup 1) (match_dup 2)) - (set (pc) - (if_then_else (match_dup 3) - (label_ref (match_operand 0 "" "")) - (pc))) - ] +(define_expand "cbranchsi4" + [(set (pc) + (if_then_else (match_operator 0 "ordered_comparison_operator" + [(match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "reg_or_const_int_operand" "")]) + (label_ref (match_operand 3 "" "")) + (pc)))] "" { - operands[1] = bfin_cc_rtx; - operands[2] = gen_rtx_LEU (BImode, bfin_compare_op0, bfin_compare_op1); - operands[3] = gen_rtx_NE (BImode, operands[1], const0_rtx); + rtx bi_compare = bfin_gen_compare (operands[0], SImode); + emit_jump_insn (gen_cbranchbi4 (bi_compare, bfin_cc_rtx, CONST0_RTX (BImode), + operands[3])); + DONE; }) (define_insn "cbranchbi4" [(set (pc) (if_then_else - (match_operator 0 "bfin_cbranch_operator" + (match_operator 0 "bfin_bimode_comparison_operator" [(match_operand:BI 1 "register_operand" "C") (match_operand:BI 2 "immediate_operand" "P0")]) (label_ref (match_operand 3 "" "")) @@ -2562,7 +2489,7 @@ (define_insn "cbranch_predicted_taken" [(set (pc) (if_then_else - (match_operator 0 "bfin_cbranch_operator" + (match_operator 0 "bfin_bimode_comparison_operator" [(match_operand:BI 1 "register_operand" "C") (match_operand:BI 2 "immediate_operand" "P0")]) (label_ref (match_operand 3 "" "")) @@ -2578,7 +2505,7 @@ (define_insn "cbranch_with_nops" [(set (pc) (if_then_else - (match_operator 0 "bfin_cbranch_operator" + (match_operator 0 "bfin_bimode_comparison_operator" [(match_operand:BI 1 "register_operand" "C") (match_operand:BI 2 "immediate_operand" "P0")]) (label_ref (match_operand 3 "" "")) @@ -2592,60 +2519,49 @@ [(set_attr "type" "brcc") (set_attr "length" "8")]) -;; setcc insns. */ -(define_expand "seq" - [(set (match_dup 1) (eq:BI (match_dup 2) (match_dup 3))) - (set (match_operand:SI 0 "register_operand" "") - (ne:SI (match_dup 1) (const_int 0)))] - "" -{ - operands[2] = bfin_compare_op0; - operands[3] = bfin_compare_op1; - operands[1] = bfin_cc_rtx; -}) +;; setcc insns. -(define_expand "slt" - [(set (match_dup 1) (lt:BI (match_dup 2) (match_dup 3))) +(define_expand "cstorebi4" + [(set (match_dup 4) + (match_operator:BI 1 "bfin_bimode_comparison_operator" + [(match_operand:BI 2 "register_operand" "") + (match_operand:BI 3 "reg_or_const_int_operand" "")])) (set (match_operand:SI 0 "register_operand" "") - (ne:SI (match_dup 1) (const_int 0)))] + (ne:SI (match_dup 4) (const_int 0)))] "" { - operands[2] = bfin_compare_op0; - operands[3] = bfin_compare_op1; - operands[1] = bfin_cc_rtx; -}) + /* It could be expanded as a movbisi instruction, but the portable + alternative produces better code. */ + if (GET_CODE (operands[1]) == NE) + FAIL; -(define_expand "sle" - [(set (match_dup 1) (le:BI (match_dup 2) (match_dup 3))) - (set (match_operand:SI 0 "register_operand" "") - (ne:SI (match_dup 1) (const_int 0)))] - "" -{ - operands[2] = bfin_compare_op0; - operands[3] = bfin_compare_op1; - operands[1] = bfin_cc_rtx; + operands[4] = bfin_cc_rtx; }) -(define_expand "sltu" - [(set (match_dup 1) (ltu:BI (match_dup 2) (match_dup 3))) - (set (match_operand:SI 0 "register_operand" "") - (ne:SI (match_dup 1) (const_int 0)))] +(define_expand "cstoresi4" + [(set (match_operand:SI 0 "register_operand") + (match_operator:SI 1 "ordered_comparison_operator" + [(match_operand:SI 2 "register_operand" "") + (match_operand:SI 3 "reg_or_const_int_operand" "")]))] "" { - operands[2] = bfin_compare_op0; - operands[3] = bfin_compare_op1; - operands[1] = bfin_cc_rtx; -}) + rtx bi_compare, test; -(define_expand "sleu" - [(set (match_dup 1) (leu:BI (match_dup 2) (match_dup 3))) - (set (match_operand:SI 0 "register_operand" "") - (ne:SI (match_dup 1) (const_int 0)))] - "" -{ - operands[2] = bfin_compare_op0; - operands[3] = bfin_compare_op1; - operands[1] = bfin_cc_rtx; + if (!bfin_direct_comparison_operator (operands[1], SImode)) + { + if (!register_operand (operands[3], SImode) + || GET_CODE (operands[1]) == NE) + FAIL; + test = gen_rtx_fmt_ee (swap_condition (GET_CODE (operands[1])), + SImode, operands[3], operands[2]); + } + else + test = operands[1]; + + bi_compare = bfin_gen_compare (test, SImode); + gcc_assert (GET_CODE (bi_compare) == NE); + emit_insn (gen_movbisi (operands[0], bfin_cc_rtx)); + DONE; }) (define_insn "nop" @@ -2674,13 +2590,16 @@ "CC = %1;" [(set_attr "length" "2")]) -(define_insn "movbisi" +(define_insn_and_split "movbisi" [(set (match_operand:SI 0 "register_operand" "=d") (ne:SI (match_operand:BI 1 "register_operand" "C") (const_int 0)))] "" - "%0 = CC;" - [(set_attr "length" "2")]) + "#" + "" + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:BI 1 "register_operand" "")))] + "") (define_insn "notbi" [(set (match_operand:BI 0 "register_operand" "=C") @@ -2740,8 +2659,7 @@ "bfin_expand_epilogue (0, 0, 1); DONE;") (define_expand "eh_return" - [(unspec_volatile [(match_operand:SI 0 "register_operand" "")] - UNSPEC_VOLATILE_EH_RETURN)] + [(use (match_operand:SI 0 "register_operand" ""))] "" { emit_insn (gen_eh_store_handler (EH_RETURN_HANDLER_RTX, operands[0])); @@ -2759,11 +2677,10 @@ [(set_attr "type" "mcst")]) (define_insn_and_split "eh_return_internal" - [(set (pc) - (unspec_volatile [(reg:SI REG_P2)] UNSPEC_VOLATILE_EH_RETURN))] + [(eh_return)] "" "#" - "reload_completed" + "epilogue_completed" [(const_int 1)] "bfin_expand_epilogue (1, 1, 0); DONE;") @@ -2811,23 +2728,26 @@ (define_insn "return_internal" [(return) - (unspec [(match_operand 0 "immediate_operand" "i")] UNSPEC_RETURN)] + (use (match_operand 0 "register_operand" ""))] "reload_completed" { - switch (INTVAL (operands[0])) + switch (REGNO (operands[0])) { - case EXCPT_HANDLER: + case REG_RETX: return "rtx;"; - case NMI_HANDLER: + case REG_RETN: return "rtn;"; - case INTERRUPT_HANDLER: + case REG_RETI: return "rti;"; - case SUBROUTINE: + case REG_RETS: return "rts;"; } gcc_unreachable (); }) +;; When used at a location where CC contains 1, causes a speculative load +;; that is later cancelled. This is used for certain workarounds in +;; interrupt handler prologues. (define_insn "dummy_load" [(unspec_volatile [(match_operand 0 "register_operand" "a") (match_operand 1 "register_operand" "C")] @@ -2838,6 +2758,17 @@ (set_attr "length" "4") (set_attr "seq_insns" "multi")]) +;; A placeholder insn inserted before the final scheduling pass. It is used +;; to improve scheduling of loads when workarounds for speculative loads are +;; needed, by not placing them in the first few cycles after a conditional +;; branch. +(define_insn "stall" + [(unspec_volatile [(match_operand 0 "const_int_operand" "P1P3")] + UNSPEC_VOLATILE_STALL)] + "" + "" + [(set_attr "type" "stall")]) + (define_insn "csync" [(unspec_volatile [(const_int 0)] UNSPEC_VOLATILE_CSYNC)] "" @@ -2877,7 +2808,7 @@ (parallel [(const_int 1)]))))] "" "%h0 = %h2 << 0%!" - [(set_attr "type" "dsp32")]) + [(set_attr "type" "dsp32shiftimm")]) (define_insn "movhiv2hi_high" [(set (match_operand:V2HI 0 "register_operand" "=d") @@ -2887,7 +2818,7 @@ (match_operand:HI 2 "register_operand" "d")))] "" "%d0 = %h2 << 0%!" - [(set_attr "type" "dsp32")]) + [(set_attr "type" "dsp32shiftimm")]) ;; No earlyclobber on alternative two since our sequence ought to be safe. ;; The order of operands is intentional to match the VDSP builtin (high word @@ -2910,7 +2841,7 @@ (match_dup 2) (vec_select:HI (match_dup 0) (parallel [(const_int 1)]))))] "" - [(set_attr "type" "dsp32")]) + [(set_attr "type" "dsp32shiftimm")]) ; Like composev2hi, but operating on elements of V2HI vectors. ; Useful on its own, and as a combiner bridge for the multiply and @@ -2933,7 +2864,7 @@ %0 = PACK (%h2,%d1)%! %0 = PACK (%d2,%h1)%! %0 = PACK (%d2,%d1)%!" - [(set_attr "type" "dsp32")]) + [(set_attr "type" "dsp32shiftimm,dsp32shiftimm,dsp32shiftimm,dsp32shiftimm,dsp32,dsp32,dsp32,dsp32")]) (define_insn "movv2hi_hi" [(set (match_operand:HI 0 "register_operand" "=d,d,d") @@ -2944,7 +2875,7 @@ /* optimized out */ %h0 = %h1 << 0%! %h0 = %d1 << 0%!" - [(set_attr "type" "dsp32")]) + [(set_attr "type" "dsp32shiftimm")]) (define_expand "movv2hi_hi_low" [(set (match_operand:HI 0 "register_operand" "") @@ -2962,74 +2893,82 @@ ;; Unusual arithmetic operations on 16-bit registers. -(define_insn "ssaddhi3" +(define_code_iterator sp_or_sm [ss_plus ss_minus]) +(define_code_attr spm_string [(ss_plus "+") (ss_minus "-")]) +(define_code_attr spm_name [(ss_plus "add") (ss_minus "sub")]) + +(define_insn "ss<spm_name>hi3" [(set (match_operand:HI 0 "register_operand" "=d") - (ss_plus:HI (match_operand:HI 1 "register_operand" "d") + (sp_or_sm:HI (match_operand:HI 1 "register_operand" "d") (match_operand:HI 2 "register_operand" "d")))] "" - "%h0 = %h1 + %h2 (S)%!" + "%h0 = %h1 <spm_string> %h2 (S)%!" [(set_attr "type" "dsp32")]) -(define_insn "ssaddhi3_parts" - [(set (vec_select:HI - (match_operand:V2HI 0 "register_operand" "d") - (parallel [(match_operand 3 "const01_operand" "P0P1")])) - (ss_plus:HI (vec_select:HI - (match_operand:V2HI 1 "register_operand" "d") - (parallel [(match_operand 4 "const01_operand" "P0P1")])) - (vec_select:HI - (match_operand:V2HI 2 "register_operand" "d") - (parallel [(match_operand 5 "const01_operand" "P0P1")]))))] - "" +(define_insn "ss<spm_name>hi3_parts" + [(set (match_operand:HI 0 "register_operand" "=d") + (sp_or_sm:HI (vec_select:HI + (match_operand:V2HI 1 "register_operand" "d") + (parallel [(match_operand 3 "const01_operand" "P0P1")])) + (vec_select:HI + (match_operand:V2HI 2 "register_operand" "d") + (parallel [(match_operand 4 "const01_operand" "P0P1")]))))] + "" { const char *templates[] = { - "%h0 = %h1 + %h2 (S)%!", - "%d0 = %h1 + %h2 (S)%!", - "%h0 = %d1 + %h2 (S)%!", - "%d0 = %d1 + %h2 (S)%!", - "%h0 = %h1 + %d2 (S)%!", - "%d0 = %h1 + %d2 (S)%!", - "%h0 = %d1 + %d2 (S)%!", - "%d0 = %d1 + %d2 (S)%!" }; - int alt = INTVAL (operands[3]) + (INTVAL (operands[4]) << 1) - + (INTVAL (operands[5]) << 2); + "%h0 = %h1 <spm_string> %h2 (S)%!", + "%h0 = %d1 <spm_string> %h2 (S)%!", + "%h0 = %h1 <spm_string> %d2 (S)%!", + "%h0 = %d1 <spm_string> %d2 (S)%!" }; + int alt = INTVAL (operands[3]) + (INTVAL (operands[4]) << 1); return templates[alt]; } [(set_attr "type" "dsp32")]) -(define_insn "sssubhi3_parts" - [(set (vec_select:HI - (match_operand:V2HI 0 "register_operand" "d") - (parallel [(match_operand 3 "const01_operand" "P0P1")])) - (ss_minus:HI (vec_select:HI - (match_operand:V2HI 1 "register_operand" "d") - (parallel [(match_operand 4 "const01_operand" "P0P1")])) - (vec_select:HI - (match_operand:V2HI 2 "register_operand" "d") - (parallel [(match_operand 5 "const01_operand" "P0P1")]))))] - "" +(define_insn "ss<spm_name>hi3_low_parts" + [(set (match_operand:V2HI 0 "register_operand" "=d") + (vec_concat:V2HI + (vec_select:HI (match_operand:V2HI 1 "register_operand" "0") + (parallel [(const_int 0)])) + (sp_or_sm:HI (vec_select:HI + (match_operand:V2HI 2 "register_operand" "d") + (parallel [(match_operand 4 "const01_operand" "P0P1")])) + (vec_select:HI + (match_operand:V2HI 3 "register_operand" "d") + (parallel [(match_operand 5 "const01_operand" "P0P1")])))))] + "" { const char *templates[] = { - "%h0 = %h1 - %h2 (S)%!", - "%d0 = %h1 - %h2 (S)%!", - "%h0 = %d1 - %h2 (S)%!", - "%d0 = %d1 - %h2 (S)%!", - "%h0 = %h1 - %d2 (S)%!", - "%d0 = %h1 - %d2 (S)%!", - "%h0 = %d1 - %d2 (S)%!", - "%d0 = %d1 - %d2 (S)%!" }; - int alt = INTVAL (operands[3]) + (INTVAL (operands[4]) << 1) - + (INTVAL (operands[5]) << 2); + "%h0 = %h2 <spm_string> %h3 (S)%!", + "%h0 = %d2 <spm_string> %h3 (S)%!", + "%h0 = %h2 <spm_string> %d3 (S)%!", + "%h0 = %d2 <spm_string> %d3 (S)%!" }; + int alt = INTVAL (operands[4]) + (INTVAL (operands[5]) << 1); return templates[alt]; } [(set_attr "type" "dsp32")]) -(define_insn "sssubhi3" - [(set (match_operand:HI 0 "register_operand" "=d") - (ss_minus:HI (match_operand:HI 1 "register_operand" "d") - (match_operand:HI 2 "register_operand" "d")))] - "" - "%h0 = %h1 - %h2 (S)%!" +(define_insn "ss<spm_name>hi3_high_parts" + [(set (match_operand:V2HI 0 "register_operand" "=d") + (vec_concat:V2HI + (sp_or_sm:HI (vec_select:HI + (match_operand:V2HI 2 "register_operand" "d") + (parallel [(match_operand 4 "const01_operand" "P0P1")])) + (vec_select:HI + (match_operand:V2HI 3 "register_operand" "d") + (parallel [(match_operand 5 "const01_operand" "P0P1")]))) + (vec_select:HI (match_operand:V2HI 1 "register_operand" "0") + (parallel [(const_int 1)]))))] + "" +{ + const char *templates[] = { + "%d0 = %h2 <spm_string> %h3 (S)%!", + "%d0 = %d2 <spm_string> %h3 (S)%!", + "%d0 = %h2 <spm_string> %d3 (S)%!", + "%d0 = %d2 <spm_string> %d3 (S)%!" }; + int alt = INTVAL (operands[4]) + (INTVAL (operands[5]) << 1); + return templates[alt]; +} [(set_attr "type" "dsp32")]) ;; V2HI vector insns @@ -3239,30 +3178,23 @@ [(set_attr "type" "dsp32")]) (define_insn "flag_mulhi_parts" - [(set (vec_select:HI - (match_operand:V2HI 0 "register_operand" "d") - (parallel [(match_operand 3 "const01_operand" "P0P1")])) + [(set (match_operand:HI 0 "register_operand" "=d") (unspec:HI [(vec_select:HI (match_operand:V2HI 1 "register_operand" "d") - (parallel [(match_operand 4 "const01_operand" "P0P1")])) + (parallel [(match_operand 3 "const01_operand" "P0P1")])) (vec_select:HI (match_operand:V2HI 2 "register_operand" "d") - (parallel [(match_operand 5 "const01_operand" "P0P1")])) - (match_operand 6 "const_int_operand" "n")] + (parallel [(match_operand 4 "const01_operand" "P0P1")])) + (match_operand 5 "const_int_operand" "n")] UNSPEC_MUL_WITH_FLAG))] "" { const char *templates[] = { - "%h0 = %h1 * %h2 %M6%!", - "%d0 = %h1 * %h2 %M6%!", - "%h0 = %d1 * %h2 %M6%!", - "%d0 = %d1 * %h2 %M6%!", - "%h0 = %h1 * %d2 %M6%!", - "%d0 = %h1 * %d2 %M6%!", - "%h0 = %d1 * %d2 %M6%!", - "%d0 = %d1 * %d2 %M6%!" }; - int alt = INTVAL (operands[3]) + (INTVAL (operands[4]) << 1) - + (INTVAL (operands[5]) << 2); + "%h0 = %h1 * %h2 %M5%!", + "%h0 = %d1 * %h2 %M5%!", + "%h0 = %h1 * %d2 %M5%!", + "%h0 = %d1 * %d2 %M5%!" }; + int alt = INTVAL (operands[3]) + (INTVAL (operands[4]) << 1); return templates[alt]; } [(set_attr "type" "dsp32")]) @@ -4207,7 +4139,7 @@ %0 = ASHIFT %1 BY %h2 (V, S)%! %0 = %1 << %2 (V,S)%! %0 = %1 >>> %N2 (V,S)%!" - [(set_attr "type" "dsp32")]) + [(set_attr "type" "dsp32,dsp32shiftimm,dsp32shiftimm")]) (define_insn "ssashifthi3" [(set (match_operand:HI 0 "register_operand" "=d,d,d") @@ -4221,7 +4153,7 @@ %0 = ASHIFT %1 BY %h2 (V, S)%! %0 = %1 << %2 (V,S)%! %0 = %1 >>> %N2 (V,S)%!" - [(set_attr "type" "dsp32")]) + [(set_attr "type" "dsp32,dsp32shiftimm,dsp32shiftimm")]) (define_insn "ssashiftsi3" [(set (match_operand:SI 0 "register_operand" "=d,d,d") @@ -4235,7 +4167,7 @@ %0 = ASHIFT %1 BY %h2 (S)%! %0 = %1 << %2 (S)%! %0 = %1 >>> %N2 (S)%!" - [(set_attr "type" "dsp32")]) + [(set_attr "type" "dsp32,dsp32shiftimm,dsp32shiftimm")]) (define_insn "lshiftv2hi3" [(set (match_operand:V2HI 0 "register_operand" "=d,d,d") @@ -4249,7 +4181,7 @@ %0 = LSHIFT %1 BY %h2 (V)%! %0 = %1 << %2 (V)%! %0 = %1 >> %N2 (V)%!" - [(set_attr "type" "dsp32")]) + [(set_attr "type" "dsp32,dsp32shiftimm,dsp32shiftimm")]) (define_insn "lshifthi3" [(set (match_operand:HI 0 "register_operand" "=d,d,d") @@ -4263,7 +4195,7 @@ %0 = LSHIFT %1 BY %h2 (V)%! %0 = %1 << %2 (V)%! %0 = %1 >> %N2 (V)%!" - [(set_attr "type" "dsp32")]) + [(set_attr "type" "dsp32,dsp32shiftimm,dsp32shiftimm")]) ;; Load without alignment exception (masking off low bits) @@ -4275,3 +4207,5 @@ "DISALGNEXCPT || %0 = [%1];" [(set_attr "type" "mcld") (set_attr "length" "8")]) + +(include "sync.md") diff --git a/gcc/config/bfin/crti.s b/gcc/config/bfin/crti.s index 136516e7cbe..b6f20fc9e6b 100644 --- a/gcc/config/bfin/crti.s +++ b/gcc/config/bfin/crti.s @@ -1,13 +1,13 @@ /* Specialized code needed to support construction and destruction of file-scope objects in C++ and Java code, and to support exception handling. - Copyright (C) 2005, 2008 Free Software Foundation, Inc. + Copyright (C) 2005, 2008, 2009 Free Software Foundation, Inc. Contributed by Analog Devices. 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) +the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, @@ -15,16 +15,14 @@ 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. */ +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. -/* As a special exception, if you link this library with files - compiled with GCC to produce an executable, this does not cause - the resulting executable to be covered by the GNU General Public License. - This exception does not however invalidate any other reasons why - the executable file might be covered by the GNU General Public License. */ +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ /* * This file just supplies function prologues for the .init and .fini diff --git a/gcc/config/bfin/crtlibid.s b/gcc/config/bfin/crtlibid.s index 54d5b57b694..beab8093810 100644 --- a/gcc/config/bfin/crtlibid.s +++ b/gcc/config/bfin/crtlibid.s @@ -1,12 +1,12 @@ /* Provide a weak definition of the library ID, for the benefit of certain configure scripts. - Copyright (C) 2005, 2008 Free Software Foundation, Inc. + Copyright (C) 2005, 2008, 2009 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) +the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, @@ -14,16 +14,14 @@ 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. */ +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. -/* As a special exception, if you link this library with files - compiled with GCC to produce an executable, this does not cause - the resulting executable to be covered by the GNU General Public License. - This exception does not however invalidate any other reasons why - the executable file might be covered by the GNU General Public License. */ +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ .ident "GNU C crtlibid.o" diff --git a/gcc/config/bfin/crtn.s b/gcc/config/bfin/crtn.s index 7c436252f66..7fcd27bfade 100644 --- a/gcc/config/bfin/crtn.s +++ b/gcc/config/bfin/crtn.s @@ -1,13 +1,13 @@ /* Specialized code needed to support construction and destruction of file-scope objects in C++ and Java code, and to support exception handling. - Copyright (C) 2005, 2008 Free Software Foundation, Inc. + Copyright (C) 2005, 2008, 2009 Free Software Foundation, Inc. Contributed by Analog Devices. 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) +the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, @@ -15,16 +15,14 @@ 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. */ +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. -/* As a special exception, if you link this library with files - compiled with GCC to produce an executable, this does not cause - the resulting executable to be covered by the GNU General Public License. - This exception does not however invalidate any other reasons why - the executable file might be covered by the GNU General Public License. */ +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ /* * This file supplies function epilogues for the .init and .fini sections. diff --git a/gcc/config/bfin/elf.h b/gcc/config/bfin/elf.h index 9a2ec01cb89..975212faa23 100644 --- a/gcc/config/bfin/elf.h +++ b/gcc/config/bfin/elf.h @@ -1,3 +1,26 @@ +/* Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + #undef STARTFILE_SPEC #define STARTFILE_SPEC "\ %{msim:%{!shared:crt0%O%s}} \ diff --git a/gcc/config/bfin/lib1funcs.asm b/gcc/config/bfin/lib1funcs.asm index c8d7fe855cf..4e15ad23068 100644 --- a/gcc/config/bfin/lib1funcs.asm +++ b/gcc/config/bfin/lib1funcs.asm @@ -1,12 +1,12 @@ /* libgcc functions for Blackfin. - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2009 Free Software Foundation, Inc. Contributed by Analog Devices. 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) +the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, @@ -14,17 +14,14 @@ 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. */ - -/* As a special exception, if you link this library with files - compiled with GCC to produce an executable, this does not cause - the resulting executable to be covered by the GNU General Public License. - This exception does not however invalidate any other reasons why - the executable file might be covered by the GNU General Public License. */ +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ #ifdef L_divsi3 .text diff --git a/gcc/config/bfin/libgcc-bfin.ver b/gcc/config/bfin/libgcc-bfin.ver index 1afb78e9c82..a10a0f0a6ef 100644 --- a/gcc/config/bfin/libgcc-bfin.ver +++ b/gcc/config/bfin/libgcc-bfin.ver @@ -1,3 +1,22 @@ +# Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, +# 2007 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 3, 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 COPYING3. If not see +# <http://www.gnu.org/licenses/>. + GCC_3.0 { # libgcc1 integer symbols ___absvsi2 diff --git a/gcc/config/bfin/linux-unwind.h b/gcc/config/bfin/linux-unwind.h index c3697114721..88c8285632d 100644 --- a/gcc/config/bfin/linux-unwind.h +++ b/gcc/config/bfin/linux-unwind.h @@ -1,30 +1,26 @@ /* DWARF2 EH unwinding support for Blackfin. - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2007, 2009 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) +the Free Software Foundation; either version 3, 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 with other programs, and to distribute -those programs 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 another program.) - 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. */ +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ /* Do code reading to identify a signal frame, and set the frame state data appropriately. See unwind-dw2.c for the structs. diff --git a/gcc/config/bfin/linux.h b/gcc/config/bfin/linux.h index b786dcb6fff..5c716cd67f7 100644 --- a/gcc/config/bfin/linux.h +++ b/gcc/config/bfin/linux.h @@ -1,3 +1,26 @@ +/* Copyright (C) 2007, 2008 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + #undef SUBTARGET_DRIVER_SELF_SPECS #define SUBTARGET_DRIVER_SELF_SPECS \ "%{!mno-fdpic:-mfdpic} -micplb", @@ -26,3 +49,6 @@ %{static}} -init __init -fini __fini" #define MD_UNWIND_SUPPORT "config/bfin/linux-unwind.h" + +#undef TARGET_SUPPORTS_SYNC_CALLS +#define TARGET_SUPPORTS_SYNC_CALLS 1 diff --git a/gcc/config/bfin/predicates.md b/gcc/config/bfin/predicates.md index 7aac5b0534c..84bf5919509 100644 --- a/gcc/config/bfin/predicates.md +++ b/gcc/config/bfin/predicates.md @@ -59,6 +59,14 @@ (and (match_code "const_int") (match_test "op == const0_rtx || op == const1_rtx"))) +(define_predicate "const1_operand" + (and (match_code "const_int") + (match_test "op == const1_rtx"))) + +(define_predicate "const3_operand" + (and (match_code "const_int") + (match_test "INTVAL (op) == 3"))) + (define_predicate "vec_shift_operand" (ior (and (match_code "const_int") (match_test "INTVAL (op) >= -16 && INTVAL (op) < 15")) @@ -80,6 +88,14 @@ (and (match_code "reg") (match_test "D_REGNO_P (REGNO (op))"))) +(define_predicate "p_register_operand" + (and (match_code "reg") + (match_test "P_REGNO_P (REGNO (op))"))) + +(define_predicate "dp_register_operand" + (and (match_code "reg") + (match_test "D_REGNO_P (REGNO (op)) || P_REGNO_P (REGNO (op))"))) + ;; Return nonzero if OP is a LC register. (define_predicate "lc_register_operand" (and (match_code "reg") @@ -172,14 +188,22 @@ && REGNO (op) <= LAST_VIRTUAL_REGISTER)); }) -;; Test for an operator valid in a conditional branch -(define_predicate "bfin_cbranch_operator" +;; Test for an operator valid in a BImode conditional branch +(define_predicate "bfin_bimode_comparison_operator" (match_code "eq,ne")) -;; The following two are used to compute the addrtype attribute. They return +;; Test for an operator whose result is accessible with movbisi. +(define_predicate "bfin_direct_comparison_operator" + (match_code "eq,lt,le,leu,ltu")) + +;; The following three are used to compute the addrtype attribute. They return ;; true if passed a memory address usable for a 16-bit load or store using a ;; P or I register, respectively. If neither matches, we know we have a ;; 32-bit instruction. +;; We subdivide the P case into normal P registers, and SP/FP. We can assume +;; that speculative loads through SP and FP are no problem, so this has +;; an effect on the anomaly workaround code. + (define_predicate "mem_p_address_operand" (match_code "mem") { @@ -189,7 +213,19 @@ if (GET_CODE (op) == PLUS || GET_RTX_CLASS (GET_CODE (op)) == RTX_AUTOINC) op = XEXP (op, 0); gcc_assert (REG_P (op)); - return PREG_P (op); + return PREG_P (op) && op != stack_pointer_rtx && op != frame_pointer_rtx; +}) + +(define_predicate "mem_spfp_address_operand" + (match_code "mem") +{ + if (effective_address_32bit_p (op, mode)) + return 0; + op = XEXP (op, 0); + if (GET_CODE (op) == PLUS || GET_RTX_CLASS (GET_CODE (op)) == RTX_AUTOINC) + op = XEXP (op, 0); + gcc_assert (REG_P (op)); + return op == stack_pointer_rtx || op == frame_pointer_rtx; }) (define_predicate "mem_i_address_operand" diff --git a/gcc/config/bfin/sync.md b/gcc/config/bfin/sync.md new file mode 100644 index 00000000000..7025af4979d --- /dev/null +++ b/gcc/config/bfin/sync.md @@ -0,0 +1,178 @@ +;; GCC machine description for Blackfin synchronization instructions. +;; Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc. +;; Contributed by Analog Devices. +;; +;; 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 3, 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 COPYING3. If not see +;; <http://www.gnu.org/licenses/>. + +(define_code_iterator FETCHOP [plus minus ior and xor]) +(define_code_attr fetchop_name + [(plus "add") (minus "sub") (ior "ior") (and "and") (xor "xor")]) +(define_code_attr fetchop_addr + [(plus "1072") (minus "1088") (ior "1104") (and "1120") (xor "1136")]) + +(define_insn "sync_<fetchop_name>si_internal" + [(set (mem:SI (match_operand:SI 0 "register_operand" "qA")) + (unspec:SI + [(FETCHOP:SI (mem:SI (match_dup 0)) + (match_operand:SI 1 "register_operand" "q0")) + (match_operand:SI 2 "register_no_elim_operand" "a")] + UNSPEC_ATOMIC)) + (clobber (match_scratch:SI 3 "=q0")) + (clobber (match_scratch:SI 4 "=q1")) + (clobber (reg:SI REG_RETS))] + "TARGET_SUPPORTS_SYNC_CALLS" + "call (%2);" + [(set_attr "type" "call")]) + +(define_expand "sync_<fetchop_name>si" + [(parallel + [(set (match_operand:SI 0 "memory_operand" "+m") + (unspec:SI + [(FETCHOP:SI (match_dup 0) + (match_operand:SI 1 "register_operand" "q0")) + (match_dup 2)] + UNSPEC_ATOMIC)) + (clobber (match_scratch:SI 3 "")) + (clobber (match_scratch:SI 4 "")) + (clobber (reg:SI REG_RETS))])] + "TARGET_SUPPORTS_SYNC_CALLS" +{ + if (!REG_P (XEXP (operands[0], 0))) + { + operands[0] = shallow_copy_rtx (operands[0]); + XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0)); + } + operands[2] = force_reg (Pmode, GEN_INT (<fetchop_addr>)); +}) + +(define_insn "sync_old_<fetchop_name>si_internal" + [(set (match_operand:SI 0 "register_operand" "=q1") + (mem:SI (match_operand:SI 1 "register_operand" "qA"))) + (set (mem:SI (match_dup 1)) + (unspec:SI + [(FETCHOP:SI (mem:SI (match_dup 1)) + (match_operand:SI 2 "register_operand" "q0")) + (match_operand:SI 3 "register_no_elim_operand" "a")] + UNSPEC_ATOMIC)) + (clobber (match_scratch:SI 4 "=q0")) + (clobber (reg:SI REG_RETS))] + "TARGET_SUPPORTS_SYNC_CALLS" + "call (%3);" + [(set_attr "type" "call")]) + +(define_expand "sync_old_<fetchop_name>si" + [(parallel + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "memory_operand" "")) + (set (match_dup 1) + (unspec:SI + [(FETCHOP:SI (match_dup 1) + (match_operand:SI 2 "register_operand" "")) + (match_dup 3)] + UNSPEC_ATOMIC)) + (clobber (match_scratch:SI 4 "")) + (clobber (reg:SI REG_RETS))])] + "TARGET_SUPPORTS_SYNC_CALLS" +{ + if (!REG_P (XEXP (operands[1], 0))) + { + operands[1] = shallow_copy_rtx (operands[1]); + XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0)); + } + operands[3] = force_reg (Pmode, GEN_INT (<fetchop_addr>)); +}) + +(define_insn "sync_new_<fetchop_name>si_internal" + [(set (match_operand:SI 0 "register_operand" "=q0") + (unspec:SI + [(FETCHOP:SI + (mem:SI (match_operand:SI 1 "register_operand" "qA")) + (match_operand:SI 2 "register_operand" "q0")) + (match_operand:SI 3 "register_no_elim_operand" "a")] + UNSPEC_ATOMIC)) + (set (mem:SI (match_dup 1)) + (unspec:SI + [(FETCHOP:SI (mem:SI (match_dup 1)) (match_dup 2)) + (match_dup 3)] + UNSPEC_ATOMIC)) + (clobber (match_scratch:SI 4 "=q1")) + (clobber (reg:SI REG_RETS))] + "TARGET_SUPPORTS_SYNC_CALLS" + "call (%3);" + [(set_attr "type" "call")]) + +(define_expand "sync_new_<fetchop_name>si" + [(parallel + [(set (match_operand:SI 0 "register_operand" "") + (unspec:SI + [(FETCHOP:SI (match_operand:SI 1 "memory_operand" "") + (match_operand:SI 2 "register_operand" "")) + (match_dup 3)] + UNSPEC_ATOMIC)) + (set (match_dup 1) + (unspec:SI + [(FETCHOP:SI (match_dup 1) (match_dup 2)) + (match_dup 3)] + UNSPEC_ATOMIC)) + (clobber (match_scratch:SI 4 "")) + (clobber (reg:SI REG_RETS))])] + "TARGET_SUPPORTS_SYNC_CALLS" +{ + if (!REG_P (XEXP (operands[1], 0))) + { + operands[1] = shallow_copy_rtx (operands[1]); + XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0)); + } + operands[3] = force_reg (Pmode, GEN_INT (<fetchop_addr>)); +}) + +(define_insn "sync_compare_and_swapsi_internal" + [(set (match_operand:SI 0 "register_operand" "=q0") + (mem:SI (match_operand:SI 1 "register_operand" "qA"))) + (set (mem:SI (match_dup 1)) + (unspec:SI + [(mem:SI (match_dup 1)) + (match_operand:SI 2 "register_operand" "q1") + (match_operand:SI 3 "register_operand" "q2") + (match_operand:SI 4 "register_no_elim_operand" "a")] + UNSPEC_ATOMIC)) + (clobber (reg:SI REG_RETS))] + "TARGET_SUPPORTS_SYNC_CALLS" + "call (%4);" + [(set_attr "type" "call")]) + +(define_expand "sync_compare_and_swapsi" + [(parallel + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "memory_operand" "")) + (set (match_dup 1) + (unspec:SI + [(match_dup 1) + (match_operand:SI 2 "register_operand" "") + (match_operand:SI 3 "register_operand" "") + (match_dup 4)] + UNSPEC_ATOMIC)) + (clobber (reg:SI REG_RETS))])] + "TARGET_SUPPORTS_SYNC_CALLS" +{ + if (!REG_P (XEXP (operands[1], 0))) + { + operands[1] = shallow_copy_rtx (operands[1]); + XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0)); + } + operands[4] = force_reg (Pmode, GEN_INT (0x420)); +}) diff --git a/gcc/config/bfin/t-bfin b/gcc/config/bfin/t-bfin index 566f3e111bd..37b6871c1dc 100644 --- a/gcc/config/bfin/t-bfin +++ b/gcc/config/bfin/t-bfin @@ -1,3 +1,21 @@ +# Copyright (C) 2005, 2007 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 3, 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 COPYING3. If not see +# <http://www.gnu.org/licenses/>. + ## Target part of the Makefile LIB1ASMSRC = bfin/lib1funcs.asm diff --git a/gcc/config/bfin/t-bfin-elf b/gcc/config/bfin/t-bfin-elf index b5606e7bb75..39209f628ef 100644 --- a/gcc/config/bfin/t-bfin-elf +++ b/gcc/config/bfin/t-bfin-elf @@ -1,3 +1,21 @@ +# Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, 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 COPYING3. If not see +# <http://www.gnu.org/licenses/>. + ## Target part of the Makefile LIB1ASMSRC = bfin/lib1funcs.asm @@ -30,8 +48,15 @@ MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf531-none mcpu?bf532-none=mcpu?bf533-non MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf534-none mcpu?bf532-none=mcpu?bf536-none MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf537-none mcpu?bf532-none=mcpu?bf538-none MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf539-none mcpu?bf532-none=mcpu?bf542-none -MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf544-none mcpu?bf532-none=mcpu?bf547-none -MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf548-none mcpu?bf532-none=mcpu?bf549-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf542m-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf544-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf544m-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf547-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf547m-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf548-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf548m-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf549-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf549m-none MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf561-none MULTILIB_EXCEPTIONS=mleaf-id-shared-library* diff --git a/gcc/config/bfin/t-bfin-linux b/gcc/config/bfin/t-bfin-linux index c8c03d69e28..f7ba9550128 100644 --- a/gcc/config/bfin/t-bfin-linux +++ b/gcc/config/bfin/t-bfin-linux @@ -1,3 +1,21 @@ +# Copyright (C) 2007, 2008 Free Software Foundation, Inc. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, 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 COPYING3. If not see +# <http://www.gnu.org/licenses/>. + ## Target part of the Makefile LIB1ASMSRC = bfin/lib1funcs.asm @@ -29,8 +47,15 @@ MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf531-none mcpu?bf532-none=mcpu?bf533-non MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf534-none mcpu?bf532-none=mcpu?bf536-none MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf537-none mcpu?bf532-none=mcpu?bf538-none MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf539-none mcpu?bf532-none=mcpu?bf542-none -MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf544-none mcpu?bf532-none=mcpu?bf547-none -MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf548-none mcpu?bf532-none=mcpu?bf549-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf542m-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf544-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf544m-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf547-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf547m-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf548-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf548m-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf549-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf549m-none MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf561-none SHLIB_MAPFILES=$(srcdir)/config/bfin/libgcc-bfin.ver diff --git a/gcc/config/bfin/t-bfin-uclinux b/gcc/config/bfin/t-bfin-uclinux index d075d6b5e65..eb6d2253eb0 100644 --- a/gcc/config/bfin/t-bfin-uclinux +++ b/gcc/config/bfin/t-bfin-uclinux @@ -1,3 +1,21 @@ +# Copyright (C) 2007, 2008 Free Software Foundation, Inc. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, 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 COPYING3. If not see +# <http://www.gnu.org/licenses/>. + ## Target part of the Makefile LIB1ASMSRC = bfin/lib1funcs.asm @@ -30,8 +48,15 @@ MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf531-none mcpu?bf532-none=mcpu?bf533-non MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf534-none mcpu?bf532-none=mcpu?bf536-none MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf537-none mcpu?bf532-none=mcpu?bf538-none MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf539-none mcpu?bf532-none=mcpu?bf542-none -MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf544-none mcpu?bf532-none=mcpu?bf547-none -MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf548-none mcpu?bf532-none=mcpu?bf549-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf542m-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf544-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf544m-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf547-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf547m-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf548-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf548m-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf549-none +MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf549m-none MULTILIB_MATCHES+=mcpu?bf532-none=mcpu?bf561-none MULTILIB_EXCEPTIONS=mleaf-id-shared-library* diff --git a/gcc/config/bfin/uclinux.h b/gcc/config/bfin/uclinux.h index 041f2eea851..6001b23645b 100644 --- a/gcc/config/bfin/uclinux.h +++ b/gcc/config/bfin/uclinux.h @@ -1,3 +1,26 @@ +/* Copyright (C) 2005, 2006, 2007 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 3, 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + #undef STARTFILE_SPEC #define STARTFILE_SPEC \ "%{!shared: crt1%O%s} crti%O%s crtbegin%O%s crtlibid%O%s" @@ -13,3 +36,6 @@ --wrap=mmap --wrap=munmap --wrap=alloca\ %{fmudflapth: --wrap=pthread_create\ }} %{fmudflap|fmudflapth: --wrap=main}" + +#undef TARGET_SUPPORTS_SYNC_CALLS +#define TARGET_SUPPORTS_SYNC_CALLS 1 |