CC_MODE and cc0
Zack Weinberg
zack@codesourcery.com
Wed Feb 18 23:01:00 GMT 2004
Paul Koning <pkoning@equallogic.com> writes:
> This note is prompted by discussion on the gcc-patches list about the
> CR16C/CRX processor port submission.
>
> I'm trying to understand the issue relating to cc0 vs. CC_MODE.
> Reading gccint is no help. Reading random mailing list notes isn't
> much help either; the one I've seen so far reiterates the points that
> Alexandre Oliva made a few days ago but doesn't shed much more light
> on the subject.
Well, in my opinion there are deep problems with all the ways to
represent conditional operations in GCC machine descriptions. Yes,
all. I'm aware of at least four - the "classic" cc0-using cmpMODE,
bCOND, sCOND named patterns; the same but with a hard register instead
of cc0; compare-and-branch-in-one-go patterns; and the several
different forms of predicated execution, which I'm lumping together
because I don't fully understand them.
cc0 and the associated named patterns are actually a good model of a
broad class of machines - where there is just one condition-code
register that's set by most operations, and a small number of
conditional instructions that look only at that condition-code
register. The problem with it is that some of the RTL optimizers,
notably the scheduler, throw up their hands at cc0's implicit side
effects. For this reason, and also because it isn't a particularly
good model for architectures that aren't in this broad class, people
have been moving away from it, to the point where it's not recommended
for use for new targets just because it may get broken accidentally
and stay that way for months.
The biggest problem with all the other ways to represent conditional
operations is that the RTL "expander" (the code that produces RTL from
abstract syntax trees) has never been fully weaned away from
assumptions embedded in the cc0 model. No matter what your hardware
does, you've got to use the same named patterns to represent a
comparison and branch, and they just don't fit some architectures.
One winds up gluing it all together with define_expand patterns and
global variables to save state between the compare and the branch.
Look at the Alpha back end for a good example.
The other big problem with the other ways is sometimes you get junk
code like your example (you're absolutely right, it's a redundant
compare)
> cmpl $4, %eax
> je .L4
> cmpl $4, %eax
> jle .L3
because cc0 has custom optimizers to deal with this, but the hard-
register method relies on generic optimizers that aren't always up to
the task. This particular case has been fixed for 3.4 by the way (see
test code and discussion below).
Long term, I think what needs to happen is, we need to sit down and
make an inventory of all the different supported architectures and how
they handle conditional operations in the hardware, and then we need
to work out a new way, *one* new way, that can represent all of them
with equal facility. I suspect this new way looks like a set of named
compare-and-branch patterns, which can be expanded to whatever the
architecture likes; a nice generic if-conversion mechanism to handle
predicated execution (we already mostly have this); a MD macro
facility that makes it less painful to write the necessary patterns
for machines with one condition code register that's set by most
instructions; and beefed up generic-RTL-optimizer handling of
conditional operations.
---
I compiled this test program with 3.3, 3.4, and mainline at -O2
-fomit-frame-pointer, targeting i386:
extern void up(), down(), eq();
void foo(int a, int b) {
if (a == b) eq();
else if (a < b) down();
else up();
}
The assembly looks like this in 3.3:
movl 4(%esp), %edx
movl 8(%esp), %eax
cmpl %eax, %edx
je .L7
cmpl %eax, %edx
jge .L4
jmp down
.p2align 2,,3
.L4:
jmp up
.p2align 2,,3
.L7:
jmp eq
and like this in 3.4 and 3.5:
movl 8(%esp), %eax
cmpl %eax, 4(%esp)
je .L7
jge .L4
jmp down
.p2align 2,,3
.L4:
jmp up
.p2align 2,,3
.L7:
jmp eq
Optimal code for this example (since the x86 allows conditional
jumps of arbitrary distance) would be something like
movl 8(%esp), %eax
cmpl %eax, 4(%esp)
je eq
jge up
jmp down
but I guess we don't have the ability to collapse sibcalls into
conditional jumps yet.
zw
More information about the Gcc
mailing list