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}