From 9b6b54e2fe12171e8d7178c2fd8f6bd0d5493718 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Mon, 10 Feb 2003 11:45:26 +0000 Subject: [PATCH] Add support for Cirrus EP9312, an ARM variant. From-SVN: r62625 --- gcc/ChangeLog | 15 ++ gcc/config.gcc | 11 +- gcc/config/arm/aout.h | 71 ++++++- gcc/config/arm/arm-protos.h | 6 +- gcc/config/arm/arm.c | 389 +++++++++++++++++++++++++++++++++++- gcc/config/arm/arm.h | 126 ++++++++++-- gcc/config/arm/arm.md | 169 +++++++++++++--- gcc/config/arm/t-arm-elf | 4 + gcc/doc/invoke.texi | 17 +- 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 + + * Contributed support for the Cirrus EP9312 "Maverick" + floating point co-processor. Written by Aldy Hernandez + . + (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 * 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 -- 2.30.2