http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56369
Bug #: 56369
Summary: Missed opportunity to combine comparisons with zero
Classification: Unclassified
Product: gcc
Version: 4.8.0
Status: UNCONFIRMED
Severity: enhancement
Priority: P3
Component: tree-optimization
AssignedTo: unassig...@gcc.gnu.org
ReportedBy: olege...@gcc.gnu.org
Target: sh*-*-* arm*-*-*
I'm not sure whether this is really a tree-optimization or middle-end (e.g.
combine) issue...
With rev 196091 the following example:
extern int func_10 (void*);
int
func_11 (void* x)
{
int status = 0;
do
{
status = func10 (x);
status = status < 0 ? status : 0;
} while (status >= 0);
return status;
}
compiled for SH4 with -O2 -m4 results in:
_func_11:
mov.l r8,@-r15
mov.l r9,@-r15
mov r4,r9
mov.l .L8,r8
sts.l pr,@-r15
.align 2
.L4:
jsr @r8
mov r9,r4
cmp/pl r0 // T = r0 > 0
bt/s .L4
tst r0,r0 // T = r0 == 0
bt .L4
lds.l @r15+,pr
mov.l @r15+,r9
rts
mov.l @r15+,r8
.L9:
.align 2
.L8:
.long _func10
As seen above, the two comparisons could be done with a single one:
cmp/pz r0 // T = r0 >= 0
I've tried out a few SH specific things to see if combine would do it, but it
just won't combine the two. I guess because the two comparisons end up in two
different basic blocks.
On ARM, there's a smin insn defined, but the problem is the similar. The
example above compiled with -O2 results in:
func_11:
stmfd sp!, {r4, lr}
mov r4, r0
.L3:
mov r0, r4
bl func10
and r0, r0, r0, asr #31 // smin (r0, 0)
cmp r0, #0 // r == 0
beq .L3
ldmfd sp!, {r4, lr}
bx lr
which could be done without the smin (r0, 0), and save the and insn:
func_11:
stmfd sp!, {r4, lr}
mov r4, r0
.L3:
mov r0, r4
bl func10
cmp r0, #0
bge .L3
ldmfd sp!, {r4, lr}
bx lr