[PATCH][ARM] PR target/70830: Avoid POP-{reglist}^ when returning from interrupt handlers
Kyrill Tkachov
kyrylo.tkachov@foss.arm.com
Thu May 12 09:24:00 GMT 2016
Ping.
https://gcc.gnu.org/ml/gcc-patches/2016-05/msg00395.html
Thanks,
Kyrill
On 05/05/16 12:50, Kyrill Tkachov wrote:
> Hi all,
>
> In this PR we deal with some fallout from the conversion to unified assembly.
> We now end up emitting instructions like:
> pop {r0,r1,r2,r3,pc}^
> which is not legal. We have to use an LDM form.
>
> There are bugs in two arm.c functions: output_return_instruction and arm_output_multireg_pop.
>
> In output_return_instruction the buggy hunk from the conversion was:
> else
> - if (TARGET_UNIFIED_ASM)
> sprintf (instr, "pop%s\t{", conditional);
> - else
> - sprintf (instr, "ldm%sfd\t%%|sp!, {", conditional);
>
> The code was already very obscurely structured and arguably the bug was latent.
> It emitted POP only when TARGET_UNIFIED_ASM was on, and since TARGET_UNIFIED_ASM was on
> only for Thumb, we never went down this path interrupt handling code, since the interrupt
> attribute is only available for ARM code. After the removal of TARGET_UNIFIED_ASM we ended up
> using POP unconditionally. So this patch adds a check for IS_INTERRUPT and outputs the
> appropriate LDM form.
>
> In arm_output_multireg_pop the buggy hunk was:
> - if ((regno_base == SP_REGNUM) && TARGET_THUMB)
> + if ((regno_base == SP_REGNUM) && update)
> {
> - /* Output pop (not stmfd) because it has a shorter encoding. */
> - gcc_assert (update);
> sprintf (pattern, "pop%s\t{", conditional);
> }
>
> Again, the POP was guarded on TARGET_THUMB and so would never be taken on interrupt handling
> routines. This patch guards that with the appropriate check on interrupt return.
>
> Also, there are a couple of bugs in the 'else' branch of that 'if':
> * The "ldmfd%s" was output without a '\t' at the end which meant that the base register
> name would be concatenated with the 'ldmfd', creating invalid assembly.
>
> * The logic:
>
> if (regno_base == SP_REGNUM)
> /* update is never true here, hence there is no need to handle
> pop here. */
> sprintf (pattern, "ldmfd%s", conditional);
>
> if (update)
> sprintf (pattern, "ldmia%s\t", conditional);
> else
> sprintf (pattern, "ldm%s\t", conditional);
>
> Meant that for "regno == SP_REGNUM && !update" we'd end up printing "ldmfd%sldm%s\t"
> to pattern. I didn't manage to reproduce that condition though, so maybe it can't ever occur.
> This patch fixes both these issues nevertheless.
>
> I've added the testcase from the PR to catch the fix in output_return_instruction.
> The testcase doesn't catch the bugs in arm_output_multireg_pop, but the existing tests
> gcc.target/arm/interrupt-1.c and gcc.target/arm/interrupt-2.c would have caught them
> if only they were assemble tests rather than just compile. So this patch makes them
> assembly tests (and reverts the scan-assembler checks for the correct LDM pattern).
>
> Bootstrapped and tested on arm-none-linux-gnueabihf.
> Ok for trunk and GCC 6?
>
> Thanks,
> Kyrill
>
> 2016-05-05 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
>
> PR target/70830
> * config/arm/arm.c (arm_output_multireg_pop): Avoid POP instruction
> when popping the PC and within an interrupt handler routine.
> Add missing tab to output of "ldmfd".
> (output_return_instruction): Output LDMFD with SP update rather
> than POP when returning from interrupt handler.
>
> 2016-05-05 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
>
> PR target/70830
> * gcc.target/arm/interrupt-1.c: Change dg-compile to dg-assemble.
> Add -save-temps to dg-options.
> Scan for ldmfd rather than pop instruction.
> * gcc.target/arm/interrupt-2.c: Likewise.
> * gcc.target/arm/pr70830.c: New test.
More information about the Gcc-patches
mailing list