This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
RE: PATCH: PR target/34001: Incorrect x86 fastcall behavior
- From: "Ye, Joey" <joey dot ye at intel dot com>
- To: "H.J. Lu" <hjl at lucon dot org>
- Cc: <jh at suse dot cz>, <ubizjak at gmail dot com>, <gcc-patches at gcc dot gnu dot org>
- Date: Fri, 16 Nov 2007 12:35:47 +0800
- Subject: RE: PATCH: PR target/34001: Incorrect x86 fastcall behavior
- References: <20071109170040.GA12383@lucon.org>
HJ,
You patch has a minor problem that fastcall will pass non-scalar integer parameter in EAX/ECX/EDX, which is still imcompatible to MS fastcall. MSVC pass parameter on stack unless it is scalar integer less equal to 32 bits.
With this patch GCC fastcall passes first parameter in EAX when it is not a scalar integer less equal to 32 bits. Check following example and review the patch fixing it:
#define MAGIC 123
typedef struct {
char c1, c2;
} a_type;
int
#ifdef _GNU_C_
__attribute__ ((fastcall))
#else
__fastcall
#endif
foo(a_type a, int b, int c, int d)
{
return a.c1 + b + c + d;
}
int main()
{
a_type a;
a.c1=MAGIC;
return foo(a,0,1,2) == MAGIC + 1 ? 0 : 1;
}
MSVC 6 and 7:
@foo@16:
00000000: 55 push ebp
00000001: 8B EC mov ebp,esp
00000003: 83 EC 08 sub esp,8
00000006: 89 55 F8 mov dword ptr [ebp-8],edx ;arg3 in edx
00000009: 89 4D FC mov dword ptr [ebp-4],ecx ;arg2 in ecx
0000000C: 0F BE 45 08 movsx eax,byte ptr [ebp+8] ;arg1 in stack
00000010: 03 45 FC add eax,dword ptr [ebp-4]
00000013: 03 45 F8 add eax,dword ptr [ebp-8]
00000016: 03 45 0C add eax,dword ptr [ebp+0Ch] ;arg4 in stack
00000019: 8B E5 mov esp,ebp
0000001B: 5D pop ebp
0000001C: C2 08 00 ret 8
_main:
0000001F: 55 push ebp
00000020: 8B EC mov ebp,esp
00000022: 51 push ecx
00000023: C6 45 FC 7B mov byte ptr [ebp-4],7Bh
00000027: 6A 02 push 2 ;param4 in stack
00000029: BA 01 00 00 00 mov edx,1 ;param3 in edx
0000002E: 33 C9 xor ecx,ecx ;param2 in ecx
00000030: 66 8B 45 FC mov ax,word ptr [ebp-4] ;param1 in eax
00000034: 50 push eax
00000035: E8 00 00 00 00 call 0000003A
0000003A: 33 C9 xor ecx,ecx
0000003C: 83 F8 7C cmp eax,7Ch
0000003F: 0F 95 C1 setne cl
00000042: 8B C1 mov eax,ecx
00000044: 8B E5 mov esp,ebp
00000046: 5D pop ebp
00000047: C3 ret
GCC 4.3 with your fastcall patch:
.file "f.c"
.text
.globl foo
.type foo, @function
foo:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movw %ax, -2(%ebp) ;arg1 in eax
movl %edx, -8(%ebp) ;arg2 in edx
movzbl -2(%ebp), %eax
movsbl %al,%eax
addl -8(%ebp), %eax
addl 8(%ebp), %eax ;arg3 in stack
addl 12(%ebp), %eax ;arg4 in stack
leave
ret $8
.size foo, .-foo
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $24, %esp
movb $123, -6(%ebp)
movzwl -6(%ebp), %eax ; param1 in eax
movl $2, 4(%esp) ; param4 in stack
movl $1, (%esp) ; param3 in stack
movl $0, %edx ; param2 in edx
call foo
subl $8, %esp
cmpl $124, %eax
setne %al
movzbl %al, %eax
movl -4(%ebp), %ecx
leave
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (GNU) 4.3.0 20071104 (experimental) [trunk revision 129880]"
.section .note.GNU-stack,"",@progbits
Here is a patch to fix it:
Index: gcc/config/i386/i386.c
===================================================================
--- gcc/config/i386/i386.c (revision 129880)
+++ gcc/config/i386/i386.c (working copy)
@@ -4229,9 +4229,12 @@
int regno = cum->regno;
/* Fastcall allocates the first two DWORD (SImode) or
- smaller arguments to ECX and EDX. */
+ smaller arguments to ECX and EDX if it isn't an
+ aggregate type . */
if (cum->fastcall)
{
+ if (type && AGGREGATE_TYPE_P (type))
+ break;
if (mode == BLKmode || mode == DImode)
break;
With this patch generated code will be:
.file "f.c"
.text
.globl foo
.type foo, @function
foo:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl %edx, -4(%ebp)
movzbl 8(%ebp), %eax
movsbl %al,%eax
addl -4(%ebp), %eax
addl 12(%ebp), %eax
addl 16(%ebp), %eax
leave
ret $12
.size foo, .-foo
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $28, %esp
movb $123, -6(%ebp)
movl $2, 8(%esp)
movl $1, 4(%esp)
movzwl -6(%ebp), %eax
movw %ax, (%esp)
movl $0, %edx
call foo
subl $12, %esp
cmpl $124, %eax
setne %al
movzbl %al, %eax
movl -4(%ebp), %ecx
leave
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (GNU) 4.3.0 20071104 (experimental) [trunk revision 129880]"
.section .note.GNU-stack,"",@progbits
Thanks - Joey
-----Original Message-----
From: gcc-patches-owner@gcc.gnu.org [mailto:gcc-patches-owner@gcc.gnu.org] On Behalf Of H.J. Lu
Sent: 2007年11月10日 1:01
To: gcc-patches@gcc.gnu.org
Cc: jh@suse.cz; ubizjak@gmail.com
Subject: PATCH: PR target/34001: Incorrect x86 fastcall behavior
From
http://msdn2.microsoft.com/en-us/library/6xa169sk(VS.80).aspx
"The first two DWORD or smaller arguments are passed in ECX and EDX
registers; all other arguments are passed right to left."
But it isn't clear if it applies to structure/union. We tested all MS
compilers we have and verified that the above doesn't apply to
structure/union. To make fastcall compatible with MS compilers, we
should only put scalar arguments in ECX and EDX.
H.J.
---
2007-11-09 H.J. Lu <hongjiu.lu@intel.com>
PR target/34001
* config/i386/i386.c (function_arg_32): Don't pass aggregate
arguments in ECX/EDX for fastcall.
--- gcc/config/i386/i386.c.fastcall 2007-11-06 19:52:12.000000000 -0800
+++ gcc/config/i386/i386.c 2007-11-08 11:48:38.000000000 -0800
@@ -4233,8 +4233,10 @@ function_arg_32 (CUMULATIVE_ARGS *cum, e
int regno = cum->regno;
/* Fastcall allocates the first two DWORD (SImode) or
- smaller arguments to ECX and EDX. */
- if (cum->fastcall)
+ smaller arguments to ECX and EDX if it isn't an
+ aggregate type . */
+ if (cum->fastcall
+ && (!type || !AGGREGATE_TYPE_P (type)))
{
if (mode == BLKmode || mode == DImode)
break;