[PATCH][ARM] PR target/70830: Avoid POP-{reglist}^ when returning from interrupt handlers

Kyrill Tkachov kyrylo.tkachov@foss.arm.com
Tue May 24 13:48:00 GMT 2016


Ping.
https://gcc.gnu.org/ml/gcc-patches/2016-05/msg01211.html

Thanks,
Kyrill

On 17/05/16 11:40, Kyrill Tkachov wrote:
>
> On 13/05/16 12:05, Kyrill Tkachov wrote:
>> Hi Christophe,
>>
>> On 12/05/16 20:57, Christophe Lyon wrote:
>>> On 12 May 2016 at 11:48, Ramana Radhakrishnan <ramana.gcc@googlemail.com> wrote:
>>>> On Thu, May 5, 2016 at 12:50 PM, Kyrill Tkachov
>>>> <kyrylo.tkachov@foss.arm.com> 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?
>>>>>
>>> Hi Kyrill,
>>>
>>> Did you test --with-mode=thumb?
>>> When using arm mode, I see regressions:
>>>
>>>    gcc.target/arm/neon-nested-apcs.c (test for excess errors)
>>>    gcc.target/arm/nested-apcs.c (test for excess errors)
>>
>> It's because I have a local patch in my binutils that makes gas warn on the
>> deprecated sequences that these two tests generate (they use the deprecated -mapcs option),
>> so these tests were already showing the (test for excess errors) FAIL for me,
>> so I they didn't appear in my tests diff for this patch. :(
>>
>> I've reproduced the failure with a clean tree.
>> Where before we generated:
>>     ldm    sp, {fp, sp, pc}
>> now we generate:
>>     pop    {fp, sp, pc}
>>
>> which are not equivalent (pop performs a write-back) and gas warns:
>> Warning: writeback of base register when in register list is UNPREDICTABLE
>>
>> I'm testing a patch to fix this.
>> Sorry for the regression.
>
> Here is the fix.
> I had remove the update from the condition for the "pop" erroneously. Of course, if we're not
> updating the SP we can't use POP that has an implicit writeback.
>
> Bootstrapped on arm-none-linux-gnueabihf. Tested with -mthumb and -marm.
>
> Ok for trunk and GCC 6?
>
> Thanks,
> Kyrill
>
> 2016-05-17  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
>
>     PR target/70830
>     * config/arm/arm.c (arm_output_multireg_pop): Guard "pop" on update.
>



More information about the Gcc-patches mailing list