llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.13k stars 12.01k forks source link

clang fastcall x86 abi does not match gcc on unix #109987

Closed m-lw closed 1 day ago

m-lw commented 1 month ago

Some uses of fastcall in the x86 abi no longer match what gcc has always generated on unix. This changed in llvm 16 and is probably the result of the fix for #57737. Possibly this fix should have only applied to MS Windows targets?

E.g. compiling this code with the -O option on FreeBSD 13.3 with clang version 19.0.0git (snapshot from 2024-05-10):

typedef union { long long l ; double d ; } res_val_union;
#define FASTCALL_ATTRIBUTE  __attribute__ ((fastcall))

static res_val_union fastcall_results_vector[100] ;

res_val_union* fastcall_type_results_5(void) { return fastcall_results_vector ;}

int  FASTCALL_ATTRIBUTE  fastcall_ilc_5(long long arg_1, signed char arg_2)
{
  fastcall_results_vector[0].l = (long long)arg_1;
  fastcall_results_vector[1].l = (long long)arg_2;
  return 50;
}

gives this code:

fastcall_ilc_5:                         # @fastcall_ilc_5
    .cfi_startproc
# %bb.0:                                # %entry
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset %ebp, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register %ebp
    movl    8(%ebp), %eax
    movl    12(%ebp), %edx
    movl    %edx, fastcall_results_vector+4
    movl    %eax, fastcall_results_vector
    movsbl  %cl, %eax
    movl    %eax, fastcall_results_vector+8
    sarl    $31, %eax
    movl    %eax, fastcall_results_vector+12
    movl    $50, %eax
    popl    %ebp
    .cfi_def_cfa %esp, 4
    retl    $8

whereas in gcc version 15.0.0 20240630 (experimental) it gives:

fastcall_ilc_5:
    pushl   %ebp
    movl    %esp, %ebp
    movl    8(%ebp), %eax
    movl    12(%ebp), %edx
    movl    %eax, fastcall_results_vector
    movl    %edx, fastcall_results_vector+4
    movsbl  16(%ebp), %eax
    movl    %eax, fastcall_results_vector+8
    cltd
    movl    %edx, fastcall_results_vector+12
    movl    $50, %eax
    popl    %ebp
    ret $12

Note that the second argument is in %cl in clang but is on the stack in gcc.

llvmbot commented 1 month ago

@llvm/issue-subscribers-backend-x86

Author: None (m-lw)

Some uses of fastcall in the x86 abi no longer match what gcc has always generated on unix. This changed in llvm 16 and is probably the result of the fix for #57737. Possibly this fix should have only applied to MS Windows targets? E.g. compiling this code with the -O option on FreeBSD 13.3 with clang version 19.0.0git (snapshot from 2024-05-10): ``` typedef union { long long l ; double d ; } res_val_union; #define FASTCALL_ATTRIBUTE __attribute__ ((fastcall)) static res_val_union fastcall_results_vector[100] ; res_val_union* fastcall_type_results_5(void) { return fastcall_results_vector ;} int FASTCALL_ATTRIBUTE fastcall_ilc_5(long long arg_1, signed char arg_2) { fastcall_results_vector[0].l = (long long)arg_1; fastcall_results_vector[1].l = (long long)arg_2; return 50; } ``` gives this code: ``` fastcall_ilc_5: # @fastcall_ilc_5 .cfi_startproc # %bb.0: # %entry pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset %ebp, -8 movl %esp, %ebp .cfi_def_cfa_register %ebp movl 8(%ebp), %eax movl 12(%ebp), %edx movl %edx, fastcall_results_vector+4 movl %eax, fastcall_results_vector movsbl %cl, %eax movl %eax, fastcall_results_vector+8 sarl $31, %eax movl %eax, fastcall_results_vector+12 movl $50, %eax popl %ebp .cfi_def_cfa %esp, 4 retl $8 ``` whereas in gcc version 15.0.0 20240630 (experimental) it gives: ``` fastcall_ilc_5: pushl %ebp movl %esp, %ebp movl 8(%ebp), %eax movl 12(%ebp), %edx movl %eax, fastcall_results_vector movl %edx, fastcall_results_vector+4 movsbl 16(%ebp), %eax movl %eax, fastcall_results_vector+8 cltd movl %edx, fastcall_results_vector+12 movl $50, %eax popl %ebp ret $12 ``` Note that the second argument is in `%cl` in clang but is on the stack in gcc.
AaronBallman commented 2 days ago

CC @phoebewang @rnk as author/reviewer for the original changes. It does seem like the original changes maybe should have only applied when we're trying to be compatible with MSVC?

rnk commented 2 days ago

This feels like a GCC bug, but I doubt they will make any change. It would be reasonable to thread isWindowsMSVCEnvironment into the boolean logic that controls whether we update the free register set.

m-lw commented 2 days ago

Just to be clear, this is not something specific to GCC 15. The oldest GCC that I have easy access to is 4.1.2 and that also passes the second argument on the stack.

phoebewang commented 1 day ago