From 5fd424238b25fd8ff6ac403ef923bdce2b2b2347 Mon Sep 17 00:00:00 2001 From: Paul Brook Date: Thu, 13 Nov 2008 15:19:02 +0000 Subject: [PATCH] invoke.texi: Document --fix-cortex-m3. 2008-11-13 Paul Brook gcc/ * doc/invoke.texi: Document --fix-cortex-m3. * config/arm/arm.c (arm_override_options): Set fix_cm3_ldrd if Cortex-M3 cpu is selected. (output_move_double): Avoid overlapping base register and first destination register when fix_cm3_ldrd. * config/arm/arm.opt: Add mfix-cortex-m3-ldrd. From-SVN: r141822 --- gcc/ChangeLog | 9 ++++++ gcc/config/arm/arm.c | 70 +++++++++++++++++++++++++++++------------- gcc/config/arm/arm.opt | 7 ++++- gcc/doc/invoke.texi | 12 ++++++-- 4 files changed, 74 insertions(+), 24 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0ec0db60603..2ae685a51e8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2008-11-13 Paul Brook + + * doc/invoke.texi: Document --fix-cortex-m3. + * config/arm/arm.c (arm_override_options): Set fix_cm3_ldrd if + Cortex-M3 cpu is selected. + (output_move_double): Avoid overlapping base register and first + destination register when fix_cm3_ldrd. + * config/arm/arm.opt: Add mfix-cortex-m3-ldrd. + 2008-11-13 Jakub Jelinek PR bootstrap/38100 diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index aeb0e53ea72..a1cef0bd103 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -1037,6 +1037,7 @@ arm_override_options (void) { unsigned i; enum processor_type target_arch_cpu = arm_none; + enum processor_type selected_cpu = arm_none; /* Set up the flags based on the cpu/architecture selected by the user. */ for (i = ARRAY_SIZE (arm_select); i--;) @@ -1069,6 +1070,9 @@ arm_override_options (void) if (i == ARM_OPT_SET_ARCH) target_arch_cpu = sel->core; + if (i == ARM_OPT_SET_CPU) + selected_cpu = (enum processor_type) (sel - ptr->processors); + if (i != ARM_OPT_SET_TUNE) { /* If we have been given an architecture and a processor @@ -1099,21 +1103,20 @@ arm_override_options (void) { const struct processors * sel; unsigned int sought; - enum processor_type cpu; - cpu = TARGET_CPU_DEFAULT; - if (cpu == arm_none) + selected_cpu = TARGET_CPU_DEFAULT; + if (selected_cpu == arm_none) { #ifdef SUBTARGET_CPU_DEFAULT /* Use the subtarget default CPU if none was specified by configure. */ - cpu = SUBTARGET_CPU_DEFAULT; + selected_cpu = SUBTARGET_CPU_DEFAULT; #endif /* Default to ARM6. */ - if (cpu == arm_none) - cpu = arm6; + if (selected_cpu == arm_none) + selected_cpu = arm6; } - sel = &all_cores[cpu]; + sel = &all_cores[selected_cpu]; insn_flags = sel->flags; @@ -1505,6 +1508,15 @@ arm_override_options (void) arm_pic_register = pic_register; } + /* Enable -mfix-cortex-m3-ldrd by default for Cortex-M3 cores. */ + if (fix_cm3_ldrd == 2) + { + if (selected_cpu == cortexm3) + fix_cm3_ldrd = 1; + else + fix_cm3_ldrd = 0; + } + /* ??? We might want scheduling for thumb2. */ if (TARGET_THUMB && flag_schedule_insns) { @@ -9978,7 +9990,8 @@ output_move_double (rtx *operands) switch (GET_CODE (XEXP (operands[1], 0))) { case REG: - if (TARGET_LDRD) + if (TARGET_LDRD + && !(fix_cm3_ldrd && reg0 == REGNO(XEXP (operands[1], 0)))) output_asm_insn ("ldr%(d%)\t%0, [%m1]", operands); else output_asm_insn ("ldm%(ia%)\t%m1, %M0", operands); @@ -10010,6 +10023,10 @@ output_move_double (rtx *operands) case PRE_MODIFY: case POST_MODIFY: + /* Autoicrement addressing modes should never have overlapping + base and destination registers, and overlapping index registers + are already prohibited, so this doesn't need to worry about + fix_cm3_ldrd. */ otherops[0] = operands[0]; otherops[1] = XEXP (XEXP (XEXP (operands[1], 0), 1), 0); otherops[2] = XEXP (XEXP (XEXP (operands[1], 0), 1), 1); @@ -10062,11 +10079,15 @@ output_move_double (rtx *operands) /* We might be able to use ldrd %0, %1 here. However the range is different to ldr/adr, and it is broken on some ARMv7-M implementations. */ - output_asm_insn ("adr%?\t%0, %1", operands); + /* Use the second register of the pair to avoid problematic + overlap. */ + otherops[1] = operands[1]; + output_asm_insn ("adr%?\t%0, %1", otherops); + operands[1] = otherops[0]; if (TARGET_LDRD) - output_asm_insn ("ldr%(d%)\t%0, [%0]", operands); + output_asm_insn ("ldr%(d%)\t%0, [%1]", operands); else - output_asm_insn ("ldm%(ia%)\t%0, %M0", operands); + output_asm_insn ("ldm%(ia%)\t%1, %M0", operands); break; /* ??? This needs checking for thumb2. */ @@ -10099,30 +10120,37 @@ output_move_double (rtx *operands) return ""; } } + otherops[0] = gen_rtx_REG(SImode, REGNO(operands[0]) + 1); + operands[1] = otherops[0]; if (TARGET_LDRD && (GET_CODE (otherops[2]) == REG || (GET_CODE (otherops[2]) == CONST_INT && INTVAL (otherops[2]) > -256 && INTVAL (otherops[2]) < 256))) { - if (reg_overlap_mentioned_p (otherops[0], + if (reg_overlap_mentioned_p (operands[0], otherops[2])) { + rtx tmp; /* Swap base and index registers over to avoid a conflict. */ - otherops[1] = XEXP (XEXP (operands[1], 0), 1); - otherops[2] = XEXP (XEXP (operands[1], 0), 0); + tmp = otherops[1]; + otherops[1] = otherops[2]; + otherops[2] = tmp; } /* If both registers conflict, it will usually have been fixed by a splitter. */ - if (reg_overlap_mentioned_p (otherops[0], otherops[2])) + if (reg_overlap_mentioned_p (operands[0], otherops[2]) + || (fix_cm3_ldrd && reg0 == REGNO (otherops[1]))) { - output_asm_insn ("add%?\t%1, %1, %2", otherops); - output_asm_insn ("ldr%(d%)\t%0, [%1]", - otherops); + output_asm_insn ("add%?\t%0, %1, %2", otherops); + output_asm_insn ("ldr%(d%)\t%0, [%1]", operands); } else - output_asm_insn ("ldr%(d%)\t%0, [%1, %2]", otherops); + { + otherops[0] = operands[0]; + output_asm_insn ("ldr%(d%)\t%0, [%1, %2]", otherops); + } return ""; } @@ -10140,9 +10168,9 @@ output_move_double (rtx *operands) output_asm_insn ("sub%?\t%0, %1, %2", otherops); if (TARGET_LDRD) - return "ldr%(d%)\t%0, [%0]"; + return "ldr%(d%)\t%0, [%1]"; - return "ldm%(ia%)\t%0, %M0"; + return "ldm%(ia%)\t%1, %M0"; } else { diff --git a/gcc/config/arm/arm.opt b/gcc/config/arm/arm.opt index c8bdcf80f48..1d07cedf0de 100644 --- a/gcc/config/arm/arm.opt +++ b/gcc/config/arm/arm.opt @@ -159,4 +159,9 @@ Use Neon quad-word (rather than double-word) registers for vectorization mword-relocations Target Report Var(target_word_relocations) Init(TARGET_DEFAULT_WORD_RELOCATIONS) -+Only generate absolute relocations on word sized values. +Only generate absolute relocations on word sized values. + +mfix-cortex-m3-ldrd +Target Report Var(fix_cm3_ldrd) Init(2) +Avoid overlapping destination and address registers on LDRD instructions +that may trigger Cortex-M3 errata. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 3f6f400f6dc..ce621520fce 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -452,8 +452,9 @@ Objective-C and Objective-C++ Dialects}. -mthumb -marm @gol -mtpcs-frame -mtpcs-leaf-frame @gol -mcaller-super-interworking -mcallee-super-interworking @gol --mtp=@var{name} --mword-relocations} +-mtp=@var{name} @gol +-mword-relocations @gol +-mfix-cortex-m3-ldrd} @emph{AVR Options} @gccoptlist{-mmcu=@var{mcu} -msize -minit-stack=@var{n} -mno-interrupts @gol @@ -8708,6 +8709,13 @@ Put functions, data, and readonly data in @var{text-section}, by default. This can be overridden with the @code{section} attribute. @xref{Variable Attributes}. +@item -mfix-cortex-m3-ldrd +@opindex mfix-cortex-m3-ldrd +Some Cortex-M3 cores can cause data corruption when @code{ldrd} instructions +with overlapping destination and base registers are used. This option avoids +generating these instructions. This option is enabled by default when +@option{-mcpu=cortex-m3} is specified. + @end table @node ARM Options