+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
arm*-*-*)
cpu_type=arm
;;
+ep9312*-*-*)
+ cpu_type=arm
+ ;;
xscale-*-*)
cpu_type=arm
;;
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
;;
| xarm7m | xarm7dm | xarm7dmi | xarm[79]tdmi \
| xarm7100 | xarm7500 | xarm7500fe | xarm810 \
| xxscale \
+ | xep9312 \
| xstrongarm | xstrongarm110 | xstrongarm1100)
target_cpu_default2="TARGET_CPU_$with_cpu"
;;
fi
;;
esac
+ case $machine in
+ 9ep9312-*-*)
+ target_cpu_default2="TARGET_CPU_9ep9312"
+ ;;
+ esac
;;
hppa*-*-* | parisc*-*-*)
"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
{"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
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));
extern int arm_function_arg_pass_by_reference PARAMS ((CUMULATIVE_ARGS *,
enum machine_mode,
tree, int));
-
#endif
#if defined AOF_ASSEMBLER
#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. */
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
#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. */
/* 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;
{"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 },
{ "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 }
};
{ TARGET_CPU_arm9, "arm9" },
{ TARGET_CPU_strongarm, "strongarm" },
{ TARGET_CPU_xscale, "xscale" },
+ { TARGET_CPU_ep9312, "ep9312" },
{ TARGET_CPU_generic, "arm" },
{ 0, 0 }
};
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)
{
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. */
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. */
&& 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;
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
case LE:
case GT:
case GE:
+ if (TARGET_CIRRUS)
+ return CCFPmode;
return CCFPEmode;
default:
/* 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
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;
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 ();
|| 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:
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;
if (regno == CC_REGNUM)
return NO_REGS;
+ if (IS_CIRRUS_REGNUM (regno))
+ return CIRRUS_REGS;
+
return FPU_REGS;
}
#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
#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
#endif
#endif
#endif
+#endif
#undef CPP_SPEC
#define CPP_SPEC "%(cpp_cpu_arch) %(subtarget_cpp_spec) \
%{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__} \
%{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)}} \
"
/* Nonzero means to use ARM/Thumb Procedure Call Standard conventions. */
#define ARM_FLAG_ATPCS (1 << 22)
+/* Fix invalid Cirrus instruction combinations by inserting NOPs. */
+#define CIRRUS_FIX_INVALID_INSNS (1 << 23)
+
#define TARGET_APCS_FRAME (target_flags & ARM_FLAG_APCS_FRAME)
#define TARGET_POKE_FUNCTION_NAME (target_flags & ARM_FLAG_POKE)
#define TARGET_FPE (target_flags & ARM_FLAG_FPE)
#define TARGET_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)
#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
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, "" } \
}
{
FP_HARD,
FP_SOFT2,
- FP_SOFT3
+ FP_SOFT3,
+ FP_CIRRUS
};
/* Recast the floating point class to be the floating point attribute. */
#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;
/* 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;
*: 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]
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.
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
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; \
/* 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
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 \
}
{
NO_REGS,
FPU_REGS,
+ CIRRUS_REGS,
LO_REGS,
STACK_REG,
BASE_REGS,
{ \
"NO_REGS", \
"FPU_REGS", \
+ "CIRRUS_REGS", \
"LO_REGS", \
"STACK_REG", \
"BASE_REGS", \
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:
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 \
(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 \
/* 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
\
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)) \
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)
\f
#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.
/* 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 */
{"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
(and (eq_attr "core_cycles" "multi")
(eq_attr "type" "!mult,load,store1,store2,store3,store4")) 32 32)
\f
+(include "cirrus.md")
+
;;---------------------------------------------------------------------------
;; Insn patterns
;;
;; 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
(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)
(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)
(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)
(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)
(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")))]
(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")))]
(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)
(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")))]
[(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")))]
"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")))]
(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")))]
[(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"
[(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"
(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"
;; 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))]
(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"
(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"
\f
;; 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"
(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"
(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"
(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"
;; 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")))]
(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"
(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));
"
[(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))"
"*
[(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))"
[(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")
(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;
(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;
(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")
)
(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))]
)
(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))]
)
(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))]
)
(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 "" ""))]
(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))])]
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
-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
@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
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}
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