diff -ruN /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/config/arm/arm.c gcc-4.1.2/gcc/config/arm/arm.c --- /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/config/arm/arm.c 2007-05-09 16:32:29.000000000 +1000 +++ gcc-4.1.2/gcc/config/arm/arm.c 2007-05-15 09:39:41.000000000 +1000 @@ -4,6 +4,7 @@ Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl) and Martin Simmons (@harleqn.co.uk). More major hacks by Richard Earnshaw (rearnsha@arm.com). + Cirrus Crunch bugfixes by Vladimir Ivanov (vladit@nucleusys.com) This file is part of GCC. @@ -131,9 +132,17 @@ static bool arm_xscale_rtx_costs (rtx, int, int, int *); static bool arm_9e_rtx_costs (rtx, int, int, int *); static int arm_address_cost (rtx); -static bool arm_memory_load_p (rtx); +// static bool arm_memory_load_p (rtx); static bool arm_cirrus_insn_p (rtx); -static void cirrus_reorg (rtx); +// static void cirrus_reorg (rtx); +static bool arm_mem_access_p (rtx); +static bool cirrus_dest_regn_p (rtx, int); +static rtx cirrus_prev_next_mach_insn (rtx, int *, int); +static rtx cirrus_prev_mach_insn (rtx, int *); +static rtx cirrus_next_mach_insn (rtx, int *); +static void cirrus_reorg_branch (rtx); +static void cirrus_reorg_bug1 (rtx); +static void cirrus_reorg_bug10_12 (rtx); static void arm_init_builtins (void); static rtx arm_expand_builtin (tree, rtx, rtx, enum machine_mode, int); static void arm_init_iwmmxt_builtins (void); @@ -5399,41 +5412,6 @@ || TREE_CODE (valtype) == COMPLEX_TYPE)); } -/* Returns TRUE if INSN is an "LDR REG, ADDR" instruction. - Use by the Cirrus Maverick code which has to workaround - a hardware bug triggered by such instructions. */ -static bool -arm_memory_load_p (rtx insn) -{ - rtx body, lhs, rhs;; - - if (insn == NULL_RTX || GET_CODE (insn) != INSN) - return false; - - body = PATTERN (insn); - - if (GET_CODE (body) != SET) - return false; - - lhs = XEXP (body, 0); - rhs = XEXP (body, 1); - - lhs = REG_OR_SUBREG_RTX (lhs); - - /* If the destination is not a general purpose - register we do not have to worry. */ - if (GET_CODE (lhs) != REG - || REGNO_REG_CLASS (REGNO (lhs)) != GENERAL_REGS) - return false; - - /* As well as loads from memory we also have to react - to loads of invalid constants which will be turned - into loads from the minipool. */ - return (GET_CODE (rhs) == MEM - || GET_CODE (rhs) == SYMBOL_REF - || note_invalid_constants (insn, -1, false)); -} - /* Return TRUE if INSN is a Cirrus instruction. */ static bool arm_cirrus_insn_p (rtx insn) @@ -5452,124 +5433,218 @@ return attr != CIRRUS_NOT; } -/* Cirrus reorg for invalid instruction combinations. */ -static void -cirrus_reorg (rtx first) +/* Return TRUE if ISN does memory access. */ +static bool +arm_mem_access_p (rtx insn) { - enum attr_cirrus attr; - rtx body = PATTERN (first); - rtx t; - int nops; + enum attr_type attr; - /* 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); + /* 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; - if (arm_cirrus_insn_p (t)) - ++ nops; + attr = get_attr_type (insn); - if (arm_cirrus_insn_p (next_nonnote_insn (t))) - ++ nops; + return attr == TYPE_LOAD_BYTE + || attr == TYPE_LOAD1 || attr == TYPE_LOAD2 || attr == TYPE_LOAD3 || attr == TYPE_LOAD4 + || attr == TYPE_F_CVT + || attr == TYPE_F_MEM_R || attr == TYPE_R_MEM_F || attr == TYPE_F_2_R || attr == TYPE_R_2_F + || attr == TYPE_F_LOAD || attr == TYPE_F_LOADS || attr == TYPE_F_LOADD + || attr == TYPE_F_STORE || attr == TYPE_F_STORES || attr == TYPE_F_STORED + || attr == TYPE_STORE1 || attr == TYPE_STORE2 || attr == TYPE_STORE3 || attr == TYPE_STORE4; + +} - while (nops --) - emit_insn_after (gen_nop (), first); +/* Return TRUE if destination is certain Cirrus register. */ +static bool +cirrus_dest_regn_p (rtx body, int regn) +{ + rtx lhs; + int reg; + lhs = XEXP (body, 0); + if (GET_CODE (lhs) != REG) + return 0; - return; - } + reg = REGNO (lhs); + if (REGNO_REG_CLASS (reg) != CIRRUS_REGS) + return 0; - /* (float (blah)) is in parallel with a clobber. */ - if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0) - body = XVECEXP (body, 0, 0); + return reg == regn; +} + +/* Get previous/next machine instruction during Cirrus workaround scans. + Assume worst case (for the purpose of Cirrus workarounds) + for JUMP / CALL instructions. */ +static rtx +cirrus_prev_next_mach_insn (rtx insn, int *len, int next) +{ + rtx t; + int l = 0; - if (GET_CODE (body) == SET) + /* It seems that we can count only on INSN length. */ + for ( ; ; ) { - rtx lhs = XEXP (body, 0), rhs = XEXP (body, 1); + if (next) + insn = NEXT_INSN (insn); + else + insn = PREV_INSN (insn); + if (!insn) + break; - /* cfldrd, cfldr64, cfstrd, cfstr64 must - be followed by a non Cirrus insn. */ - if (get_attr_cirrus (first) == CIRRUS_DOUBLE) - { - if (arm_cirrus_insn_p (next_nonnote_insn (first))) - emit_insn_after (gen_nop (), first); + if (GET_CODE (insn) == INSN) + { + l = get_attr_length (insn) / 4; + if (l) + break; + } + else if (GET_CODE (insn) == JUMP_INSN) + { + l = 1; + t = is_jump_table (insn); + if (t) + l += get_jump_table_size (t) / 4; + break; + } + else if (GET_CODE (insn) == CALL_INSN) + { + l = 1; + break; + } + } - return; - } - else if (arm_memory_load_p (first)) - { - unsigned int arm_regno; + if (len) + *len = l; - /* 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 - { - gcc_assert (GET_CODE (rhs) == REG); - arm_regno = REGNO (rhs); - } + return insn; +} - /* Next insn. */ - first = next_nonnote_insn (first); +static rtx +cirrus_prev_mach_insn (rtx insn, int *len) +{ + return cirrus_prev_next_mach_insn (insn, len, 0); +} - if (! arm_cirrus_insn_p (first)) - return; +static rtx +cirrus_next_mach_insn (rtx insn, int *len) +{ + return cirrus_prev_next_mach_insn (insn, len, 1); +} - body = PATTERN (first); +/* Cirrus reorg for branch slots. */ +static void +cirrus_reorg_branch (rtx insn) +{ + rtx t; + int nops, l; - /* (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); + /* TODO: handle jump-tables. */ + t = is_jump_table (insn); + if (t) + return; + + /* Any branch must be followed by 2 non Cirrus instructions. */ + t = insn; + for (nops = 2; nops > 0; ) + { + if (!cirrus_next_mach_insn (t, 0)) + { + insn = t; + break; + } + t = cirrus_next_mach_insn (t, &l); + if (arm_cirrus_insn_p (t)) + break; + nops -= l; - return; - } } - /* get_attr cannot accept USE or CLOBBER. */ - if (!first - || GET_CODE (first) != INSN - || GET_CODE (PATTERN (first)) == USE - || GET_CODE (PATTERN (first)) == CLOBBER) - return; + while (nops-- > 0) + emit_insn_after (gen_nop (), insn); /* WARNING: this appears to cause "bad immediate value for offset" errors in the assembler */ +} - attr = get_attr_cirrus (first); +/* Cirrus reorg for bug #1 (cirrus + cfcmpxx). */ +static void +cirrus_reorg_bug1 (rtx insn) +{ + rtx body = PATTERN (insn), body2; + rtx t; + int i, nops, l; + enum attr_cirrus attr; - /* Any coprocessor compare instruction (cfcmps, cfcmpd, ...) - must be followed by a non-coprocessor instruction. */ - if (attr == CIRRUS_COMPARE) + /* Check if destination or clobber is Cirrus register. */ + if (GET_CODE (body) == PARALLEL) { - nops = 0; - - t = next_nonnote_insn (first); + for (i = 0; i < XVECLEN (body, 0); i++) + { + body2 = XVECEXP (body, 0, i); + if (GET_CODE (body2) == SET) + { + if (cirrus_dest_regn_p (body2, LAST_CIRRUS_FP_REGNUM)) + { + nops = 5; + goto fix; + } + } + else if (GET_CODE (body2) == CLOBBER) + { + if (cirrus_dest_regn_p (body2, LAST_CIRRUS_FP_REGNUM)) + { + nops = 4; + goto fix; + } + } + } + } + else if (GET_CODE (body) == SET) + { + if (cirrus_dest_regn_p (body, LAST_CIRRUS_FP_REGNUM)) + { + nops = 5; + goto fix; + } + } + return; - if (arm_cirrus_insn_p (t)) - ++ nops; +fix: + t = insn; + for ( ; nops > 0; ) + { + t = cirrus_next_mach_insn (t, &l); + if (!t) + break; + if (GET_CODE (t) == JUMP_INSN + || GET_CODE (t) == CALL_INSN) + { + nops -= l; + break; + } + else if (arm_cirrus_insn_p (t)) + { + attr = get_attr_cirrus (t); + if (attr == CIRRUS_COMPARE) + break; + } + nops -= l; + } - if (arm_cirrus_insn_p (next_nonnote_insn (t))) - ++ nops; + while (nops-- > 0) + emit_insn_after (gen_nop (), insn); /* WARNING: this appears to cause "bad immediate value for offset" errors in the assembler */ +} - while (nops --) - emit_insn_after (gen_nop (), first); +/* Cirrus reorg for bugs #10 and #12 (data aborts). */ +static void +cirrus_reorg_bug10_12 (rtx insn) +{ + rtx t; - return; - } + t = cirrus_next_mach_insn (insn, 0); + if (arm_cirrus_insn_p (t)) + if (TARGET_CIRRUS_D0 || + get_attr_cirrus (t) == CIRRUS_DOUBLE) + emit_insn_after (gen_nop (), insn); /* WARNING: this appears to cause "bad immediate value for offset" errors in the assembler */ } /* Return TRUE if X references a SYMBOL_REF. */ @@ -7727,7 +7796,7 @@ { Mnode * mp; Mnode * nmp; - int align64 = 0; + int align64 = 0, stuffnop = 0; if (ARM_DOUBLEWORD_ALIGN) for (mp = minipool_vector_head; mp != NULL; mp = mp->next) @@ -7742,8 +7811,27 @@ ";; Emitting minipool after insn %u; address %ld; align %d (bytes)\n", INSN_UID (scan), (unsigned long) minipool_barrier->address, align64 ? 8 : 4); + /* Check if branch before minipool is already stuffed with nops. */ + if (TARGET_CIRRUS_D0 || TARGET_CIRRUS_D1) + { + rtx t; + + t = prev_active_insn (scan); + if (GET_CODE (t) != INSN + || PATTERN (t) != const0_rtx) + stuffnop = 1; + } scan = emit_label_after (gen_label_rtx (), scan); scan = emit_insn_after (align64 ? gen_align_8 () : gen_align_4 (), scan); + /* Last instruction was branch, so put two non-Cirrus opcodes. */ + if (stuffnop) + { +#if TARGET_CIRRUS /* This is doubling up on nops, so I don't think this is a good idea */ + emit_insn_before (gen_nop (), scan); /* WARNING: this appears to cause "bad immediate value for offset" errors in the assembler */ + emit_insn_before (gen_nop (), scan); /* WARNING: this appears to cause "bad immediate value for offset" errors in the assembler */ +#endif + } + scan = emit_label_after (minipool_vector_label, scan); for (mp = minipool_vector_head; mp != NULL; mp = nmp) @@ -8151,15 +8239,38 @@ gcc_assert (GET_CODE (insn) == NOTE); minipool_pad = 0; +#if TARGET_CIRRUS /* I think this is a double-up */ + /* Scan all the insn and fix Cirrus issues. */ + if (TARGET_CIRRUS_D0 || TARGET_CIRRUS_D1) + { + rtx t, s; + + for (t = cirrus_next_mach_insn (insn, 0); t; t = cirrus_next_mach_insn (t, 0)) + if (arm_mem_access_p (t)) + cirrus_reorg_bug10_12 (t); + + if (TARGET_CIRRUS_D0) + for (t = cirrus_next_mach_insn (insn, 0); t; t = cirrus_next_mach_insn (t, 0)) + if (arm_cirrus_insn_p (t)) + cirrus_reorg_bug1 (t); + + /* Find last insn. */ + for (t = insn; ; t = s) + { + s = cirrus_next_mach_insn (t, 0); + if (!s) + break; + } + /* Scan backward and fix branches. - WARNING: appears to cause "bad immediate value for offset" problems! */ + for ( ; t; t = cirrus_prev_mach_insn (t, 0)) + if (GET_CODE (t) == JUMP_INSN + || GET_CODE (t) == CALL_INSN) + cirrus_reorg_branch (t); + } +#endif /* Scan all the insns and record the operands that will need fixing. */ for (insn = next_nonnote_insn (insn); insn; insn = next_nonnote_insn (insn)) { - if (TARGET_CIRRUS_FIX_INVALID_INSNS - && (arm_cirrus_insn_p (insn) - || GET_CODE (insn) == JUMP_INSN - || arm_memory_load_p (insn))) - cirrus_reorg (insn); - if (GET_CODE (insn) == BARRIER) push_minipool_barrier (insn, address); else if (INSN_P (insn)) @@ -11755,16 +11910,10 @@ || 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_NOT) + /* To avoid erratic behaviour, we avoid conditional Cirrus + instructions when doing workarounds. */ + if (arm_cirrus_insn_p(this_insn) + && (TARGET_CIRRUS_D0 || TARGET_CIRRUS_D1)) fail = TRUE; break; diff -ruN /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/config/arm/arm.h gcc-4.1.2/gcc/config/arm/arm.h --- /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/config/arm/arm.h 2005-11-05 01:02:51.000000000 +1000 +++ gcc-4.1.2/gcc/config/arm/arm.h 2007-05-15 10:15:05.000000000 +1000 @@ -5,6 +5,7 @@ and Martin Simmons (@harleqn.co.uk). More major hacks by Richard Earnshaw (rearnsha@arm.com) Minor hacks by Nick Clifton (nickc@cygnus.com) + Cirrus Crunch fixes by Vladimir Ivanov (vladitx@nucleusys.com) This file is part of GCC. @@ -140,7 +141,9 @@ %{msoft-float:%{mhard-float: \ %e-msoft-float and -mhard_float may not be used together}} \ %{mbig-endian:%{mlittle-endian: \ - %e-mbig-endian and -mlittle-endian may not be used together}}" + %e-mbig-endian and -mlittle-endian may not be used together}} \ +%{mfix-crunch-d0:%{mfix-crunch-d1: \ + %e-mfix-crunch-d0 and -mfix-crunch-d1 may not be used together}}" #ifndef CC1_SPEC #define CC1_SPEC "" @@ -179,6 +182,9 @@ #define TARGET_HARD_FLOAT_ABI (arm_float_abi == ARM_FLOAT_ABI_HARD) #define TARGET_FPA (arm_fp_model == ARM_FP_MODEL_FPA) #define TARGET_MAVERICK (arm_fp_model == ARM_FP_MODEL_MAVERICK) +#define TARGET_CIRRUS (arm_arch_cirrus) +#define TARGET_CIRRUS_D0 0 /* (target_flags & ARM_FLAG_CIRRUS_D0) */ +#define TARGET_CIRRUS_D1 1 /* (target_flags & ARM_FLAG_CIRRUS_D1) */ #define TARGET_VFP (arm_fp_model == ARM_FP_MODEL_VFP) #define TARGET_IWMMXT (arm_arch_iwmmxt) #define TARGET_REALLY_IWMMXT (TARGET_IWMMXT && TARGET_ARM) diff -ruN /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/config/arm/arm.opt gcc-4.1.2/gcc/config/arm/arm.opt --- /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/config/arm/arm.opt 2005-11-05 01:02:51.000000000 +1000 +++ gcc-4.1.2/gcc/config/arm/arm.opt 2007-05-15 10:09:31.000000000 +1000 @@ -68,6 +68,14 @@ Target Report Mask(CIRRUS_FIX_INVALID_INSNS) Cirrus: Place NOPs to avoid invalid instruction combinations +fix-crunch-d0 +Target Report Mask(ARM_FLAG_CIRRUS_D0) +Cirrus: workarounds for Crunch coprocessor revision D0 + +fix-crunch-d1 +Target Report Mask(ARM_FLAG_CIRRUS_D1) +Cirrus: workarounds for Crunch coprocessor revision D1 + mcpu= Target RejectNegative Joined Specify the name of the target CPU diff -ruN /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/doc/invoke.texi gcc-4.1.2/gcc/doc/invoke.texi --- /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/doc/invoke.texi 2006-09-26 07:21:58.000000000 +1000 +++ gcc-4.1.2/gcc/doc/invoke.texi 2007-05-15 10:07:04.000000000 +1000 @@ -408,7 +408,7 @@ -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 +-mfix-crunch-d0 -mfix-crunch-d1 @gol -mpoke-function-name @gol -mthumb -marm @gol -mtpcs-frame -mtpcs-leaf-frame @gol @@ -7435,17 +7435,12 @@ 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 implementations. The default -can be re-enabled by use of the @option{-mno-cirrus-fix-invalid-insns} -switch. +@item -mfix-crunch-d0 +@itemx -mfix-crunch-d1 +@opindex mfix-crunch-d0 +@opindex mfix-crunch-d1 +Enable workarounds for the Cirrus MaverickCrunch coprocessor revisions +D0 and D1 respectively. @item -mpoke-function-name @opindex mpoke-function-name