Bug 42324 - Gcc doesn't follow x86-64 psABI on _Bool
Summary: Gcc doesn't follow x86-64 psABI on _Bool
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 4.5.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks: 46942
  Show dependency treegraph
 
Reported: 2009-12-07 18:18 UTC by H.J. Lu
Modified: 2011-01-02 17:58 UTC (History)
6 users (show)

See Also:
Host:
Target: x86_64-*-linux-gnu
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
Source and object files (3.50 KB, application/octet-stream)
2009-12-09 17:43 UTC, H.J. Lu
Details

Note You need to log in before you can comment on or make changes to this bug.
Description H.J. Lu 2009-12-07 18:18:56 UTC
x86-64 psABI says:

---
When a value of type _Bool is passed in a register or on the stack,
the upper 63 bits of the eightbyte shall be zero.
---

However, gcc generates:

[hjl@gnu-6 tmp]$ cat b.c
_Bool myfunction(char val)
{
  return val;
}
[hjl@gnu-6 tmp]$ gcc -O2 -S b.c
[hjl@gnu-6 tmp]$ cat b.s
	.file	"b.c"
	.text
	.p2align 4,,15
.globl myfunction
	.type	myfunction, @function
myfunction:
.LFB0:
	.cfi_startproc
	testb	%dil, %dil
	setne	%al
	ret
	.cfi_endproc
.LFE0:
	.size	myfunction, .-myfunction

Icc generates:
        movsbq    %dil, %rax                                    #3.10
        movl      $1, %edx                                      #3.10
        testl     %eax, %eax                                    #3.10
        cmovne    %edx, %eax                                    #3.10
        ret                                                     #3.10
Comment 1 H. Peter Anvin 2009-12-07 18:32:08 UTC
For what it's worth, gcc 3.4.6 generates a clear on the output register, and therefore complies with the written ABI.
Comment 2 H.J. Lu 2009-12-07 18:39:30 UTC
(In reply to comment #1)
> For what it's worth, gcc 3.4.6 generates a clear on the output register, and
> therefore complies with the written ABI.
> 

That is true. However, gcc 3.4.6 does:


[hjl@gnu-26 pr42324]$ cat b1.c
_Bool myfunction(char val);

int
foo (char v)
{
  return myfunction (v);
}
[hjl@gnu-26 pr42324]$ gcc -O2 -S b1.c
[hjl@gnu-26 pr42324]$ cat b1.s
	.file	"b1.c"
	.text
	.p2align 4,,15
.globl foo
	.type	foo, @function
foo:
.LFB2:
	subq	$8, %rsp
.LCFI0:
	movsbl	%dil,%edi
	call	myfunction
	addq	$8, %rsp
	movzbl	%al, %eax
	ret

It assumes that _Bool is returned in AL. Gcc 3.4.6 generates:

[hjl@gnu-26 pr42324]$ cat b2.c
void foo (char, char, char, char, char, char, char, _Bool);

void
myfunction(char val)
{
  foo (val, val, val, val, val, val, val, val);
}
[hjl@gnu-26 pr42324]$ gcc -O2 -S b2.c
[hjl@gnu-26 pr42324]$ cat b2.s
	.file	"b2.c"
	.text
	.p2align 4,,15
.globl myfunction
	.type	myfunction, @function
myfunction:
.LFB2:
	movsbl	%dil,%r10d
	subq	$24, %rsp
.LCFI0:
	xorl	%eax, %eax
	testb	%dil, %dil
	movl	%r10d, %r9d
	movl	%r10d, %r8d
	setne	%al
	movl	%r10d, %ecx
	movl	%r10d, %edx
	movl	%r10d, %esi
	movl	%r10d, %edi
	movl	%eax, 8(%rsp)
	movl	%r10d, (%rsp)
	call	foo
	addq	$24, %rsp
	ret

The upper 32bits of _Bool on stack aren't zeroed.
Comment 3 H.J. Lu 2009-12-07 18:58:25 UTC
Gcc 4.1/4.2 generate:

	xorl	%eax, %eax
	testb	%dil, %dil
	setne	%al
	ret
Comment 4 H.J. Lu 2009-12-07 19:41:33 UTC
We have 3 options:

1. Keep the psABI ASIS and fix gcc. But zero out upper 32bits of 64bits for
_Bool on stack doesn't make any sense.
2. Remove that paragraph in the psABI and keep gcc ASIS. It will make _Bool
consistent independent of if it is used for function parameters. Both gcc
and icc always treat _Bool as char even if it is returned from a function.
It may break compatibilities among x86-64 compilers. But we have such
problems anyway for gcc 4.3 and 4.4.
3. Changes the psABI to zero out 1-31bits. When _Bool is returned from
function, upper 63bits will be zeroed out due to x86-64 architecture. But
on stack, we only need to zero out 1-31bits. Even if we do this, we still
can't treat _Bool as long long when returned from a function since it will
break with object files compiled with gcc 4.3/4.4.
Comment 5 Richard Biener 2009-12-07 20:49:15 UTC
The ABI says "is passed", not "is returned".  The frontend did return-value
promotion until I disabled that (see endless discussions and libffi fixes
at that point).

So where is a _Bool passed in a registed or on the stack in your testcases?
I see the _Bool on stack is properly extended to 32bits.  That the ABI
requires 64bits here for _Bool seems odd - does it require that for
char and int, too?

There is an invalid dup for the return value promotion btw.
Comment 6 H.J. Lu 2009-12-07 20:59:02 UTC
(In reply to comment #5)
> The ABI says "is passed", not "is returned".  The frontend did return-value
> promotion until I disabled that (see endless discussions and libffi fixes
> at that point).
> 
> So where is a _Bool passed in a registed or on the stack in your testcases?

Please see b2.c in comment #2.

> I see the _Bool on stack is properly extended to 32bits.  That the ABI
> requires 64bits here for _Bool seems odd - does it require that for
> char and int, too?
> 

That is very odd. I think the psABI should be changed to

---
When a value of type _Bool is passed in a registeror on the stack,
the bits1-31 of the eightbyte shall be zero.
---

and leave the upper 32bits undefined.
Comment 7 H.J. Lu 2009-12-08 18:17:41 UTC
Another testcase:

[hjl@gnu-26 pr42324]$ cat b3.c 
void foo (unsigned long, unsigned int, unsigned long,
	  unsigned int, unsigned int, unsigned int, unsigned int,
	  unsigned long, unsigned int);

void bar (_Bool v1, _Bool v2, unsigned char v3, unsigned char v4,
	  unsigned char v5, unsigned char v6,
	  unsigned char v7, _Bool v8)
{
  foo (v1, v2, v3, v4, v5, v6, v7, v8, v8);
}
[hjl@gnu-26 pr42324]$ /usr/gcc-4.4/bin/gcc -O2 b3.c -S  
[hjl@gnu-26 pr42324]$ cat b3.s
	.file	"b3.c"
	.text
	.p2align 4,,15
.globl bar
	.type	bar, @function
bar:
.LFB2:
	subq	$24, %rsp
.LCFI0:
	movzbl	%cl, %ecx
	movzbl	%dl, %edx
	movzbl	40(%rsp), %r10d
	movzbl	%sil, %esi
	movzbl	%dil, %edi
	movzbl	%r9b, %r9d
	movzbl	%r8b, %r8d
	movzbl	%r10b, %eax
	movq	%r10, 8(%rsp)
	movl	%eax, 16(%rsp)
	movzbl	32(%rsp), %eax
	movl	%eax, (%rsp)
	call	foo
	addq	$24, %rsp
	ret

icc 11.1 generates:

	.globl bar
bar:
# parameter 1: %edi
# parameter 2: %esi
# parameter 3: %edx
# parameter 4: %ecx
# parameter 5: %r8d
# parameter 6: %r9d
# parameter 7: 48 + %rsp
# parameter 8: 56 + %rsp
..B1.1:                         # Preds ..B1.0
..___tag_value_bar.1:                                           #8.1
        subq      $40, %rsp                                     #8.1
..___tag_value_bar.2:                                           #
        movzbl    48(%rsp), %eax                                #9.32
        movzbl    56(%rsp), %r10d                               #9.36
        movl      %eax, (%rsp)                                  #9.32
        movzbl    %dil, %edi                                    #8.1
        movq      %r10, 8(%rsp)                                 #9.36
        movl      %r10d, 16(%rsp)                               #9.40
        movzbl    %sil, %esi                                    #9.12
        movzbl    %dl, %edx                                     #8.1
        movzbl    %cl, %ecx                                     #9.20
        movzbl    %r8b, %r8d                                    #9.24
        movzbl    %r9b, %r9d                                    #9.28
        call      foo                                           #9.3
                                # LOE rbx rbp r12 r13 r14 r15
..B1.2:                         # Preds ..B1.1
        addq      $40, %rsp                                     #10.1
..___tag_value_bar.3:                                           #
        ret                                                     #10.1

So both gcc and icc treat _Bool parameters in register and on stack
as 1 byte. I think we should just drop

---
When a value of type _Bool is passed in a register or on the stack,
the upper 63 bits of the eightbyte shall be zero.
---

from psABI since it isn't really followed/used at all.
Comment 8 H.J. Lu 2009-12-08 18:26:51 UTC
Both icc and gcc generate:

[hjl@gnu-26 pr42324]$ cat b4.c
extern unsigned int bartmp;

void foo(_Bool bar)
{
 bartmp = bar;
}
[hjl@gnu-26 pr42324]$ objdump -dw b4.o

b4.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <foo>:
   0:	40 0f b6 ff          	movzbl %dil,%edi
   4:	89 3d 00 00 00 00    	mov    %edi,0x0(%rip)        # a <foo+0xa>
   a:	c3                   	retq   
[hjl@gnu-26 pr42324]$ 
Comment 9 H.J. Lu 2009-12-09 17:43:22 UTC
Created attachment 19268 [details]
Source and object files

These are sources and object files generated by gcc 4.4, icc 11.1 and
Sun Studio 12 Update 1 at -O. The results are

1. All compilers access _Bool as one byte when reading function
return and function parameters.
2. icc 11.1 and Sun Studio 12 Update 1 clear bits 1-63 when writing
function return and function parameters.
3. Gcc 4.4 clears bits 1-7 when writing function return.
4. Gcc 4.4 clears bits 1-31 when writing function parameters.
Comment 10 H.J. Lu 2009-12-10 14:41:45 UTC
This is what I got from Sun:

Solaris x86-64 compiler does not support this x86-64 psABI requirement for _Bool :

  "When a value of type _Bool is passed in a register or on the stack,
the upper 63 bits of the eightbyte shall be zero"

  Solaris x86-64 compiler processes it like char or byte. i.e. When a value of type _Bool is passed in a register or on the stack,
the bits1-31 of the eightbyte shall be zero and upper 32bits should be left undefined.

  Thus current behavior of Sun compiler is that which described by option 2. i.e. following solution looks the best from the point of view of Solaris x86-64 compiler :


  "2. Remove that paragraph in the psABI and keep gcc ASIS. It will make _Bool
  consistent independent of if it is used for function parameters. Both gcc
  and icc always treat _Bool as char even if it is returned from a function.
  It may break compatibilities among x86-64 compilers. But we have such
  problems anyway for gcc 4.3 and 4.4.
  "
Comment 11 H. Peter Anvin 2009-12-10 15:20:18 UTC
Rather makes the choice a no-brainer, doesn't it...
Comment 12 Michael Matz 2010-01-13 12:08:46 UTC
The ABI (http://www.x86-64.org/documentation/abi.pdf) now contains this
language:

--------------------
When a value of type \code{_Bool} is returned or passed in a register or
on the stack, bit 0 contains the truth value and bits 1 to 7 shall be
zero.
--------------------

Hence, fixed by adjusting the document :)
Comment 13 jsm-csl@polyomino.org.uk 2010-01-13 13:55:15 UTC
Subject: Re:  Gcc doesn't follow x86-64 psABI on _Bool

On Wed, 13 Jan 2010, matz at gcc dot gnu dot org wrote:

> The ABI (http://www.x86-64.org/documentation/abi.pdf) now contains this
> language:

Any chance you could give this ABI meaningful version numbers (i.e., 
change the version number when changing the document)?  There have by now 
been several different versions all claiming to be version 0.99, with 
dates varying by more than two years.

Comment 14 Michael Matz 2010-01-13 14:33:29 UTC
Yeah, I started to use micro version numbers, but I can't write to the html
file on that webserver, only to the subdirectory containing the PDFs.  See
  http://www.x86-64.org/documentation/
for a listing.  The current ABI is abi-0.99.4.pdf.  I now encode this also
into the document itself.
Comment 15 H.J. Lu 2010-01-13 14:45:56 UTC
We have Google groups for gABI and i386 psABI. Should I create an x86-64
psABI group?
Comment 16 Michael Matz 2010-01-13 14:49:35 UTC
We have a mailing list already, I don't think we need another one.