summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog15
-rw-r--r--gcc/config.gcc11
-rw-r--r--gcc/config/arm/aout.h71
-rw-r--r--gcc/config/arm/arm-protos.h6
-rw-r--r--gcc/config/arm/arm.c389
-rw-r--r--gcc/config/arm/arm.h126
-rw-r--r--gcc/config/arm/arm.md169
-rw-r--r--gcc/config/arm/t-arm-elf4
-rw-r--r--gcc/doc/invoke.texi17
9 files changed, 746 insertions, 62 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 4b08a6310b1..7bd777971a8 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,18 @@
+2003-02-10 Nick Clifton <nickc@redhat.com>
+
+ * Contributed support for the Cirrus EP9312 "Maverick"
+ floating point co-processor. Written by Aldy Hernandez
+ <aldyh@redhat.com>.
+ (config/arm/arm.c): Add Cirrus support.
+ (config/arm/arm.h): Likewise.
+ (config/arm/aout.h): Likewise.
+ (config/arm/arm.md): Likewise.
+ (config/arm/arm-protos.h): Likewise.
+ (config.gcc): Likewise.
+ (doc/invoke.texi): Describe new -mcpu value and new
+ -mcirrus-fix-invalid-insns switch,
+ (cirrus.md): New file.
+
Mon Feb 10 11:40:18 CET 2003 Jan Hubicka <jh@suse.cz>
* combine.c (combine_simplify_rtx): Simplify using
diff --git a/gcc/config.gcc b/gcc/config.gcc
index 2b8d0b506f7..b76fbd8326f 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -259,6 +259,9 @@ strongarm*-*-*)
arm*-*-*)
cpu_type=arm
;;
+ep9312*-*-*)
+ cpu_type=arm
+ ;;
xscale-*-*)
cpu_type=arm
;;
@@ -700,7 +703,7 @@ arm*-*-rtems*)
thread_file='rtems'
fi
;;
-arm*-*-elf)
+arm*-*-elf | ep9312-*-elf)
tm_file="dbxelf.h elfos.h arm/unknown-elf.h arm/elf.h arm/aout.h arm/arm.h"
tmake_file=arm/t-arm-elf
;;
@@ -2789,6 +2792,7 @@ arm*-*-*)
| xarm7m | xarm7dm | xarm7dmi | xarm[79]tdmi \
| xarm7100 | xarm7500 | xarm7500fe | xarm810 \
| xxscale \
+ | xep9312 \
| xstrongarm | xstrongarm110 | xstrongarm1100)
target_cpu_default2="TARGET_CPU_$with_cpu"
;;
@@ -2806,6 +2810,11 @@ arm*-*-*)
fi
;;
esac
+ case $machine in
+ 9ep9312-*-*)
+ target_cpu_default2="TARGET_CPU_9ep9312"
+ ;;
+ esac
;;
hppa*-*-* | parisc*-*-*)
diff --git a/gcc/config/arm/aout.h b/gcc/config/arm/aout.h
index a142ae11944..6d6e908951b 100644
--- a/gcc/config/arm/aout.h
+++ b/gcc/config/arm/aout.h
@@ -73,7 +73,10 @@ Boston, MA 02111-1307, USA. */
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
"r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc", \
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
- "cc", "sfp", "afp" \
+ "cc", "sfp", "afp", \
+ "mv0", "mv1", "mv2", "mv3", "mv4", "mv5", \
+ "mv6", "mv7", "mv8", "mv9", "mv10", "mv11",\
+ "mv12", "mv13", "mv14", "mv15" \
}
#endif
@@ -98,7 +101,71 @@ Boston, MA 02111-1307, USA. */
{"r12", 12}, /* ip */ \
{"r13", 13}, /* sp */ \
{"r14", 14}, /* lr */ \
- {"r15", 15} /* pc */ \
+ {"r15", 15}, /* pc */ \
+ {"mvf0", 27}, \
+ {"mvf1", 28}, \
+ {"mvf2", 29}, \
+ {"mvf3", 30}, \
+ {"mvf4", 31}, \
+ {"mvf5", 32}, \
+ {"mvf6", 33}, \
+ {"mvf7", 34}, \
+ {"mvf8", 35}, \
+ {"mvf9", 36}, \
+ {"mvf10", 37}, \
+ {"mvf11", 38}, \
+ {"mvf12", 39}, \
+ {"mvf13", 40}, \
+ {"mvf14", 41}, \
+ {"mvf15", 42}, \
+ {"mvd0", 27}, \
+ {"mvd1", 28}, \
+ {"mvd2", 29}, \
+ {"mvd3", 30}, \
+ {"mvd4", 31}, \
+ {"mvd5", 32}, \
+ {"mvd6", 33}, \
+ {"mvd7", 34}, \
+ {"mvd8", 35}, \
+ {"mvd9", 36}, \
+ {"mvd10", 37}, \
+ {"mvd11", 38}, \
+ {"mvd12", 39}, \
+ {"mvd13", 40}, \
+ {"mvd14", 41}, \
+ {"mvd15", 42}, \
+ {"mvfx0", 27}, \
+ {"mvfx1", 28}, \
+ {"mvfx2", 29}, \
+ {"mvfx3", 30}, \
+ {"mvfx4", 31}, \
+ {"mvfx5", 32}, \
+ {"mvfx6", 33}, \
+ {"mvfx7", 34}, \
+ {"mvfx8", 35}, \
+ {"mvfx9", 36}, \
+ {"mvfx10", 37}, \
+ {"mvfx11", 38}, \
+ {"mvfx12", 39}, \
+ {"mvfx13", 40}, \
+ {"mvfx14", 41}, \
+ {"mvfx15", 42}, \
+ {"mvdx0", 27}, \
+ {"mvdx1", 28}, \
+ {"mvdx2", 29}, \
+ {"mvdx3", 30}, \
+ {"mvdx4", 31}, \
+ {"mvdx5", 32}, \
+ {"mvdx6", 33}, \
+ {"mvdx7", 34}, \
+ {"mvdx8", 35}, \
+ {"mvdx9", 36}, \
+ {"mvdx10", 37}, \
+ {"mvdx11", 38}, \
+ {"mvdx12", 39}, \
+ {"mvdx13", 40}, \
+ {"mvdx14", 41}, \
+ {"mvdx15", 42} \
}
#endif
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 8923dd02452..0d0dba22a6c 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -94,6 +94,11 @@ extern int logical_binary_operator PARAMS ((rtx, enum machine_mode));
extern int multi_register_push PARAMS ((rtx, enum machine_mode));
extern int load_multiple_operation PARAMS ((rtx, enum machine_mode));
extern int store_multiple_operation PARAMS ((rtx, enum machine_mode));
+extern int cirrus_fp_register PARAMS ((rtx, enum machine_mode));
+extern int cirrus_general_operand PARAMS ((rtx, enum machine_mode));
+extern int cirrus_register_operand PARAMS ((rtx, enum machine_mode));
+extern int cirrus_shift_const PARAMS ((rtx, enum machine_mode));
+extern int cirrus_memory_offset PARAMS ((rtx));
extern int symbol_mentioned_p PARAMS ((rtx));
extern int label_mentioned_p PARAMS ((rtx));
@@ -149,7 +154,6 @@ extern rtx arm_va_arg PARAMS ((tree, tree));
extern int arm_function_arg_pass_by_reference PARAMS ((CUMULATIVE_ARGS *,
enum machine_mode,
tree, int));
-
#endif
#if defined AOF_ASSEMBLER
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index e59f461fbea..c1a6f2f7406 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -62,6 +62,12 @@ typedef struct minipool_fixup Mfix;
#define Ulong unsigned long
#define Ccstar const char *
+const char extra_reg_names1[][16] =
+{ "mv0", "mv1", "mv2", "mv3", "mv4", "mv5", "mv6", "mv7",
+ "mv8", "mv9", "mv10", "mv11", "mv12", "mv13", "mv14", "mv15"
+};
+#define extra_reg_names1 bogus1_regnames
+
const struct attribute_spec arm_attribute_table[];
/* Forward function declarations. */
@@ -144,6 +150,9 @@ static int arm_rtx_costs_1 PARAMS ((rtx, enum rtx_code,
enum rtx_code));
static bool arm_rtx_costs PARAMS ((rtx, int, int, int*));
static int arm_address_cost PARAMS ((rtx));
+static int is_load_address PARAMS ((rtx));
+static int is_cirrus_insn PARAMS ((rtx));
+static void cirrus_reorg PARAMS ((rtx));
#undef Hint
#undef Mmode
@@ -263,6 +272,7 @@ int arm_structure_size_boundary = DEFAULT_STRUCTURE_SIZE_BOUNDARY;
#define FL_STRONG (1 << 8) /* StrongARM */
#define FL_ARCH5E (1 << 9) /* DSP extensions to v5 */
#define FL_XSCALE (1 << 10) /* XScale */
+#define FL_CIRRUS (1 << 11) /* Cirrus/DSP. */
/* The bits in this mask specify which
instructions we are allowed to generate. */
@@ -301,6 +311,9 @@ int arm_is_xscale = 0;
/* Nonzero if this chip is an ARM6 or an ARM7. */
int arm_is_6_or_7 = 0;
+/* Nonzero if this chip is a Cirrus/DSP. */
+int arm_is_cirrus = 0;
+
/* Nonzero if generating Thumb instructions. */
int thumb_code = 0;
@@ -391,6 +404,7 @@ static const struct processors all_cores[] =
{"arm940t", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
{"arm9tdmi", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
{"arm9e", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED },
+ {"ep9312", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_CIRRUS },
{"strongarm", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_STRONG },
{"strongarm110", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_STRONG },
{"strongarm1100", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_STRONG },
@@ -417,6 +431,7 @@ static const struct processors all_architectures[] =
{ "armv5", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 },
{ "armv5t", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 },
{ "armv5te", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 | FL_ARCH5E },
+ { "ep9312", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_CIRRUS },
{ NULL, 0 }
};
@@ -514,6 +529,7 @@ arm_override_options ()
{ TARGET_CPU_arm9, "arm9" },
{ TARGET_CPU_strongarm, "strongarm" },
{ TARGET_CPU_xscale, "xscale" },
+ { TARGET_CPU_ep9312, "ep9312" },
{ TARGET_CPU_generic, "arm" },
{ 0, 0 }
};
@@ -712,13 +728,23 @@ arm_override_options ()
thumb_code = (TARGET_ARM == 0);
arm_is_6_or_7 = (((tune_flags & (FL_MODE26 | FL_MODE32))
&& !(tune_flags & FL_ARCH4))) != 0;
+ arm_is_cirrus = (tune_flags & FL_CIRRUS) != 0;
- /* Default value for floating point code... if no co-processor
- bus, then schedule for emulated floating point. Otherwise,
- assume the user has an FPA.
- Note: this does not prevent use of floating point instructions,
- -msoft-float does that. */
- arm_fpu = (tune_flags & FL_CO_PROC) ? FP_HARD : FP_SOFT3;
+ if (arm_is_cirrus)
+ {
+ arm_fpu = FP_CIRRUS;
+
+ /* Ignore -mhard-float if -mcpu=ep9312. */
+ if (TARGET_HARD_FLOAT)
+ target_flags ^= ARM_FLAG_SOFT_FLOAT;
+ }
+ else
+ /* Default value for floating point code... if no co-processor
+ bus, then schedule for emulated floating point. Otherwise,
+ assume the user has an FPA.
+ Note: this does not prevent use of floating point instructions,
+ -msoft-float does that. */
+ arm_fpu = (tune_flags & FL_CO_PROC) ? FP_HARD : FP_SOFT3;
if (target_fp_name)
{
@@ -733,8 +759,15 @@ arm_override_options ()
else
arm_fpu_arch = FP_DEFAULT;
- if (TARGET_FPE && arm_fpu != FP_HARD)
+ if (TARGET_FPE)
+ {
+ if (arm_fpu == FP_SOFT3)
+ arm_fpu = FP_SOFT2;
+ else if (arm_fpu == FP_CIRRUS)
+ warning ("-mpfpe switch not supported by ep9312 target cpu - ignored.");
+ else if (arm_fpu != FP_HARD)
arm_fpu = FP_SOFT2;
+ }
/* For arm2/3 there is no need to do any scheduling if there is only
a floating point emulator, or we are doing software floating-point. */
@@ -1902,6 +1935,8 @@ arm_return_in_memory (type)
int
arm_float_words_big_endian ()
{
+ if (TARGET_CIRRUS)
+ return 0;
/* For FPA, float words are always big-endian. For VFP, floats words
follow the memory system mode. */
@@ -2688,6 +2723,12 @@ arm_legitimate_index_p (mode, index, strict_p)
&& INTVAL (index) > -1024
&& (INTVAL (index) & 3) == 0);
+ if (TARGET_CIRRUS
+ && (GET_MODE_CLASS (mode) == MODE_FLOAT || mode == DImode))
+ return (code == CONST_INT
+ && INTVAL (index) < 255
+ && INTVAL (index) > -255);
+
if (arm_address_register_rtx_p (index, strict_p)
&& GET_MODE_SIZE (mode) <= 4)
return 1;
@@ -3856,6 +3897,262 @@ fpu_add_operand (op, mode)
return FALSE;
}
+/* Return nonzero if OP is a valid Cirrus memory address pattern. */
+
+int
+cirrus_memory_offset (op)
+ rtx op;
+{
+ /* Reject eliminable registers. */
+ if (! (reload_in_progress || reload_completed)
+ && ( reg_mentioned_p (frame_pointer_rtx, op)
+ || reg_mentioned_p (arg_pointer_rtx, op)
+ || reg_mentioned_p (virtual_incoming_args_rtx, op)
+ || reg_mentioned_p (virtual_outgoing_args_rtx, op)
+ || reg_mentioned_p (virtual_stack_dynamic_rtx, op)
+ || reg_mentioned_p (virtual_stack_vars_rtx, op)))
+ return 0;
+
+ if (GET_CODE (op) == MEM)
+ {
+ rtx ind;
+
+ ind = XEXP (op, 0);
+
+ /* Match: (mem (reg)). */
+ if (GET_CODE (ind) == REG)
+ return 1;
+
+ /* Match:
+ (mem (plus (reg)
+ (const))). */
+ if (GET_CODE (ind) == PLUS
+ && GET_CODE (XEXP (ind, 0)) == REG
+ && REG_MODE_OK_FOR_BASE_P (XEXP (ind, 0), VOIDmode)
+ && GET_CODE (XEXP (ind, 1)) == CONST_INT)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Return nonzero if OP is a Cirrus or general register. */
+
+int
+cirrus_register_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (GET_MODE (op) != mode && mode != VOIDmode)
+ return FALSE;
+
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+
+ return (GET_CODE (op) == REG
+ && (REGNO_REG_CLASS (REGNO (op)) == CIRRUS_REGS
+ || REGNO_REG_CLASS (REGNO (op)) == GENERAL_REGS));
+}
+
+/* Return nonzero if OP is a cirrus FP register. */
+
+int
+cirrus_fp_register (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (GET_MODE (op) != mode && mode != VOIDmode)
+ return FALSE;
+
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+
+ return (GET_CODE (op) == REG
+ && (REGNO (op) >= FIRST_PSEUDO_REGISTER
+ || REGNO_REG_CLASS (REGNO (op)) == CIRRUS_REGS));
+}
+
+/* Return nonzero if OP is a 6bit constant (0..63). */
+
+int
+cirrus_shift_const (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return (GET_CODE (op) == CONST_INT
+ && INTVAL (op) >= 0
+ && INTVAL (op) < 64);
+}
+
+/* Return nonzero if INSN is an LDR R0,ADDR instruction. */
+
+static int
+is_load_address (insn)
+ rtx insn;
+{
+ rtx body, lhs, rhs;;
+
+ if (!insn)
+ return 0;
+
+ if (GET_CODE (insn) != INSN)
+ return 0;
+
+ body = PATTERN (insn);
+
+ if (GET_CODE (body) != SET)
+ return 0;
+
+ lhs = XEXP (body, 0);
+ rhs = XEXP (body, 1);
+
+ return (GET_CODE (lhs) == REG
+ && REGNO_REG_CLASS (REGNO (lhs)) == GENERAL_REGS
+ && (GET_CODE (rhs) == MEM
+ || GET_CODE (rhs) == SYMBOL_REF));
+}
+
+/* Return nonzero if INSN is a Cirrus instruction. */
+
+static int
+is_cirrus_insn (insn)
+ rtx insn;
+{
+ enum attr_cirrus attr;
+
+ /* get_attr aborts on USE and CLOBBER. */
+ if (!insn
+ || GET_CODE (insn) != INSN
+ || GET_CODE (PATTERN (insn)) == USE
+ || GET_CODE (PATTERN (insn)) == CLOBBER)
+ return 0;
+
+ attr = get_attr_cirrus (insn);
+
+ return attr != CIRRUS_NO;
+}
+
+/* Cirrus reorg for invalid instruction combinations. */
+
+static void
+cirrus_reorg (first)
+ rtx first;
+{
+ enum attr_cirrus attr;
+ rtx body = PATTERN (first);
+ rtx t;
+ int nops;
+
+ /* Any branch must be followed by 2 non Cirrus instructions. */
+ if (GET_CODE (first) == JUMP_INSN && GET_CODE (body) != RETURN)
+ {
+ nops = 0;
+ t = next_nonnote_insn (first);
+
+ if (is_cirrus_insn (t))
+ ++ nops;
+
+ if (is_cirrus_insn (next_nonnote_insn (t)))
+ ++ nops;
+
+ while (nops --)
+ emit_insn_after (gen_nop (), first);
+
+ return;
+ }
+
+ /* (float (blah)) is in parallel with a clobber. */
+ if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
+ body = XVECEXP (body, 0, 0);
+
+ if (GET_CODE (body) == SET)
+ {
+ rtx lhs = XEXP (body, 0), rhs = XEXP (body, 1);
+
+ /* cfldrd, cfldr64, cfstrd, cfstr64 must
+ be followed by a non Cirrus insn. */
+ if (get_attr_cirrus (first) == CIRRUS_DOUBLE)
+ {
+ if (is_cirrus_insn (next_nonnote_insn (first)))
+ emit_insn_after (gen_nop (), first);
+
+ return;
+ }
+ else if (is_load_address (first))
+ {
+ unsigned int arm_regno;
+
+ /* Any ldr/cfmvdlr, ldr/cfmvdhr, ldr/cfmvsr, ldr/cfmv64lr,
+ ldr/cfmv64hr combination where the Rd field is the same
+ in both instructions must be split with a non Cirrus
+ insn. Example:
+
+ ldr r0, blah
+ nop
+ cfmvsr mvf0, r0. */
+
+ /* Get Arm register number for ldr insn. */
+ if (GET_CODE (lhs) == REG)
+ arm_regno = REGNO (lhs);
+ else if (GET_CODE (rhs) == REG)
+ arm_regno = REGNO (rhs);
+ else
+ abort ();
+
+ /* Next insn. */
+ first = next_nonnote_insn (first);
+
+ if (!is_cirrus_insn (first))
+ return;
+
+ body = PATTERN (first);
+
+ /* (float (blah)) is in parallel with a clobber. */
+ if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0))
+ body = XVECEXP (body, 0, 0);
+
+ if (GET_CODE (body) == FLOAT)
+ body = XEXP (body, 0);
+
+ if (get_attr_cirrus (first) == CIRRUS_MOVE
+ && GET_CODE (XEXP (body, 1)) == REG
+ && arm_regno == REGNO (XEXP (body, 1)))
+ emit_insn_after (gen_nop (), first);
+
+ return;
+ }
+ }
+
+ /* get_attr aborts on USE and CLOBBER. */
+ if (!first
+ || GET_CODE (first) != INSN
+ || GET_CODE (PATTERN (first)) == USE
+ || GET_CODE (PATTERN (first)) == CLOBBER)
+ return;
+
+ attr = get_attr_cirrus (first);
+
+ /* Any coprocessor compare instruction (cfcmps, cfcmpd, ...)
+ must be followed by a non-coprocessor instruction. */
+ if (attr == CIRRUS_COMPARE)
+ {
+ nops = 0;
+
+ t = next_nonnote_insn (first);
+
+ if (is_cirrus_insn (t))
+ ++ nops;
+
+ if (is_cirrus_insn (next_nonnote_insn (t)))
+ ++ nops;
+
+ while (nops --)
+ emit_insn_after (gen_nop (), first);
+
+ return;
+ }
+}
+
/* Return nonzero if OP is a constant power of two. */
int
@@ -5355,6 +5652,8 @@ arm_select_cc_mode (op, x, y)
case LE:
case GT:
case GE:
+ if (TARGET_CIRRUS)
+ return CCFPmode;
return CCFPEmode;
default:
@@ -6678,6 +6977,12 @@ arm_reorg (first)
/* Scan all the insns and record the operands that will need fixing. */
for (insn = next_nonnote_insn (first); insn; insn = next_nonnote_insn (insn))
{
+ if (TARGET_CIRRUS_FIX_INVALID_INSNS
+ && (is_cirrus_insn (insn)
+ || GET_CODE (insn) == JUMP_INSN
+ || is_load_address (insn)))
+ cirrus_reorg (insn);
+
if (GET_CODE (insn) == BARRIER)
push_minipool_barrier (insn, address);
else if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN
@@ -9168,6 +9473,16 @@ arm_print_operand (stream, x, code)
fprintf (stream, "%s", arithmetic_instr (x, 1));
return;
+ /* Truncate Cirrus shift counts. */
+ case 's':
+ if (GET_CODE (x) == CONST_INT)
+ {
+ fprintf (stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0x3f);
+ return;
+ }
+ arm_print_operand (stream, x, 0);
+ return;
+
case 'I':
fprintf (stream, "%s", arithmetic_instr (x, 0));
return;
@@ -9274,6 +9589,43 @@ arm_print_operand (stream, x, code)
fputs (thumb_condition_code (x, 1), stream);
return;
+
+ /* Cirrus registers can be accessed in a variety of ways:
+ single floating point (f)
+ double floating point (d)
+ 32bit integer (fx)
+ 64bit integer (dx). */
+ case 'W': /* Cirrus register in F mode. */
+ case 'X': /* Cirrus register in D mode. */
+ case 'Y': /* Cirrus register in FX mode. */
+ case 'Z': /* Cirrus register in DX mode. */
+ if (GET_CODE (x) != REG || REGNO_REG_CLASS (REGNO (x)) != CIRRUS_REGS)
+ abort ();
+
+ fprintf (stream, "mv%s%s",
+ code == 'W' ? "f"
+ : code == 'X' ? "d"
+ : code == 'Y' ? "fx" : "dx", reg_names[REGNO (x)] + 2);
+
+ return;
+
+ /* Print cirrus register in the mode specified by the register's mode. */
+ case 'V':
+ {
+ int mode = GET_MODE (x);
+
+ if (GET_CODE (x) != REG || REGNO_REG_CLASS (REGNO (x)) != CIRRUS_REGS)
+ abort ();
+
+ fprintf (stream, "mv%s%s",
+ mode == DFmode ? "d"
+ : mode == SImode ? "fx"
+ : mode == DImode ? "dx"
+ : "f", reg_names[REGNO (x)] + 2);
+
+ return;
+ }
+
default:
if (x == 0)
abort ();
@@ -9765,6 +10117,18 @@ arm_final_prescan_insn (insn)
|| GET_CODE (scanbody) == PARALLEL)
|| get_attr_conds (this_insn) != CONDS_NOCOND)
fail = TRUE;
+
+ /* A conditional cirrus instruction must be followed by
+ a non Cirrus instruction. However, since we
+ conditionalize instructions in this function and by
+ the time we get here we can't add instructions
+ (nops), because shorten_branches() has already been
+ called, we will disable conditionalizing Cirrus
+ instructions to be safe. */
+ if (GET_CODE (scanbody) != USE
+ && GET_CODE (scanbody) != CLOBBER
+ && get_attr_cirrus (this_insn) != CIRRUS_NO)
+ fail = TRUE;
break;
default:
@@ -9848,6 +10212,14 @@ arm_hard_regno_mode_ok (regno, mode)
start of an even numbered register pair. */
return (ARM_NUM_REGS (mode) < 2) || (regno < LAST_LO_REGNUM);
+ if (IS_CIRRUS_REGNUM (regno))
+ /* We have outlawed SI values in Cirrus registers because they
+ reside in the lower 32 bits, but SF values reside in the
+ upper 32 bits. This causes gcc all sorts of grief. We can't
+ even split the registers into pairs because Cirrus SI values
+ get sign extended to 64bits-- aldyh. */
+ return (GET_MODE_CLASS (mode) == MODE_FLOAT) || (mode == DImode);
+
if (regno <= LAST_ARM_REGNUM)
/* We allow any value to be stored in the general regisetrs. */
return 1;
@@ -9887,6 +10259,9 @@ arm_regno_class (regno)
if (regno == CC_REGNUM)
return NO_REGS;
+ if (IS_CIRRUS_REGNUM (regno))
+ return CIRRUS_REGS;
+
return FPU_REGS;
}
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index 802e19986c7..5732f38c7d0 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -96,6 +96,7 @@ Boston, MA 02111-1307, USA. */
#define TARGET_CPU_arm9 0x0080
#define TARGET_CPU_arm9tdmi 0x0080
#define TARGET_CPU_xscale 0x0100
+#define TARGET_CPU_ep9312 0x0200
/* Configure didn't specify. */
#define TARGET_CPU_generic 0x8000
@@ -164,6 +165,14 @@ extern GTY(()) rtx aof_pic_label;
#if TARGET_CPU_DEFAULT == TARGET_CPU_xscale
#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_5TE__ -D__XSCALE__"
#else
+#if TARGET_CPU_DEFAULT == TARGET_CPU_ep9312
+#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_4T__ -D__MAVERICK__"
+/* Set TARGET_DEFAULT to the default, but without soft-float. */
+#ifdef TARGET_DEFAULT
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT (ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME)
+#endif /* TARGET_CPU_DEFAULT */
+#else
Unrecognized value in TARGET_CPU_DEFAULT.
#endif
#endif
@@ -171,6 +180,7 @@ Unrecognized value in TARGET_CPU_DEFAULT.
#endif
#endif
#endif
+#endif
#undef CPP_SPEC
#define CPP_SPEC "%(cpp_cpu_arch) %(subtarget_cpp_spec) \
@@ -212,6 +222,8 @@ Unrecognized value in TARGET_CPU_DEFAULT.
%{march=strongarm1100:-D__ARM_ARCH_4__} \
%{march=xscale:-D__ARM_ARCH_5TE__} \
%{march=xscale:-D__XSCALE__} \
+%{march=ep9312:-D__ARM_ARCH_4T__} \
+%{march=ep9312:-D__MAVERICK__} \
%{march=armv2:-D__ARM_ARCH_2__} \
%{march=armv2a:-D__ARM_ARCH_2__} \
%{march=armv3:-D__ARM_ARCH_3__} \
@@ -251,6 +263,8 @@ Unrecognized value in TARGET_CPU_DEFAULT.
%{mcpu=strongarm1100:-D__ARM_ARCH_4__} \
%{mcpu=xscale:-D__ARM_ARCH_5TE__} \
%{mcpu=xscale:-D__XSCALE__} \
+ %{mcpu=ep9312:-D__ARM_ARCH_4T__} \
+ %{mcpu=ep9312:-D__MAVERICK__} \
%{!mcpu*:%(cpp_cpu_arch_default)}} \
"
@@ -376,6 +390,9 @@ Unrecognized value in TARGET_CPU_DEFAULT.
/* Nonzero means to use ARM/Thumb Procedure Call Standard conventions. */
#define ARM_FLAG_ATPCS (1 << 22)
+/* Fix invalid Cirrus instruction combinations by inserting NOPs. */
+#define CIRRUS_FIX_INVALID_INSNS (1 << 23)
+
#define TARGET_APCS_FRAME (target_flags & ARM_FLAG_APCS_FRAME)
#define TARGET_POKE_FUNCTION_NAME (target_flags & ARM_FLAG_POKE)
#define TARGET_FPE (target_flags & ARM_FLAG_FPE)
@@ -387,6 +404,8 @@ Unrecognized value in TARGET_CPU_DEFAULT.
#define TARGET_MMU_TRAPS (target_flags & ARM_FLAG_MMU_TRAPS)
#define TARGET_SOFT_FLOAT (target_flags & ARM_FLAG_SOFT_FLOAT)
#define TARGET_HARD_FLOAT (! TARGET_SOFT_FLOAT)
+#define TARGET_CIRRUS (arm_is_cirrus)
+#define TARGET_ANY_HARD_FLOAT (TARGET_HARD_FLOAT || TARGET_CIRRUS)
#define TARGET_VFP (target_flags & ARM_FLAG_VFP)
#define TARGET_BIG_END (target_flags & ARM_FLAG_BIG_END)
#define TARGET_INTERWORK (target_flags & ARM_FLAG_INTERWORK)
@@ -403,6 +422,7 @@ Unrecognized value in TARGET_CPU_DEFAULT.
#define TARGET_BACKTRACE (leaf_function_p () \
? (target_flags & THUMB_FLAG_LEAF_BACKTRACE) \
: (target_flags & THUMB_FLAG_BACKTRACE))
+#define TARGET_CIRRUS_FIX_INVALID_INSNS (target_flags & CIRRUS_FIX_INVALID_INSNS)
/* SUBTARGET_SWITCHES is used to add flags on a per-config basis. */
#ifndef SUBTARGET_SWITCHES
@@ -481,6 +501,10 @@ Unrecognized value in TARGET_CPU_DEFAULT.
N_("Thumb: Assume function pointers may go to non-Thumb aware code") }, \
{"no-caller-super-interworking", -THUMB_FLAG_CALLER_SUPER_INTERWORKING, \
"" }, \
+ {"cirrus-fix-invalid-insns", CIRRUS_FIX_INVALID_INSNS, \
+ N_("Cirrus: Place NOPs to avoid invalid instruction combinations") }, \
+ {"no-cirrus-fix-invalid-insns", -CIRRUS_FIX_INVALID_INSNS, \
+ N_("Cirrus: Do not break up invalid instruction combinations with NOPs") },\
SUBTARGET_SWITCHES \
{"", TARGET_DEFAULT, "" } \
}
@@ -530,7 +554,8 @@ enum floating_point_type
{
FP_HARD,
FP_SOFT2,
- FP_SOFT3
+ FP_SOFT3,
+ FP_CIRRUS
};
/* Recast the floating point class to be the floating point attribute. */
@@ -548,6 +573,11 @@ extern enum floating_point_type arm_fpu_arch;
#define FP_DEFAULT FP_SOFT2
#endif
+#if TARGET_CPU_DEFAULT == TARGET_CPU_ep9312
+#undef FP_DEFAULT
+#define FP_DEFAULT FP_CIRRUS
+#endif
+
/* Nonzero if the processor has a fast multiply insn, and one that does
a 64-bit multiply of two 32-bit values. */
extern int arm_fast_multiply;
@@ -570,6 +600,9 @@ extern int thumb_code;
/* Nonzero if this chip is a StrongARM. */
extern int arm_is_strong;
+/* Nonzero if this chip is a Cirrus variant. */
+extern int arm_is_cirrus;
+
/* Nonzero if this chip is an XScale. */
extern int arm_is_xscale;
@@ -756,6 +789,11 @@ extern const char * structure_size_string;
*: See CONDITIONAL_REGISTER_USAGE */
+/*
+ mvf0 Cirrus floating point result
+ mvf1-mvf3 Cirrus floating point scratch
+ mvf4-mvf15 S Cirrus floating point variable. */
+
/* The stack backtrace structure is as follows:
fp points to here: | save code pointer | [fp]
| return link value | [fp, #-4]
@@ -785,7 +823,9 @@ extern const char * structure_size_string;
0,0,0,0,0,0,0,0, \
0,0,0,0,0,1,0,1, \
0,0,0,0,0,0,0,0, \
- 1,1,1 \
+ 1,1,1, \
+ 1,1,1,1,1,1,1,1, \
+ 1,1,1,1,1,1,1,1 \
}
/* 1 for registers not available across function calls.
@@ -801,7 +841,9 @@ extern const char * structure_size_string;
1,1,1,1,0,0,0,0, \
0,0,0,0,1,1,1,1, \
1,1,1,1,0,0,0,0, \
- 1,1,1 \
+ 1,1,1, \
+ 1,1,1,1,1,1,1,1, \
+ 1,1,1,1,1,1,1,1 \
}
#ifndef SUBTARGET_CONDITIONAL_REGISTER_USAGE
@@ -818,6 +860,20 @@ extern const char * structure_size_string;
regno <= LAST_ARM_FP_REGNUM; ++regno) \
fixed_regs[regno] = call_used_regs[regno] = 1; \
} \
+ \
+ if (TARGET_CIRRUS) \
+ { \
+ for (regno = FIRST_ARM_FP_REGNUM; \
+ regno <= LAST_ARM_FP_REGNUM; ++ regno) \
+ fixed_regs[regno] = call_used_regs[regno] = 1; \
+ for (regno = FIRST_CIRRUS_FP_REGNUM; \
+ regno <= LAST_CIRRUS_FP_REGNUM; ++ regno) \
+ { \
+ fixed_regs[regno] = 0; \
+ call_used_regs[regno] = regno < FIRST_CIRRUS_FP_REGNUM + 4; \
+ } \
+ } \
+ \
if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM) \
{ \
fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \
@@ -941,8 +997,14 @@ extern const char * structure_size_string;
/* Base register for access to arguments of the function. */
#define ARG_POINTER_REGNUM 26
+#define FIRST_CIRRUS_FP_REGNUM 27
+#define LAST_CIRRUS_FP_REGNUM 42
+#define IS_CIRRUS_REGNUM(REGNUM) \
+ (((REGNUM) >= FIRST_CIRRUS_FP_REGNUM) && ((REGNUM) <= LAST_CIRRUS_FP_REGNUM))
+
/* The number of hard registers is 16 ARM + 8 FPU + 1 CC + 1 SFP. */
-#define FIRST_PSEUDO_REGISTER 27
+/* Cirrus registers take us up to 43... */
+#define FIRST_PSEUDO_REGISTER 43
/* 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
@@ -990,6 +1052,8 @@ extern const char * structure_size_string;
3, 2, 1, 0, 12, 14, 4, 5, \
6, 7, 8, 10, 9, 11, 13, 15, \
16, 17, 18, 19, 20, 21, 22, 23, \
+ 27, 28, 29, 30, 31, 32, 33, 34, \
+ 35, 36, 37, 38, 39, 40, 41, 42, \
24, 25, 26 \
}
@@ -1008,6 +1072,7 @@ enum reg_class
{
NO_REGS,
FPU_REGS,
+ CIRRUS_REGS,
LO_REGS,
STACK_REG,
BASE_REGS,
@@ -1025,6 +1090,7 @@ enum reg_class
{ \
"NO_REGS", \
"FPU_REGS", \
+ "CIRRUS_REGS", \
"LO_REGS", \
"STACK_REG", \
"BASE_REGS", \
@@ -1039,15 +1105,16 @@ enum reg_class
of length N_REG_CLASSES. */
#define REG_CLASS_CONTENTS \
{ \
- { 0x0000000 }, /* NO_REGS */ \
- { 0x0FF0000 }, /* FPU_REGS */ \
- { 0x00000FF }, /* LO_REGS */ \
- { 0x0002000 }, /* STACK_REG */ \
- { 0x00020FF }, /* BASE_REGS */ \
- { 0x000FF00 }, /* HI_REGS */ \
- { 0x1000000 }, /* CC_REG */ \
- { 0x200FFFF }, /* GENERAL_REGS */ \
- { 0x2FFFFFF } /* ALL_REGS */ \
+ { 0x00000000, 0x0 }, /* NO_REGS */ \
+ { 0x00FF0000, 0x0 }, /* FPU_REGS */ \
+ { 0xF8000000, 0x000007FF }, /* CIRRUS_REGS */ \
+ { 0x000000FF, 0x0 }, /* LO_REGS */ \
+ { 0x00002000, 0x0 }, /* STACK_REG */ \
+ { 0x000020FF, 0x0 }, /* BASE_REGS */ \
+ { 0x0000FF00, 0x0 }, /* HI_REGS */ \
+ { 0x01000000, 0x0 }, /* CC_REG */ \
+ { 0x0200FFFF, 0x0 }, /* GENERAL_REGS */\
+ { 0xFAFFFFFF, 0x000007FF } /* ALL_REGS */ \
}
/* The same information, inverted:
@@ -1080,6 +1147,7 @@ enum reg_class
ARM, but several more letters for the Thumb. */
#define REG_CLASS_FROM_LETTER(C) \
( (C) == 'f' ? FPU_REGS \
+ : (C) == 'v' ? CIRRUS_REGS \
: (C) == 'l' ? (TARGET_ARM ? GENERAL_REGS : LO_REGS) \
: TARGET_ARM ? NO_REGS \
: (C) == 'h' ? HI_REGS \
@@ -1143,8 +1211,9 @@ enum reg_class
(C) == 'R' ? (GET_CODE (OP) == MEM \
&& GET_CODE (XEXP (OP, 0)) == SYMBOL_REF \
&& CONSTANT_POOL_ADDRESS_P (XEXP (OP, 0))) : \
- (C) == 'S' ? (optimize > 0 && CONSTANT_ADDRESS_P (OP)) \
- : 0)
+ (C) == 'S' ? (optimize > 0 && CONSTANT_ADDRESS_P (OP)) : \
+ (C) == 'T' ? cirrus_memory_offset (OP) : \
+ 0)
#define EXTRA_CONSTRAINT_THUMB(X, C) \
((C) == 'Q' ? (GET_CODE (X) == MEM \
@@ -1188,13 +1257,18 @@ enum reg_class
/* If we need to load shorts byte-at-a-time, then we need a scratch. */
#define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, X) \
+ /* Cannot load constants into Cirrus registers. */ \
+ ((TARGET_CIRRUS \
+ && (CLASS) == CIRRUS_REGS \
+ && (CONSTANT_P (X) || GET_CODE (X) == SYMBOL_REF)) \
+ ? GENERAL_REGS : \
(TARGET_ARM ? \
(((MODE) == HImode && ! arm_arch4 && TARGET_MMU_TRAPS \
&& (GET_CODE (X) == MEM \
|| ((GET_CODE (X) == REG || GET_CODE (X) == SUBREG) \
&& true_regnum (X) == -1))) \
? GENERAL_REGS : NO_REGS) \
- : THUMB_SECONDARY_INPUT_RELOAD_CLASS (CLASS, MODE, X))
+ : THUMB_SECONDARY_INPUT_RELOAD_CLASS (CLASS, MODE, X)))
/* Try a machine-dependent way of reloading an illegitimate address
operand. If we find one, push the reload and jump to WIN. This
@@ -1217,6 +1291,9 @@ enum reg_class
\
if (MODE == DImode || (TARGET_SOFT_FLOAT && MODE == DFmode)) \
low = ((val & 0xf) ^ 0x8) - 0x8; \
+ else if (TARGET_CIRRUS) \
+ /* Need to be careful, -256 is not a valid offset. */ \
+ low = val >= 0 ? (val & 0xff) : -((-val) & 0xff); \
else if (MODE == SImode \
|| (MODE == SFmode && TARGET_SOFT_FLOAT) \
|| ((MODE == HImode || MODE == QImode) && ! arm_arch4)) \
@@ -1289,13 +1366,19 @@ enum reg_class
needed to represent mode MODE in a register of class CLASS.
ARM regs are UNITS_PER_WORD bits while FPU regs can hold any FP mode */
#define CLASS_MAX_NREGS(CLASS, MODE) \
- ((CLASS) == FPU_REGS ? 1 : ARM_NUM_REGS (MODE))
+ (((CLASS) == FPU_REGS || (CLASS) == CIRRUS_REGS) ? 1 : ARM_NUM_REGS (MODE))
+
+/* If defined, gives a class of registers that cannot be used as the
+ operand of a SUBREG that changes the mode of the object illegally. */
/* Moves between FPU_REGS and GENERAL_REGS are two memory insns. */
#define REGISTER_MOVE_COST(MODE, FROM, TO) \
(TARGET_ARM ? \
((FROM) == FPU_REGS && (TO) != FPU_REGS ? 20 : \
- (FROM) != FPU_REGS && (TO) == FPU_REGS ? 20 : 2) \
+ (FROM) != FPU_REGS && (TO) == FPU_REGS ? 20 : \
+ (FROM) == CIRRUS_REGS && (TO) != CIRRUS_REGS ? 20 : \
+ (FROM) != CIRRUS_REGS && (TO) == CIRRUS_REGS ? 20 : \
+ 2) \
: \
((FROM) == HI_REGS || (TO) == HI_REGS) ? 4 : 2)
@@ -1347,6 +1430,8 @@ enum reg_class
#define LIBCALL_VALUE(MODE) \
(TARGET_ARM && TARGET_HARD_FLOAT && GET_MODE_CLASS (MODE) == MODE_FLOAT \
? gen_rtx_REG (MODE, FIRST_ARM_FP_REGNUM) \
+ : TARGET_ARM && TARGET_CIRRUS && GET_MODE_CLASS (MODE) == MODE_FLOAT \
+ ? gen_rtx_REG (MODE, FIRST_CIRRUS_FP_REGNUM) \
: gen_rtx_REG (MODE, ARG_REGISTER (1)))
/* Define how to find the value returned by a function.
@@ -1358,8 +1443,10 @@ enum reg_class
/* 1 if N is a possible register number for a function value.
On the ARM, only r0 and f0 can return results. */
+/* On a Cirrus chip, mvf0 can return results. */
#define FUNCTION_VALUE_REGNO_P(REGNO) \
((REGNO) == ARG_REGISTER (1) \
+ || (TARGET_ARM && ((REGNO) == FIRST_CIRRUS_FP_REGNUM) && TARGET_CIRRUS) \
|| (TARGET_ARM && ((REGNO) == FIRST_ARM_FP_REGNUM) && TARGET_HARD_FLOAT))
/* How large values are returned */
@@ -2449,6 +2536,9 @@ extern int making_const_table;
{"multi_register_push", {PARALLEL}}, \
{"cc_register", {REG}}, \
{"logical_binary_operator", {AND, IOR, XOR}}, \
+ {"cirrus_register_operand", {REG}}, \
+ {"cirrus_fp_register", {REG}}, \
+ {"cirrus_shift_const", {CONST_INT}}, \
{"dominant_cc_register", {REG}},
/* Define this if you have special predicates that know special things
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index b35041a4b74..705d22dbf01 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -386,6 +386,8 @@
(and (eq_attr "core_cycles" "multi")
(eq_attr "type" "!mult,load,store1,store2,store3,store4")) 32 32)
+(include "cirrus.md")
+
;;---------------------------------------------------------------------------
;; Insn patterns
;;
@@ -394,6 +396,8 @@
;; Note: For DImode insns, there is normally no reason why operands should
;; not be in the same register, what we don't want is for something being
;; written to partially overlap something that is an input.
+;; Cirrus 64bit additions should not be split because we have a native
+;; 64bit addition instructions.
(define_expand "adddi3"
[(parallel
@@ -403,6 +407,16 @@
(clobber (reg:CC CC_REGNUM))])]
"TARGET_EITHER"
"
+ if (TARGET_CIRRUS)
+ {
+ if (!cirrus_fp_register (operands[0], DImode))
+ operands[0] = force_reg (DImode, operands[0]);
+ if (!cirrus_fp_register (operands[1], DImode))
+ operands[1] = force_reg (DImode, operands[1]);
+ emit_insn (gen_cirrus_adddi3 (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+
if (TARGET_THUMB)
{
if (GET_CODE (operands[1]) != REG)
@@ -429,7 +443,7 @@
(plus:DI (match_operand:DI 1 "s_register_operand" "%0, 0")
(match_operand:DI 2 "s_register_operand" "r, 0")))
(clobber (reg:CC CC_REGNUM))]
- "TARGET_ARM"
+ "TARGET_ARM && !TARGET_CIRRUS"
"#"
"TARGET_ARM && reload_completed"
[(parallel [(set (reg:CC_C CC_REGNUM)
@@ -457,7 +471,7 @@
(match_operand:SI 2 "s_register_operand" "r,r"))
(match_operand:DI 1 "s_register_operand" "r,0")))
(clobber (reg:CC CC_REGNUM))]
- "TARGET_ARM"
+ "TARGET_ARM && !TARGET_CIRRUS"
"#"
"TARGET_ARM && reload_completed"
[(parallel [(set (reg:CC_C CC_REGNUM)
@@ -486,7 +500,7 @@
(match_operand:SI 2 "s_register_operand" "r,r"))
(match_operand:DI 1 "s_register_operand" "r,0")))
(clobber (reg:CC CC_REGNUM))]
- "TARGET_ARM"
+ "TARGET_ARM && !TARGET_CIRRUS"
"#"
"TARGET_ARM && reload_completed"
[(parallel [(set (reg:CC_C CC_REGNUM)
@@ -789,7 +803,7 @@
(set_attr "length" "4,8")]
)
-(define_insn "addsf3"
+(define_insn "*arm_addsf3"
[(set (match_operand:SF 0 "s_register_operand" "=f,f")
(plus:SF (match_operand:SF 1 "s_register_operand" "%f,f")
(match_operand:SF 2 "fpu_add_operand" "fG,H")))]
@@ -801,7 +815,7 @@
(set_attr "predicable" "yes")]
)
-(define_insn "adddf3"
+(define_insn "*arm_adddf3"
[(set (match_operand:DF 0 "s_register_operand" "=f,f")
(plus:DF (match_operand:DF 1 "s_register_operand" "%f,f")
(match_operand:DF 2 "fpu_add_operand" "fG,H")))]
@@ -857,6 +871,15 @@
(clobber (reg:CC CC_REGNUM))])]
"TARGET_EITHER"
"
+ if (TARGET_CIRRUS
+ && TARGET_ARM
+ && cirrus_fp_register (operands[0], DImode)
+ && cirrus_fp_register (operands[1], DImode))
+ {
+ emit_insn (gen_cirrus_subdi3 (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+
if (TARGET_THUMB)
{
if (GET_CODE (operands[1]) != REG)
@@ -1042,7 +1065,7 @@
(set_attr "length" "*,8")]
)
-(define_insn "subsf3"
+(define_insn "*arm_subsf3"
[(set (match_operand:SF 0 "s_register_operand" "=f,f")
(minus:SF (match_operand:SF 1 "fpu_rhs_operand" "f,G")
(match_operand:SF 2 "fpu_rhs_operand" "fG,f")))]
@@ -1053,7 +1076,7 @@
[(set_attr "type" "farith")]
)
-(define_insn "subdf3"
+(define_insn "*arm_subdf3"
[(set (match_operand:DF 0 "s_register_operand" "=f,f")
(minus:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G")
(match_operand:DF 2 "fpu_rhs_operand" "fG,f")))]
@@ -1332,7 +1355,7 @@
"smlalbb%?\\t%Q0, %R0, %2, %3"
[(set_attr "type" "mult")])
-(define_insn "mulsf3"
+(define_insn "*arm_mulsf3"
[(set (match_operand:SF 0 "s_register_operand" "=f")
(mult:SF (match_operand:SF 1 "s_register_operand" "f")
(match_operand:SF 2 "fpu_rhs_operand" "fG")))]
@@ -1342,7 +1365,7 @@
(set_attr "predicable" "yes")]
)
-(define_insn "muldf3"
+(define_insn "*arm_muldf3"
[(set (match_operand:DF 0 "s_register_operand" "=f")
(mult:DF (match_operand:DF 1 "s_register_operand" "f")
(match_operand:DF 2 "fpu_rhs_operand" "fG")))]
@@ -2529,6 +2552,19 @@
[(set_attr "length" "2")]
)
+(define_expand "ashldi3"
+ [(set (match_operand:DI 0 "s_register_operand" "")
+ (ashift:DI (match_operand:DI 1 "general_operand" "")
+ (match_operand:SI 2 "general_operand" "")))]
+ "TARGET_ARM && (TARGET_CIRRUS)"
+ "
+ if (! s_register_operand (operands[1], DImode))
+ operands[1] = copy_to_mode_reg (DImode, operands[1]);
+ if (! s_register_operand (operands[2], SImode))
+ operands[2] = copy_to_mode_reg (SImode, operands[2]);
+ "
+)
+
(define_insn "*arm_shiftsi3"
[(set (match_operand:SI 0 "s_register_operand" "=r")
(match_operator:SI 3 "shift_operator"
@@ -2702,7 +2738,7 @@
[(set_attr "length" "2")]
)
-(define_insn "negsf2"
+(define_insn "*arm_negsf2"
[(set (match_operand:SF 0 "s_register_operand" "=f")
(neg:SF (match_operand:SF 1 "s_register_operand" "f")))]
"TARGET_ARM && TARGET_HARD_FLOAT"
@@ -2711,7 +2747,7 @@
(set_attr "predicable" "yes")]
)
-(define_insn "negdf2"
+(define_insn "*arm_negdf2"
[(set (match_operand:DF 0 "s_register_operand" "=f")
(neg:DF (match_operand:DF 1 "s_register_operand" "f")))]
"TARGET_ARM && TARGET_HARD_FLOAT"
@@ -2735,7 +2771,7 @@
;; it does, but tell the final scan operator the truth. Similarly for
;; (neg (abs...))
-(define_insn "abssi2"
+(define_insn "*arm_abssi2"
[(set (match_operand:SI 0 "s_register_operand" "=r,&r")
(abs:SI (match_operand:SI 1 "s_register_operand" "0,r")))
(clobber (reg:CC CC_REGNUM))]
@@ -2763,7 +2799,7 @@
(set_attr "length" "8")]
)
-(define_insn "abssf2"
+(define_insn "*arm_abssf2"
[(set (match_operand:SF 0 "s_register_operand" "=f")
(abs:SF (match_operand:SF 1 "s_register_operand" "f")))]
"TARGET_ARM && TARGET_HARD_FLOAT"
@@ -2772,7 +2808,7 @@
(set_attr "predicable" "yes")]
)
-(define_insn "absdf2"
+(define_insn "*arm_absdf2"
[(set (match_operand:DF 0 "s_register_operand" "=f")
(abs:DF (match_operand:DF 1 "s_register_operand" "f")))]
"TARGET_ARM && TARGET_HARD_FLOAT"
@@ -2884,7 +2920,7 @@
;; Fixed <--> Floating conversion insns
-(define_insn "floatsisf2"
+(define_insn "*arm_floatsisf2"
[(set (match_operand:SF 0 "s_register_operand" "=f")
(float:SF (match_operand:SI 1 "s_register_operand" "r")))]
"TARGET_ARM && TARGET_HARD_FLOAT"
@@ -2893,7 +2929,7 @@
(set_attr "predicable" "yes")]
)
-(define_insn "floatsidf2"
+(define_insn "*arm_floatsidf2"
[(set (match_operand:DF 0 "s_register_operand" "=f")
(float:DF (match_operand:SI 1 "s_register_operand" "r")))]
"TARGET_ARM && TARGET_HARD_FLOAT"
@@ -2902,7 +2938,7 @@
(set_attr "predicable" "yes")]
)
-(define_insn "fix_truncsfsi2"
+(define_insn "*arm_fix_truncsfsi2"
[(set (match_operand:SI 0 "s_register_operand" "=r")
(fix:SI (match_operand:SF 1 "s_register_operand" "f")))]
"TARGET_ARM && TARGET_HARD_FLOAT"
@@ -2911,7 +2947,7 @@
(set_attr "predicable" "yes")]
)
-(define_insn "fix_truncdfsi2"
+(define_insn "*arm_fix_truncdfsi2"
[(set (match_operand:SI 0 "s_register_operand" "=r")
(fix:SI (match_operand:DF 1 "s_register_operand" "f")))]
"TARGET_ARM && TARGET_HARD_FLOAT"
@@ -2922,7 +2958,7 @@
;; Truncation insns
-(define_insn "truncdfsf2"
+(define_insn "*arm_truncdfsf2"
[(set (match_operand:SF 0 "s_register_operand" "=f")
(float_truncate:SF
(match_operand:DF 1 "s_register_operand" "f")))]
@@ -3654,7 +3690,7 @@
(set_attr "pool_range" "32,32")]
)
-(define_insn "extendsfdf2"
+(define_insn "*arm_extendsfdf2"
[(set (match_operand:DF 0 "s_register_operand" "=f")
(float_extend:DF (match_operand:SF 1 "s_register_operand" "f")))]
"TARGET_ARM && TARGET_HARD_FLOAT"
@@ -3743,7 +3779,7 @@
(define_insn "*arm_movdi"
[(set (match_operand:DI 0 "nonimmediate_di_operand" "=r, r, o<>")
(match_operand:DI 1 "di_operand" "rIK,mi,r"))]
- "TARGET_ARM"
+ "TARGET_ARM && !TARGET_CIRRUS"
"*
return (output_move_double (operands));
"
@@ -3761,6 +3797,7 @@
[(set (match_operand:DI 0 "nonimmediate_operand" "=l,l,l,l,>,l, m,*r")
(match_operand:DI 1 "general_operand" "l, I,J,>,l,mi,l,*r"))]
"TARGET_THUMB
+ && !TARGET_CIRRUS
&& ( register_operand (operands[0], DImode)
|| register_operand (operands[1], DImode))"
"*
@@ -4769,6 +4806,7 @@
[(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m")
(match_operand:SF 1 "general_operand" "r,mE,r"))]
"TARGET_ARM
+ && !TARGET_CIRRUS
&& TARGET_SOFT_FLOAT
&& (GET_CODE (operands[0]) != MEM
|| register_operand (operands[1], SFmode))"
@@ -4909,6 +4947,7 @@
[(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=r,r,m")
(match_operand:DF 1 "soft_df_operand" "r,mF,r"))]
"TARGET_ARM && TARGET_SOFT_FLOAT
+ && !TARGET_CIRRUS
"
"* return output_move_double (operands);"
[(set_attr "length" "8,8,8")
@@ -5414,8 +5453,11 @@
(define_expand "cmpsf"
[(match_operand:SF 0 "s_register_operand" "")
(match_operand:SF 1 "fpu_rhs_operand" "")]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
"
+ if (TARGET_CIRRUS && !cirrus_fp_register (operands[1], SFmode))
+ operands[1] = force_reg (SFmode, operands[1]);
+
arm_compare_op0 = operands[0];
arm_compare_op1 = operands[1];
DONE;
@@ -5425,8 +5467,11 @@
(define_expand "cmpdf"
[(match_operand:DF 0 "s_register_operand" "")
(match_operand:DF 1 "fpu_rhs_operand" "")]
- "TARGET_ARM && TARGET_HARD_FLOAT"
+ "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
"
+ if (TARGET_CIRRUS && !cirrus_fp_register (operands[1], DFmode))
+ operands[1] = force_reg (DFmode, operands[1]);
+
arm_compare_op0 = operands[0];
arm_compare_op1 = operands[1];
DONE;
@@ -5531,6 +5576,65 @@
(set_attr "type" "f_2_r")]
)
+;; There is no CCFPE or CCFP modes in the code below so we can have
+;; one pattern to match either one. Besides, we're pretty sure we
+;; have either CCFPE or CCFP because we made the patterns
+;; (arm_gen_compare_reg).
+
+;; Cirrus SF compare instruction
+(define_insn "*cirrus_cmpsf"
+ [(set (reg:CCFP CC_REGNUM)
+ (compare:CCFP (match_operand:SF 0 "cirrus_fp_register" "v")
+ (match_operand:SF 1 "cirrus_fp_register" "v")))]
+ "TARGET_ARM && TARGET_CIRRUS"
+ "cfcmps%?\\tr15, %V0, %V1"
+ [(set_attr "cirrus_type" "farith")
+ (set_attr "cirrus" "compare")]
+)
+
+;; Cirrus DF compare instruction
+(define_insn "*cirrus_cmpdf"
+ [(set (reg:CCFP CC_REGNUM)
+ (compare:CCFP (match_operand:DF 0 "cirrus_fp_register" "v")
+ (match_operand:DF 1 "cirrus_fp_register" "v")))]
+ "TARGET_ARM && TARGET_CIRRUS"
+ "cfcmpd%?\\tr15, %V0, %V1"
+ [(set_attr "cirrus_type" "farith")
+ (set_attr "cirrus" "compare")]
+)
+
+;; Cirrus DI compare instruction
+(define_expand "cmpdi"
+ [(match_operand:DI 0 "cirrus_fp_register" "")
+ (match_operand:DI 1 "cirrus_fp_register" "")]
+ "TARGET_ARM && TARGET_CIRRUS"
+ "{
+ arm_compare_op0 = operands[0];
+ arm_compare_op1 = operands[1];
+ DONE;
+ }")
+
+(define_insn "*cirrus_cmpdi"
+ [(set (reg:CC CC_REGNUM)
+ (compare:CC (match_operand:DI 0 "cirrus_fp_register" "v")
+ (match_operand:DI 1 "cirrus_fp_register" "v")))]
+ "TARGET_ARM && TARGET_CIRRUS"
+ "cfcmp64%?\\tr15, %V0, %V1"
+ [(set_attr "cirrus_type" "farith")
+ (set_attr "cirrus" "compare")]
+)
+
+;; Cirrus SI compare instruction
+(define_insn "*cirrus_cmpsi_1"
+ [(set (reg:CC CC_REGNUM)
+ (compare:CC (match_operand:SI 0 "cirrus_fp_register" "v")
+ (match_operand:SI 1 "cirrus_fp_register" "v")))]
+ "TARGET_ARM && TARGET_CIRRUS && 0"
+ "cfcmp32%?\\tr15, %V0, %V1"
+ [(set_attr "cirrus_type" "farith")
+ (set_attr "cirrus" "compare")]
+)
+
(define_insn "*cmpsf_trap"
[(set (reg:CCFPE CC_REGNUM)
(compare:CCFPE (match_operand:SF 0 "s_register_operand" "f,f")
@@ -6347,8 +6451,8 @@
)
(define_insn "*call_value_reg"
- [(set (match_operand 0 "" "=r,f")
- (call (mem:SI (match_operand:SI 1 "s_register_operand" "r,r"))
+ [(set (match_operand 0 "" "=r,f,v")
+ (call (mem:SI (match_operand:SI 1 "s_register_operand" "r,r,r"))
(match_operand 2 "" "")))
(use (match_operand 3 "" ""))
(clobber (reg:SI LR_REGNUM))]
@@ -6361,8 +6465,8 @@
)
(define_insn "*call_value_mem"
- [(set (match_operand 0 "" "=r,f")
- (call (mem:SI (match_operand:SI 1 "memory_operand" "m,m"))
+ [(set (match_operand 0 "" "=r,f,v")
+ (call (mem:SI (match_operand:SI 1 "memory_operand" "m,m,m"))
(match_operand 2 "" "")))
(use (match_operand 3 "" ""))
(clobber (reg:SI LR_REGNUM))]
@@ -6393,8 +6497,8 @@
)
(define_insn "*call_value_symbol"
- [(set (match_operand 0 "s_register_operand" "=r,f")
- (call (mem:SI (match_operand:SI 1 "" "X,X"))
+ [(set (match_operand 0 "s_register_operand" "=r,f,v")
+ (call (mem:SI (match_operand:SI 1 "" "X,X,X"))
(match_operand:SI 2 "" "")))
(use (match_operand 3 "" ""))
(clobber (reg:SI LR_REGNUM))]
@@ -6476,8 +6580,8 @@
)
(define_insn "*sibcall_value_insn"
- [(set (match_operand 0 "s_register_operand" "=r,f")
- (call (mem:SI (match_operand:SI 1 "" "X,X"))
+ [(set (match_operand 0 "s_register_operand" "=r,f,v")
+ (call (mem:SI (match_operand:SI 1 "" "X,X,X"))
(match_operand 2 "" "")))
(return)
(use (match_operand 3 "" ""))]
@@ -8274,6 +8378,9 @@
(set (reg:CC CC_REGNUM)
(compare:CC (match_dup 1) (const_int 0)))]
"TARGET_ARM
+ && (!TARGET_CIRRUS
+ || (!cirrus_fp_register (operands[0], SImode)
+ && !cirrus_fp_register (operands[1], SImode)))
"
[(parallel [(set (reg:CC CC_REGNUM) (compare:CC (match_dup 1) (const_int 0)))
(set (match_dup 0) (match_dup 1))])]
diff --git a/gcc/config/arm/t-arm-elf b/gcc/config/arm/t-arm-elf
index 0011b2a8d02..79506fb5a62 100644
--- a/gcc/config/arm/t-arm-elf
+++ b/gcc/config/arm/t-arm-elf
@@ -24,6 +24,10 @@ dp-bit.c: $(srcdir)/config/fp-bit.c
MULTILIB_OPTIONS = marm/mthumb
MULTILIB_DIRNAMES = arm thumb
MULTILIB_EXCEPTIONS =
+
+# MULTILIB_OPTIONS += mcpu=ep9312
+# MULTILIB_DIRNAMES += ep9312
+# MULTILIB_EXCEPTIONS += *mthumb/*mcpu=ep9312*
# MULTILIB_OPTIONS += mlittle-endian/mbig-endian
# MULTILIB_DIRNAMES += le be
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index c8f0086a423..cfcf4dc9e08 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -386,6 +386,7 @@ in the following sections.
-msingle-pic-base -mno-single-pic-base @gol
-mpic-register=@var{reg} @gol
-mnop-fun-dllimport @gol
+-mcirrus-fix-invalid-insns -mno-cirrus-fix-invalid-insns @gol
-mpoke-function-name @gol
-mthumb -marm @gol
-mtpcs-frame -mtpcs-leaf-frame @gol
@@ -6132,7 +6133,7 @@ assembly code. Permissible names are: @samp{arm2}, @samp{arm250},
@samp{strongarm}, @samp{strongarm110}, @samp{strongarm1100},
@samp{arm8}, @samp{arm810}, @samp{arm9}, @samp{arm9e}, @samp{arm920},
@samp{arm920t}, @samp{arm940t}, @samp{arm9tdmi}, @samp{arm10tdmi},
-@samp{arm1020t}, @samp{xscale}.
+@samp{arm1020t}, @samp{xscale}, @samp{ep9312}.
@itemx -mtune=@var{name}
@opindex mtune
@@ -6152,7 +6153,7 @@ name to determine what kind of instructions it can emit when generating
assembly code. This option can be used in conjunction with or instead
of the @option{-mcpu=} option. Permissible names are: @samp{armv2},
@samp{armv2a}, @samp{armv3}, @samp{armv3m}, @samp{armv4}, @samp{armv4t},
-@samp{armv5}, @samp{armv5t}, @samp{armv5te}.
+@samp{armv5}, @samp{armv5t}, @samp{armv5te}, @samp{ep9312}.
@item -mfpe=@var{number}
@itemx -mfp=@var{number}
@@ -6224,6 +6225,18 @@ before execution begins.
Specify the register to be used for PIC addressing. The default is R10
unless stack-checking is enabled, when R9 is used.
+@item -mcirrus-fix-invalid-insns
+@opindex -mcirrus-fix-invalid-insns
+@opindex -mno-cirrus-fix-invalid-insns
+Insert NOPs into the instruction stream to in order to work around
+problems with invalid Maverick instruction combinations. This option
+is only valid if the @option{-mcpu=ep9312} option has been used to
+enable generation of instructions for the Cirrus Maverick floating
+point co-processor. This option is not enabled by default, since the
+problem is only present in older Maverick implemenations. The default
+can be re-enabled by use of the @option{-mno-cirrus-fix-invalid-insns}
+switch.
+
@item -mpoke-function-name
@opindex mpoke-function-name
Write the name of each function into the text section, directly