https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113293

            Bug ID: 113293
           Summary: Incorrect code after inlining function containing
                    extended asm
           Product: gcc
           Version: 14.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: ipa
          Assignee: unassigned at gcc dot gnu.org
          Reporter: dories.spirits_0p at icloud dot com
                CC: marxin at gcc dot gnu.org
  Target Milestone: ---

GCC compiles the following code (with -O3 -std=gnu2x):

#include <stdint.h>

#define SYSCALL_GETCHAR 1
#define SYSCALL_THREAD_CREATE 2

typedef void (*thread_func)(void *);

static inline char getc() {
    register char r0 asm("r0");
    asm volatile ("svc %[syscall]" 
                   : "=r" (r0)
                   : [syscall] "i" (SYSCALL_GETCHAR)
                   : "r1", "r2", "r3");
    return r0;
}

static inline void thread_create(thread_func func, const void * args, uint32_t
args_size) {
    register uint32_t r0 asm("r0") = (uint32_t) func;
    register uint32_t r1 asm("r1") = (uint32_t) args;
    register uint32_t r2 asm("r2") = args_size;
    asm volatile ("svc %[syscall]" 
                   : "+r" (r0), "+r" (r1), "+r" (r2)
                   : [syscall] "i" (SYSCALL_THREAD_CREATE), "r" (r0), "r" (r1),
"r" (r2)
                   : "r3");
}

void worker([[maybe_unused]] void *x) {}

void main() {
        while (true) {
                char arg = getc();
                thread_create(worker, &arg, sizeof(arg));
        }
}

into something like

main:
        movw    ip, #:lower16:worker
        sub     sp, sp, #8
        movt    ip, #:upper16:worker
.L4:
        svc #1             //char getc()
        mov     r2, #1
        mov     r0, ip     //return value of 'getc' svc call overwritten
        add     r1, sp, #7 //nothing in the stack here!
        svc #2             
        b       .L4

The return value of 'getc' is overwritten/not stored on the stack with -O1 and
higher (-Og and -O0 are not affected). I've tested on a local copy of
arm-none-eabi-gcc 10.2.0 as well as arm gcc trunk (arm-unknown-linux-gnueabihf
14.0.0 20240108) on compiler explorer.

I've also tested clang 17 targeting arm-none-eabi, which correctly stores the
result of the 'getc' svc call on the stack in all optimization levels:

.LBB1_1:
        svc     #1
        strb    r0, [sp, #3]
        [...]

ARM GCC trunk and Clang trunk:
https://godbolt.org/z/ercEYfacM

If 'getc' is marked noinline, r0 is correctly saved to the stack:

.L5:
        bl      getc
        strb    r0, [sp, #7] //saved to stack
        add     r1, sp, #7
        [...]
        svc #2
        b       .L5

With [[gnu::noinline]]
https://godbolt.org/z/ETManW1hY

This is my first bug, so please let me know if there's anything else I need to
provide.

Reply via email to