Optimization bug on function and lambda return

Bug #1840776 reported by Baptiste Cartier on 2019-08-20
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
GNU Arm Embedded Toolchain
Undecided
Unassigned

Bug Description

When calling a function or a lambda to create function arguments, the stack is not reused properly.

See question (no discussion here):
https://answers.launchpad.net/gcc-arm-embedded/+question/682825

Discussion about this bug can be found here :
https://community.arm.com/developer/tools-software/tools/f/arm-compilers-forum/13366/arm-gcc-lambda-optimization/159463#159463

The following code can reproduce the problem :
-----------------------------------------------------------

#include <stdint.h>
#include <stdio.h>

   struct TestStruct
    {
        uint32_t field1;
        uint32_t field2;
        uint32_t field3;
        uint32_t field4;

        uint32_t field11;
        uint32_t field21;
        uint32_t field31;
        uint32_t field41;
    } ;

    struct TestStruct initStructure(uint32_t f1, uint32_t f2, uint32_t f3, uint32_t f4,uint32_t f11, uint32_t f21, uint32_t f31, uint32_t f41)
    {
        struct TestStruct myStruct;
        myStruct.field1 = f1;
        myStruct.field2 = f2;
        myStruct.field3 = f3;
        myStruct.field4 = f4;

        myStruct.field11 = f11;
        myStruct.field21 = f21;
        myStruct.field31 = f31;
        myStruct.field41 = f41;

        return myStruct;
    }

#define MACROLAMBDA(f1,f2,f3,f4,f5,f6,f7,f8) \
    [&]() -> struct TestStruct { struct TestStruct ${}; \
    $.field1 = f1; \
    $.field2 = f2; \
    $.field3 = f3; \
    $.field4 = f4; \
    $.field11 = f5; \
    $.field21 = f6; \
    $.field31 = f7; \
    $.field41 = f8; \
    return $; \
}()

    void __attribute__((noinline)) doStuff(struct TestStruct myStruct)
    {
        printf("f1 = %d, f2 = %d, f3 = %d, f4 = %d, f1 = %d, f2 = %d, f3 = %d, f4 = %d", myStruct.field1, myStruct.field2, myStruct.field3, myStruct.field4,myStruct.field11, myStruct.field21, myStruct.field31, myStruct.field41);
    }

    void __attribute__((noinline)) wrapper2LAMBDA(void)
    {
        doStuff(MACROLAMBDA(1,2,3,4,5,6,7,8));
        doStuff(MACROLAMBDA(11,22,33,44,55,66,77,88));
    }

    void __attribute__((noinline)) wrapper1LAMBDA(void)
    {
        doStuff(MACROLAMBDA(1,2,3,4,5,6,7,8));
    }

    void __attribute__((noinline)) wrapper1func(void)
    {
        doStuff(initStructure(1,2,3,4,5,6,7,8));
    }

    void __attribute__((noinline)) wrapper2func(void)
    {
        doStuff(initStructure(1,2,3,4,5,6,7,8));
        doStuff(initStructure(11,22,33,44,55,66,77,88));
    }

    int main(void)
    {

        wrapper1LAMBDA();
        wrapper2LAMBDA();

        wrapper1func();
        wrapper2func();

        return 0;
    }

-----------------------------------------------------------

Consider doStuff as non inlinable.

With -O2 or -O3 wrapper1LAMBDA uses 52 bytes of stack whereas wrapper2LAMBDA uses 80. The same happens for wrapper1func and wrapper2func.

It seems that the compiler does not reused the stack slot but it should in this case.

The bug was encountered with :
- GCC: (GNU Tools for Arm Embedded Processors 8-2019-q3-update) 8.3.1 20190703 (release) [gcc-8-branch revision 273027]
- Toolchain binary downloaded at https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads
- Host machine is a Windows 10 64bits
- Target System is a STM32L4
- Preprocessed test cases are attached with assembly generated for comparison
- Bug happens when compiling in C++ (and in C without lambdas)

Baptiste Cartier (bcartier) wrote :
To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers