This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Projects for beginners


On Tue, Jan 30, 2001 at 11:49:24PM -0800, Zack Weinberg wrote:
> This is where I admit that I have never been able to understand any of
> the multiple different ways of handling condition codes in GCC.
> There's the pure cc0 approach, the every-insn's-a-parallel approach
> taken by the x86 back end, the cbranch stuff which I totally agree
> needs more documentation, and the pure flag registers approach which
> apparently only works on machines where that is the hardware.

My quick view of the history is (note some of this predates my involvement with
GCC) is (using a branch if register is > 2 as an example):

The original GCC only had cc0, because it matched the machines it was
targetting (vax, 68k).  On a CC0 machine, CC0 is treated as an additional
register and it is assumed that nearly every instruction sets CC0.  As a
perceived time saving measure (in terms of compile speed), CC0 is not listed as
being set or clobbered on any instruction, and the compiler is required to keep
branches or scc instructions immediately after the insn that explicitly sets
cc0.  The CC macros were added so that machines could track changes to CC0 on
an insn by insn basis.  The compiler treats setting CC0 as if it was set to -1
for less than, 0 for equal to, or 1 for greater than comparisons.  The test
against 0 in the branch can be any of the comparisons (LT/EQ/GT, etc.).

	(set (cc0)
	     (compare:CC (reg:SI n)
			 (const_int 2)))
	(set (pc)
	     (if_then_else (gt (cc0) (const_int 0))
			   (label_ref ...)
			   (pc)))

Having an allocatable staus register came in with the first RISC ports (Sparc
and Mips).  Here there wasn't a generalized compare instruction, but the
equivalent of a scc instruction which sets the value to 0/1.  The test against
0 in the branch is always EQ/NE.  Because the lifetime of the condition code
register is tracked like any other register, it can be separated from the
branch insn.

	(set (reg:CC n)
	     (gt:CC (reg:SI m)
		    (const_int 2)))
	(set (pc)
	     (if_then_else (ne (reg:CC n) (const_inst 0))
			   (label_ref ...)
			   (pc)))

The Mips and 88k also have branch instructions that test whether one register
is equal to or not equal to another register, and different instruction that
does signed comparisons against 0.  The branch/scc instructions generate this
directly:

	(set (pc)
	     (if_then_else (ne (reg:SI n) (reg:SI m))
			   (label_ref ...)
			   (pc)))

The Power/powerpc RISC machine (and others) added special condition registers,
which you did a compare into the register, and then a branch based on which
comparison was wanted.  These registers are allocatable, just like any other
type, and register classes are used to make sure the special registers are used
for the purpose.  One problem that occurs on some of these machines is how do
you reload the special condition register if there aren't appropriate
instructions to move it to/from a general purpose register.

	(set (reg:CC n)
	     (compare:CC (reg:SI m)
			 (const_int 2)))
	(set (pc)
	     (if_then_else (gt (reg:CC n) (const_int 0))
			   (label_ref ...)
			   (pc)))

The Power/powerpc machine also had a bit in most of the arithmetic operations,
which did the operation and then set cc0 with comparing the result against
zero, and this is handled by the combiner.

	(parallel [(set (reg:SI n)
			(ashift:SI (reg:SI m)
				   (reg:SI l)))
		   (set (reg:CC x)
			(compare:CC (ashift:SI (reg:SI m)
					       (reg:SI l))))])

One variant of the two RISC approaches is to use a fixed register(s) if the
machine only has 1 condition code register (or 1 integer condition code
register and 1 floating point condition code register).  You don't have the
scope of optimization available if you have a fixed register (ie, you can't
move it outside of loops), but the compare can be separated from the branch by
arbitary instructions that don't set the register.

The way you describe a machine like the x86 without CC0, is that you change all
of the patterns that set the hardware flags register, now become parallels
where the main operation is done, and the condition code register is set, like
the powerpc example above.

Cbranch was added for the thumb subport of the arm, and it allows the
comparison and branch to be folded together early on.  I personally haven't
hacked one of these machines yet.

	(set (pc)
	     (if_then_else (gt (reg:CC n) (const_int 0))
			   (label_ref ...)
			   (pc)))

All (almost all?) machines set this up via the compare named insns just storing
the arguments, and the appropriate branch or scc instruction actually
generating the appropriate code.

> My basic problem is that the comparison RTXes mean different things
> when they're used to set condition registers, from when they're used
> to examine condition registers.  I.e. these are not the same thing:
> 
>   (eq (reg:SI 12) (const_int 0))
>   (eq (cc0) (const_int 0))
> 
> but I've never really been able to understand just what the latter one
> means.

Logically, a COMPARE sets the register to -1/0/1, while an EQ/LT/GT, etc. sets
the register to 0/1.

> I *think* that the cbranch stuff lets you have
> 
> (set (pc) (if_then_else (eq (reg:SI 12) (reg:SI 13))
>                         (label_ref 42)
>                         (pc)))
> 
> as one insn, i.e. at least before insn splitting there's no condition
> code register at all.  But I Could Be Wrong.
> 
> > If there's someone with the answers, I'll consider doing it for
> > CRIS (awaiting approval) so that it could perhaps be used as a
> > template in addition to the thumb bits within the arm port when
> > getting rid of cc0 in other ports.
> > 
> > I guess this is actually a call for documentation of that
> > appraised "cbranch" stuff.  Maybe an item for the GCC-related
> > projects, unless the cbranch author or equivalent steps forward.
> 
> Emphatic agreement.

Bernd is probably the person to talk to about cbranch.

-- 
Michael Meissner, Red Hat, Inc.  (GCC group)
PMB 198, 174 Littleton Road #3, Westford, Massachusetts 01886, USA
Work:	  meissner@redhat.com		phone: +1 978-486-9304
Non-work: meissner@spectacle-pond.org	fax:   +1 978-692-4482

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]