This is an archive of the discontinued LLVM Phabricator instance.

[ARM] Fix incorrect conversion of a tail call to an ordinary call
ClosedPublic

Authored by chill on Nov 3 2017, 7:28 AM.

Details

Summary

Compiling the following program:

int g(int), h(int, int, int, int, int);

int f(int a, int b, int c, int d, int e) {
  a = g(a);
  if (a == -1)
    return -1;
  return h(a, b, c, d, e);
}

with clang -target arm-arm-none-eabi -mcpu=cortex-m23 -O2 produced this assembly:

f:
        .fnstart
        .save   {r4, r5, r6, r7, lr}
        push    {r4, r5, r6, r7, lr}
        .setfp  r7, sp, #12
        add     r7, sp, #12
        .pad    #4
        sub     sp, #4
        mov     r4, r3
        mov     r5, r2
        mov     r6, r1
        bl      g
        adds    r1, r0, #1
        beq     .LBB0_2
        mov     r1, r6
        mov     r2, r5
        mov     r3, r4
        bl      h
        add     sp, #4
        pop     {r4, r5, r6, r7, pc}
.LBB0_2:
        movs    r0, #0
        mvns    r0, r0
        add     sp, #4
        pop     {r4, r5, r6, r7, pc}

Here, the function h is called with an incorrect stack argument. The reason is that the compiler originally created a tail call to h , but then
converted it to an ordinary call because LR was saved by the function and restoring LR is a bit more involved for Armv6m/Armv8m.base (a.k.a. "16-bit Thumb") and negates the benefits of the tail call. Unfortunately, this conversion is incorrect for functions, which have stack arguments as nothing has been done to pass the stack arguments to the callee.

Not doing that conversion and leaving the task of properly restoring LR to emitPopSpecialFixUp solves the correctness problem.
Unfortunately, for functions, which do save LR and tail-call a function without stack arguments we generate a slightly worse code.

Now, moving to emitPopSpecialFixUp, in the case we couldn't immediately find a "pop-friendly" register, but we have a pop instructions, we
can use as a temporary one of the callee-saved low registers and restore LR before popping other calle-saves.

After the patch, the code, generated for the tail-call looks like:

ldr     r4, [sp, #20]
mov     lr, r4
pop     {r4, r5, r6, r7}
add     sp, #4
b       h

Diff Detail

Repository
rL LLVM

Event Timeline

chill created this revision.Nov 3 2017, 7:28 AM
rogfer01 added inline comments.
lib/Target/ARM/Thumb1FrameLowering.cpp
516 ↗(On Diff #121461)

Perhaps you meant const BitVector & here?

chill marked an inline comment as done.Nov 3 2017, 9:28 AM
chill added inline comments.
lib/Target/ARM/Thumb1FrameLowering.cpp
516 ↗(On Diff #121461)

Yeah, absolutely. Fixed, will upload with other (eventual) changes.

chill updated this revision to Diff 122221.Nov 9 2017, 3:27 AM
chill marked an inline comment as done.

Fix accidental pass-by-value (parameter should have reference type).

Please fix the comment in ARMSubtarget::initSubtargetFeatures to match what you're doing.

chill updated this revision to Diff 122626.Nov 13 2017, 2:42 AM

Thanks for the comments. Comment in ARMSubtarget::initSubtargetFeatures updated.

efriedma accepted this revision.Nov 13 2017, 12:13 PM
efriedma added a subscriber: sanwou01.

Please make it clear in the commit message that this reverts D29020/r294000; otherwise, LGTM.

This revision is now accepted and ready to land.Nov 13 2017, 12:13 PM
This revision was automatically updated to reflect the committed changes.
chill added a comment.Nov 14 2017, 2:39 AM

Many thanks for the review.