https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117468

            Bug ID: 117468
           Summary: arm thumb1 high reg restoration trashes register
                    reserved with -ffixed-reg
           Product: gcc
           Version: 15.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: matt.pa...@go-aps.com
  Target Milestone: ---

ARM thumb1 compilation using -ffixed-reg with r4-r7, without -Os (which
prohibits use of high registers), produces bad high register restoration code
that clobbers the fixed register.

Bug is in gcc/config/arm/arm.cc (or arm.c in older versions) and was introduced
in gcc 10, when functions thumb1_prologue_unused_call_clobbered_lo_regs and
thumb1_epilogue_unused_call_clobbered_lo_regs were added. I believe it affects
all gcc versions greater than 10.

Example source test_hireg.c which excites the problem:
---
void ext_func(int e1, int e2, int e3, int e4);

int bad_func(int p1, int p2, int p3, int p4) {
    ext_func(p4, p3, p2, p1);
    return p1 + p2 + p3 + p4;
}
---

Compile example:
arm-none-eabi-gcc -ffixed-r7 -march=armv5te -mthumb -mabi=apcs-gnu -O2 -S -o
test_hireg.s test_hireg.c

Bad results in test_hireg.s:
Prologue:
    push {r4, r5, r6, lr}
    mov lr, r8
    mov r6, r2
    mov r5, r3
    push {lr}
    mov r8, r0
    ...
Epilogue:
    ...
    pop {r7} <-- violates -ffixed-r7 by clobbering register
    mov r8, r7
    pop {r4, r5, r6, pc}

Problem: thumb1_prologue_unused_call_clobbered_lo_regs and
thumb1_epilogue_unused_call_clobbered_lo_regs create a bitmask of unused
registers that may be used for scratch work. The search omits
callee_saved_reg_p(reg), but does not take into account fixed registers which
are not reported because callee_saved_reg_p returns !call_used_or_fixed_reg_p.

Bugfix:
    Modify both thumb1_prologue_unused_call_clobbered_lo_regs and
thumb1_epilogue_unused_call_clobbered_lo_regs. In the if () statement in each
function, add condition "&& !fixed_regs[reg]".

Epilogue after bugfix:
    ...
    pop {r6} <-- avoids fixed r7 and uses r6 instead
    mov r8, r6
    pop {r4, r5, r6, pc}

Reply via email to