Bug 46680 - Suboptimal code generated for bool comparisons
Summary: Suboptimal code generated for bool comparisons
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.4.1
: P3 enhancement
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-11-27 00:53 UTC by Adriano Rezende
Modified: 2010-11-27 15:44 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Adriano Rezende 2010-11-27 00:53:24 UTC
Hi,

Take as reference the code below (compiled using gcc-4.4.1 on linux. command line: g++ main.cpp):

int main()
{
    bool value = true;

    if (value) printf("true\n");
    if (!value) printf("false\n");

    return 0;
}

The first 'if' generates the following block:

cmpb	$0, 31(%esp)
je	.L2
movl	$.LC0, (%esp)
call	puts

While the second 'if' generates the following:

.L2:
	movzbl	31(%esp), %eax
	xorl	$1, %eax
	testb	%al, %al
	je	.L3
	movl	$.LC1, (%esp)
	call	puts

I think this:

movzbl	31(%esp), %eax
xorl	$1, %eax
testb	%al, %al
je	.L3

Could be replaced by this:

cmpb	$0, 31(%esp)
jne	.L3


Is there a reason to be like this? Am I missing something?

This change will remove two instructions per comparison and also solve a strange behavior, which was the original reason for me to investigate it;

Take as an example a non-initialized bool variable, containing the value 0x8 (trash memory). The two lines below will be printed:

if (value) printf("true");
if (!value) printf("also true");

since the second 'if' will compute (0x1 xor 0x8) resulting in 0x9 (also true).

Maybe the spec doesn't care about this, but I think this is a strange behavior even for non-initialized variables.

Br,
Adriano
Comment 1 Dmitry Gorbachev 2010-11-27 05:51:15 UTC
> Am I missing something?

-O1 / -O2 / -O3 / -Os option.

> but I think this is a strange behavior
> even for non-initialized variables.

http://en.wikipedia.org/wiki/Undefined_behavior
Comment 2 Adriano Rezende 2010-11-27 12:10:21 UTC
>> Am I missing something?

> -O1 / -O2 / -O3 / -Os option.

I know about these optimization flags :).
My suggestion is directed specifically to -O0.

I would not rest knowing that it generates 4 instructions per comparison, while it could use 2 instructions, reducing my code size and my compilation time while using -O0, which is the default one.

>> but I think this is a strange behavior
>> even for non-initialized variables.

> http://en.wikipedia.org/wiki/Undefined_behavior

I also know about UB. The strange behavior I'm referring to regards the compiler implementation rather than the language specification. I just looked for this, because I expected a consistent behavior in gcc for non-initialized bool values in that matter. For example, for char types it wouldn't make sense a == !a, for whatever value randomly placed in those 8 bits. For the 'if' statements, I expected a mutual exclusive operation, like [if(a) - cmpb/je] and [if(!a) - cmpb/jne], and that wasn't happening for bool comparisons.

Well, I'm not an asm programmer nor a gcc contributor, so I may be wrong. But unless those 4 instructions make some sense, there is no purpose in keeping them.
Comment 3 Jonathan Wakely 2010-11-27 14:53:49 UTC
(In reply to comment #2)
> My suggestion is directed specifically to -O0.

If you want optimised code then use optimisation.  
 
> I also know about UB. The strange behavior I'm referring to regards the
> compiler implementation rather than the language specification. I just looked
> for this, because I expected a consistent behavior in gcc for non-initialized
> bool values in that matter.

No. You cannot expect undefined behaviour to be consistent.
Comment 4 Richard Biener 2010-11-27 14:59:21 UTC
(In reply to comment #2)
> >> Am I missing something?
> 
> > -O1 / -O2 / -O3 / -Os option.
> 
> I know about these optimization flags :).
> My suggestion is directed specifically to -O0.
> 
> I would not rest knowing that it generates 4 instructions per comparison, while
> it could use 2 instructions, reducing my code size and my compilation time
> while using -O0, which is the default one.

GCC is known to generate very bad code at -O0, but this is expected.

The reason is that GCC makes sure !value is computed into a register
(for the sake of debugging), thus does

 temp = !value;
 if (temp)
   ...
Comment 5 Adriano Rezende 2010-11-27 15:37:59 UTC
> GCC is known to generate very bad code at -O0, but this is expected.
> 
> The reason is that GCC makes sure !value is computed into a register
> (for the sake of debugging), thus does
> 
>  temp = !value;
>  if (temp)
>    ...

Thanks for the explanation, it makes sense now :)
Comment 6 Steven Bosscher 2010-11-27 15:44:36 UTC
Please do not reopen bugs closed as invalid.