freemint / m68k-atari-mint-gcc

Fork of GNU's gcc with support for the m68k-atari-mint target
https://github.com/freemint/m68k-atari-mint-gcc/wiki
Other
27 stars 7 forks source link

M68K_STRUCT_VALUE_REGNUM (and STATIC_CHAIN_REGNUM) #30

Closed vinriviere closed 1 year ago

vinriviere commented 1 year ago

I open this issue to find a definitive answer to the STRUCT_VALUE_REGNUM question. It has been discussed at several places, including: https://github.com/freemint/m68k-atari-mint-gcc/issues/18#issue-1858676224 https://github.com/freemint/m68k-atari-mint-gcc/issues/26#issuecomment-1713941782

Concretely:

$ git grep M68K_STRUCT_VALUE_REGNUM
...
config/m68k/m68k.h:#define M68K_STRUCT_VALUE_REGNUM A1_REG
config/m68k/m68kelf.h:#define M68K_STRUCT_VALUE_REGNUM A0_REG
config/m68k/netbsd-elf.h:#define M68K_STRUCT_VALUE_REGNUM A0_REG

So basically:

Moreover, m68k-atari-mint-gcc 4.6.4 uses a1, just like default m68k.

It turns out that my initial m68k-atari-mintelf-gcc build used a0, by chance. What's the right setting for a new and modern Atari toolchain?

vinriviere commented 1 year ago

Key point to understand my initial m68k-atari-mintelf settings was that I wanted it to be similar to m68k-elf, to enable all fancy ELF features. But now I understand that using m68k-elf as reference wasn't a good choice, because it also brings in SVR4 ABI oddities which we don't want.

Main configuration issue is there: https://github.com/freemint/m68k-atari-mint-gcc/blob/0e0cacb8c8f25f6a7fc35063b72a2403f21137c4/gcc/config.gcc#L2361

I shouldn't have used m68k/m68kelf.h there. I plan to finally remove it, but before that I want to discuss all the relevant parameters.

vinriviere commented 1 year ago

Testcase: struct.c

struct s
{
    long a, b, c;
};

struct s f(void)
{
    struct s ret = {0};
    return ret;
}
$ m68k-linux-gcc -Os -fomit-frame-pointer -S struct.c -o -
#NO_APP
    .file   "struct.c"
    .text
    .align  2
    .globl  f
    .type   f, @function
f:
    move.l %a1,%a0
    clr.l (%a1)
    clr.l 4(%a1)
    clr.l 8(%a1)
    rts
    .size   f, .-f
    .ident  "GCC: (GCC MiNT ELF 20230819) 13.2.0"
    .section    .note.GNU-stack,"",@progbits
$ m68k-elf-gcc -Os -fomit-frame-pointer -S struct.c -o -
#NO_APP
    .file   "struct.c"
    .text
    .align  2
    .globl  f
    .type   f, @function
f:
    clr.l (%a0)
    clr.l 4(%a0)
    clr.l 8(%a0)
    move.l %a0,%d0
    rts
    .size   f, .-f
    .ident  "GCC: (GCC MiNT ELF 20230819) 13.2.0"
$ m68k-atari-mint-gcc -Os -fomit-frame-pointer -S struct.c -o -
#NO_APP
    .text
    .even
    .globl  _f
_f:
    move.l %d2,-(%sp)
    move.l %a1,%d2
    pea 12.w
    clr.l -(%sp)
    move.l %a1,-(%sp)
    jsr _memset
    lea (12,%sp),%sp
    move.l %d2,%d0
    move.l (%sp)+,%d2
    rts

I leave apart code generation oddities. But we can see that, as expected

So the obvious choice is to configure the new m68k-atari-mintelf-gcc to use a1, just like the default (Linux) behaviour and old atari gcc. I will change that, as I already agreed in https://github.com/freemint/m68k-atari-mint-gcc/issues/26#issuecomment-1714248886.

th-otto commented 1 year ago

What's the right setting for a new and modern Atari toolchain?

Definitely it should stay as before (a1). There is absolutely no reason to change that. And as mentioned before, the shared libs that i deliver depend on that.

vinriviere commented 1 year ago

@th-otto also mentioned the parameter STATIC_CHAIN_REGNUM which is related. Official documentation is here, pretty obscure: https://gcc.gnu.org/onlinedocs/gcc-13.2.0/gccint/Frame-Registers.html#index-STATIC_005fCHAIN_005fREGNUM

Actually, this is related to nested functions (a GCC extension). Nested functions can access the parent function's local variables transparently. This is achieved by passing a hidden pointer to the parent's local variables to the nested function. The "static chain register" is the register used to pass that pointer from the parent to the nested function.

Default (m68k-linux) setting is to use a0 as STATIC_CHAIN_REGNUM: https://github.com/freemint/m68k-atari-mint-gcc/blob/0e0cacb8c8f25f6a7fc35063b72a2403f21137c4/gcc/config/m68k/m68k.h#L412-L413

But m68k-elf, having an SVR4 ABI, uses a1 instead: https://github.com/freemint/m68k-atari-mint-gcc/blob/0e0cacb8c8f25f6a7fc35063b72a2403f21137c4/gcc/config/m68k/m68kelf.h#L91-L94

It's "funny" to see that m68k-linux (default) and m68k-elf (SVR4) use the same pair of registers a0/a1 as M68K_STRUCT_VALUE_REGNUM and STATIC_CHAIN_REGNUM, but with inverted meaning. Of course if one is changed, the other needs to changed, too.

I write this for documentation and memory. As we agreed that I must revert M68K_STRUCT_VALUE_REGNUM to a1, I will also revert STATIC_CHAIN_REGNUM to a0. I will do.

vinriviere commented 1 year ago

Done: https://github.com/freemint/m68k-atari-mint-gcc/commit/cb42ec3d119f6b2f02f5abb282397977dbae07f0 I've rebuilt all my Ubuntu binaries.

For the sake of simplicity, I've just added an override in mint.h. After everything is done, I plan to completely remove the usage of m68k/m68kelf.h. But for now, I prefer to go forward step by step. Slowly but surely.

The testcase works as expected:

$ m68k-atari-mintelf-gcc -Os -fomit-frame-pointer -S struct.c -o -
#NO_APP
    .file   "struct.c"
    .text
    .align  2
    .globl  f
    .type   f, @function
f:
    clr.l (%a1)
    clr.l 4(%a1)
    clr.l 8(%a1)
    move.l %a1,%d0
    rts
    .size   f, .-f
    .ident  "GCC: (GCC MiNT ELF 20231027) 13.2.0"
vinriviere commented 1 year ago

As a summary, right settings for m68k-atari-mint* targets are:

#define STATIC_CHAIN_REGNUM A0_REG 
#define M68K_STATIC_CHAIN_REG_NAME REGISTER_PREFIX "a0"

#define M68K_STRUCT_VALUE_REGNUM A1_REG