diff options
Diffstat (limited to 'packages/gcc/gcc-4.2.4/arm-crunch-cirrus-bugfixes.patch')
-rw-r--r-- | packages/gcc/gcc-4.2.4/arm-crunch-cirrus-bugfixes.patch | 573 |
1 files changed, 573 insertions, 0 deletions
diff --git a/packages/gcc/gcc-4.2.4/arm-crunch-cirrus-bugfixes.patch b/packages/gcc/gcc-4.2.4/arm-crunch-cirrus-bugfixes.patch new file mode 100644 index 0000000000..cb0af8546d --- /dev/null +++ b/packages/gcc/gcc-4.2.4/arm-crunch-cirrus-bugfixes.patch @@ -0,0 +1,573 @@ +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 |