Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

x86 revisited - flags

123 views
Skip to first unread message

Peter "Firefly" Lund

unread,
Mar 1, 2004, 4:39:09 AM3/1/04
to
Flags are kind of hard to handle because they are an implicit source AND
an implicit operand for so many instructions.

That makes me wonder: how do AMD and Intel (and VIA and ...) handle them?

By noting that they are relatively rare as /explit/ sources (Jcc, CMOVcc,
SETcc, SALC, ROR, ROL, ...)? And by noting when they are /all/ set
together?

This could break the instructions up into smaller dependency chains. I
guess the decoder stage(s) could do this. Or does it happen as part of a
separate renaming stage?

There are probably a number of virtual flag "registers". Do chains of
instructions which do use the flags but for which the end-result in the
flags don't matter use "normal" renamed flag registers ... or is this
implemented with a set of "read 1" or "read 0" flags which can't be
changed?

Since there are so few(*) flags (5-6 bits) it might make sense to do some
special-casing. Perhaps carry and zero are handled differently from the
rest? They could be part of the forwarding network for the src/dst
operand so it really was a 34-bit thing. And all the flag bits could
share the register number for the src/dst operand. But would I want to
let the remaining bits be part of this forwarding network? Hmm... they
are used relatively rarely... and then again, I might want overflow for
the signed Jcc instructions. Hmm...

I suspect the flags are similar to the instruction encoding in that they
were a nuisance to handle until the middle of the nineties when everybody
had learned the necessary tricks. Now they are just a fixed cost in terms
of die space, validation, and design -- but they are not speed-limiting
the implementation or requiring heroic creativity on the part of the
designers.

*) Yes, I know that there are more flags in the higher bytes but they
aren't operands in all that many instructions -- or they change very
rarely.

-Peter

PS: So how /could/ the 8086 have done this differently and still stayed
relatively compatible with the 8080? And not have seemed too
weird/cumbersome to program for in the seventies?

Terje Mathisen

unread,
Mar 1, 2004, 10:13:47 AM3/1/04
to
Peter "Firefly" Lund wrote:
> Flags are kind of hard to handle because they are an implicit source AND
> an implicit operand for so many instructions.
>
> That makes me wonder: how do AMD and Intel (and VIA and ...) handle them?
>
> By noting that they are relatively rare as /explit/ sources (Jcc, CMOVcc,
> SETcc, SALC, ROR, ROL, ...)? And by noting when they are /all/ set
> together?

The latter is crucial:

INC/DEC is a specialcase, which has been removed by the x86-64
extension, so it must cost significantly to merge the flag results of an
INC/DEC with those from any other flag-modifying instruction.

Terje
--
- <Terje.M...@hda.hydro.com>
"almost all programming can be viewed as an exercise in caching"

Peter "Firefly" Lund

unread,
Mar 1, 2004, 11:30:35 AM3/1/04
to
On Mon, 1 Mar 2004, Terje Mathisen wrote:

> INC/DEC is a specialcase, which has been removed by the x86-64
> extension,

No, it hasn't. Only the one-byte encodings of register inc/dec have been
removed. You still have the two-byte encodings. Plus, there is no
difference in the way they handle flags.

And they have the same semantics in long mode and legacy mode.

> so it must cost significantly to merge the flag results of an
> INC/DEC with those from any other flag-modifying instruction.

Which makes Paul Hsieh's complaint about the shift/rotate instructions
much more understandable... it also makes the errata he was referring to
seem more reasonable.

So now I would like to both get rid of the flags and have I/O channels :/
Not easy to do that while keeping as much software compatibility with the
8080 as possible, /AND/ making it easy to program in assembler, /AND/
making it easy to interface to, /AND/ making it fit in the die budget.
And still enabling the designers to implement it all in the very short
time they had...

I guess I'll have to settle for slightly fewer instructions, an extra GPR
(by leaving SP out), IP-relative addressing, and the I/O segment register
:/

-Peter

PS: And a big stick for the 286 designers!

Mitch Alsup

unread,
Mar 1, 2004, 11:40:59 AM3/1/04
to
"Peter \"Firefly\" Lund" <fir...@diku.dk> wrote in message news:<Pine.LNX.4.58.04...@brok.diku.dk>...

> Flags are kind of hard to handle because they are an implicit source AND
> an implicit operand for so many instructions.

Lots of instructions produce flags, not so many consume flags.



> That makes me wonder: how do AMD and Intel (and VIA and ...) handle them?
>
> By noting that they are relatively rare as /explit/ sources (Jcc, CMOVcc,
> SETcc, SALC, ROR, ROL, ...)? And by noting when they are /all/ set
> together?
>
> This could break the instructions up into smaller dependency chains. I
> guess the decoder stage(s) could do this. Or does it happen as part of a
> separate renaming stage?

Flags are renamed in 3 groups in Athlon/Opteron, Carry, Overflow, and
ZAPS (Zero, auxilliary carry, parity, sign) and are tracked independently.
So if one instruction sets C but not C or ZAPS, and another sets ZAPS there
is no serialization. The issue come in when the flags from two different
instructions are consumed by a single instruction. But in general the
consumer just waits for all its flags before scheduling. Each flag
group has its own forwarding logic.

The only snafu here is that some instructions set flags only "most of
the time". Take shifts, when the shift count is non-zero, the flags are
set, when zero the flags are not molested. Athlon and Opteron take
microfaults on shifts with zero to repair the data flow graph related
to flags.


>
> I suspect the flags are similar to the instruction encoding in that they
> were a nuisance to handle until the middle of the nineties when everybody
> had learned the necessary tricks. Now they are just a fixed cost in terms
> of die space, validation, and design -- but they are not speed-limiting
> the implementation or requiring heroic creativity on the part of the
> designers.

The only real critical path is the producer of flags to a consumer of flags
that effect a branch resolution. High quality branch prediction takes the
pressure of of this critical dependence.

Mitch

Peter "Firefly" Lund

unread,
Mar 1, 2004, 11:53:37 AM3/1/04
to
On Mon, 1 Mar 2004, Mitch Alsup wrote:

> Flags are renamed in 3 groups in Athlon/Opteron, Carry, Overflow, and
> ZAPS (Zero, auxilliary carry, parity, sign) and are tracked independently.

Thank you, Mitch! :)

I'll go do some cogitation tonight on why it was done like this... I'm
already looking forward to it :)

Hmmm... how does the consumer get the right set of flags if the three
groups are renamed independently?

-Peter

"On two occasions I have been asked [by members of Parliament], 'Pray, Mr.
Babbage, if you put into the machine wrong figures, will the right answers
come out?' I am not able rightly to apprehend the kind of confusion of
ideas that could provoke such a question."

Andreas Kaiser

unread,
Mar 1, 2004, 1:11:58 PM3/1/04
to
On Mon, 01 Mar 2004 16:13:47 +0100, Terje Mathisen
<terje.m...@hda.hydro.com> wrote:

>INC/DEC is a specialcase, which has been removed by the x86-64
>extension, so it must cost significantly to merge the flag results of an
>INC/DEC with those from any other flag-modifying instruction.

They have not been removed.

However Intel strongly discourages their use, because of an artificial
input dependency on prior flags.

Gruss, Andreas

Andreas Kaiser

unread,
Mar 1, 2004, 1:20:30 PM3/1/04
to
On 1 Mar 2004 08:40:59 -0800, Mitch...@aol.com (Mitch Alsup) wrote:

>Flags are renamed in 3 groups in Athlon/Opteron, Carry, Overflow, and
>ZAPS (Zero, auxilliary carry, parity, sign) and are tracked independently.
>So if one instruction sets C but not C or ZAPS, and another sets ZAPS there
>is no serialization.

The P4 however has just one single group of condition code flags. An
instruction which modifies only part of the condition code has an
input dependency on prior flags, because of the merge which is
required. A real pain for INC/DEC address index counters in loops
because they connect datapaths which are better kept independant.

>The only snafu here is that some instructions set flags only "most of
>the time". Take shifts, when the shift count is non-zero, the flags are
>set, when zero the flags are not molested. Athlon and Opteron take
>microfaults on shifts with zero to repair the data flow graph related
>to flags.

Obviously a good old AMD tradition. I've noticed this on the K5 too.
Others have an input dependency on prior flags instead.

Gruss, Andreas

Andreas Kaiser

unread,
Mar 1, 2004, 1:30:01 PM3/1/04
to
On Mon, 01 Mar 2004 18:01:19 +0100, Andi Kleen
<fre...@alancoxonachip.com> wrote:

>PPC would need at least 8 such groups to track all CR* subregisters I guess.
>This sounds like x86 requires less hardware here than a PPC implementation.
>But it may be not as critical there because flag setting is always optional.

Not too complicated if you think of the 8 CRs being separate registers
and renamed just like GPRs. That's how it usually it implemented.

It only gets complicated when a set of CRs is moved as a whole. And
guess what: the PPC 6xx optimization guides recommend to move CRs
individually, up to some upper limit (maybe 3-5 or so). Maybe those
oldies just serialised the CR handling for multi-CR moves, a mechanism
which won't work all too well in a deeply OOO Power4/5/970.

Gruss, Andreas

Terje Mathisen

unread,
Mar 1, 2004, 1:38:49 PM3/1/04
to
Peter "Firefly" Lund wrote:
> On Mon, 1 Mar 2004, Terje Mathisen wrote:
>
>
>>INC/DEC is a specialcase, which has been removed by the x86-64
>>extension,
>
> No, it hasn't. Only the one-byte encodings of register inc/dec have been
> removed. You still have the two-byte encodings. Plus, there is no

I didn't mean that the instructions were gone, only that the CF special
case was modified, however, it seems like I misremembered.

> difference in the way they handle flags.

Mea culpa. The x86-64 manuals I have do state that the INC/DEC
instructions doesn't modify Carry, even in 64-bit mode.


>
> And they have the same semantics in long mode and legacy mode.

Right.

Jeffrey Dutky

unread,
Mar 1, 2004, 3:03:11 PM3/1/04
to
Terje Mathisen <terje.m...@hda.hydro.com> wrote in message news:<c1vjva$v0s$1...@osl016lin.hda.hydro.com>...

> Peter "Firefly" Lund wrote:
> > Flags are kind of hard to handle because they are an implicit source AND
> > an implicit operand for so many instructions.
> >
> > That makes me wonder: how do AMD and Intel (and VIA and ...) handle them?
> >
> > By noting that they are relatively rare as /explit/ sources (Jcc, CMOVcc,
> > SETcc, SALC, ROR, ROL, ...)? And by noting when they are /all/ set
> > together?
>
> The latter is crucial:
>
> INC/DEC is a specialcase, which has been removed by the x86-64
> extension, so it must cost significantly to merge the flag results of an
> INC/DEC with those from any other flag-modifying instruction.

I thought INC/DEC were removed for a much more mundane reason: AMD needed
some opcode space and INC/DEC could be done by other means. Granted, I can't
back that up in any way: I don't recall where I read or heard that, or if it
was credited to a reliable source.

- Jeff Dutky

Ken Hagan

unread,
Mar 2, 2004, 4:58:58 AM3/2/04
to
"Peter \"Firefly\" Lund" <fir...@diku.dk> wrote...

> Flags are kind of hard to handle because they are an implicit
> source AND an implicit operand for so many instructions.

Mitch Alsup wrote:
>
> Lots of instructions produce flags, not so many consume flags.

So would it have been (and would it still be) helpful to define
a "FLAGS:" instruction prefix which marked out those operations
whose flag outputs are later consumed?

It presumably wouldn't have been useful in the 8086. The flags
came for free and my prefix would have cost an instruction byte.

Based on the discussion in this thread, I'm guessing it wouldn't
have been useful to OoO implementations 20 years later, either,
since there are ways round the problem and it doesn't sound like
the cost is too high.

However, it might have been very useful to anyone writing an x86
emulator. Had *those* been easier to write, one of the RISC
families might have toppled the 486 or Pentium. (Is it time to
mention the Alpha, yet?)


Mitch Alsup

unread,
Mar 2, 2004, 12:18:59 PM3/2/04
to
"Ken Hagan" <K.H...@thermoteknix.co.uk> wrote in message news:<c21lo1$e84$1$8300...@news.demon.co.uk>...

> "Peter \"Firefly\" Lund" <fir...@diku.dk> wrote...
> > Flags are kind of hard to handle because they are an implicit
> > source AND an implicit operand for so many instructions.
>
> Mitch Alsup wrote:
> >
> > Lots of instructions produce flags, not so many consume flags.
>
> So would it have been (and would it still be) helpful to define
> a "FLAGS:" instruction prefix which marked out those operations
> whose flag outputs are later consumed?

For the 95%-tile cases, you can use the following Jcc instruction
to be the 'postfix' indicator that flags are actually necessary.

With modern 32-bit environments (and 64-bits) can compiled code,
there are very few condition code consuming instructions that
are not conditional branches in actual codes. All the CMOVs,
RCL, RCR, ADDC, SUBC,... add up to an almost ignorable component
in the current code base.

>
> It presumably wouldn't have been useful in the 8086. The flags
> came for free and my prefix would have cost an instruction byte.
>
> Based on the discussion in this thread, I'm guessing it wouldn't
> have been useful to OoO implementations 20 years later, either,
> since there are ways round the problem and it doesn't sound like
> the cost is too high.
>
> However, it might have been very useful to anyone writing an x86
> emulator. Had *those* been easier to write, one of the RISC
> families might have toppled the 486 or Pentium. (Is it time to
> mention the Alpha, yet?)

Yes, indeedie! Its reletively easy for the hardware to provide all
the gyrations necessary to track and manipulate flags to x86 specs.
Its another thing entirely for software running on a foreign
architecture to compute the same flag gyrations.

Mitch

John F. Carr

unread,
Mar 3, 2004, 2:12:54 PM3/3/04
to
In article <m3r7wcc...@averell.firstfloor.org>,
Andi Kleen <fre...@alancoxonachip.com> wrote:

>Mitch...@aol.com (Mitch Alsup) writes:
>>
>> Flags are renamed in 3 groups in Athlon/Opteron, Carry, Overflow, and
>> ZAPS (Zero, auxilliary carry, parity, sign) and are tracked independently.
>
>PPC would need at least 8 such groups to track all CR* subregisters I guess.
>This sounds like x86 requires less hardware here than a PPC implementation.
>But it may be not as critical there because flag setting is always optional.

Original POWER had _4_ groups, not 1 or 8 or 32. cr0 and cr4 were
a pair, etc., for interlocking. (This might have been the oddity
they blamed on CMOS fanout limitations.)

There was also a separate functional unit (on a separate chip from
the integer datapath) to handle condition register operations.


--
John Carr (j...@mit.edu)

Terje Mathisen

unread,
Mar 3, 2004, 8:32:11 PM3/3/04
to
John F. Carr wrote:
> Original POWER had _4_ groups, not 1 or 8 or 32. cr0 and cr4 were
> a pair, etc., for interlocking. (This might have been the oddity
> they blamed on CMOS fanout limitations.)
>
> There was also a separate functional unit (on a separate chip from
> the integer datapath) to handle condition register operations.

This was an important Achilles' heel on the original Power imho.

It took something like 3 cycles extra to propagate a condition code over
to the separate branch unit, whihc meant that the compiler had a big
problem trying to come up with ways to lift condition code determination
high enough to cover this additional latency.

Andy Glew

unread,
Mar 9, 2004, 10:46:21 AM3/9/04
to
> >Flags are renamed in 3 groups in Athlon/Opteron, Carry, Overflow, and
> >ZAPS (Zero, auxilliary carry, parity, sign) and are tracked
independently.
> >So if one instruction sets C but not C or ZAPS, and another sets ZAPS
there
> >is no serialization.
>
> The P4 however has just one single group of condition code flags. An
> instruction which modifies only part of the condition code has an
> input dependency on prior flags, because of the merge which is
> required. A real pain for INC/DEC address index counters in loops
> because they connect datapaths which are better kept independant.

The P6 conceptually had a mask indicating which flags were potentially
written, a mask indicating which flags were actually written,
and a mask indicating which flags were needed as inputs.

The flags were actually stored as roughly 8 extra bits on every
physical register in the reorder buffer. Only the bits under the mask
were valid.

The renamer tracked which ROB entry contained the most recently
written version of the flags, subject to the mask of potentially written
flags. If a uop depended on one of the flags that were indicated as
valid in this bitmask, it need only depend on that physical register.
If a uop depended on flags that were not valid in that bitmask,
it had to wait until retirement merged al of the flags together,
just like the partial register stall.

Retirement merged flags from the ROB using the bitmask
of actually written flags.

Above I say "mask" and "bitmask"; that was the original vision. In reality,
only a few values of the mask are necessary, corresponding to roughly
COZAPS; therefore, tight encodings were used.

---

I am surprised that P4 merged flags at creation time, although that would
be consistent with what P4 did to partial registers: replace infrequent
but expensive (whole pipe) partial read stalls with frequent but less
expensive
(dataflow) stalls on all partial writes.


Michael S

unread,
Mar 9, 2004, 1:54:07 PM3/9/04
to
"Ken Hagan" <K.H...@thermoteknix.co.uk> wrote in message news:<c21lo1$e84$1$8300...@news.demon.co.uk>...


I think, you're looking at "FLAGS:" prefix from the wrong angle.
The prefix it can be useful not because it reduces direct cost of the
hardware. Quite to the contrary - it makes hardware slightly more
complicated. The usefulness of the prefix (or PPC's multiple CRs or
SPARC's multiple sets of flags) lays in new opportunities for the
software to carry down ILP information.

For example:
if (A > AA)
if (B > BB)
do_11();
else
do_10();
else
if (B > BB)
do_01();
else
do_00();


On x86 compiler will produce something like this:
cf = cmp(A, AA);
if (cf.le) goto L2;
cf = cmp(B, BB);
if (cf.le) goto L1;
do_11();
goto L4;
L1:do_10();
goto L4;
L2:cf = cmp(B, BB);
if (cf.le) goto L3;
do_01();
goto L4;
L3:do_00();
L4:

On SPARC (which has most similar flags scheme to x86) it will look
like this:
cf1 = cmp(A, AA);
cr2 = cmp(B, BB);
if (cf1.le) goto L2;
if (cf2.le) goto L1;
do_11();
goto L4;
L1:do_10();
goto L4;
L2:if (cf2.le) goto L3;
do_01();
goto L4;
L3:do_00();
L4:

Other popular RISCs would achieve the same result by more or less
similar technique.

It's easy to see that on RISCs both comparisons could be done
concurrently.
On the x86 OoO hardware also can do comparisons concurrently, but if
branch prediction fails the 2nd comparison should be redone.

Since I was looking for the simplest possible illustration the result
isn't very convincing - performance loss is pretty small. In more
complex cases you will see more serious losses of parallelism esp.
because it is easily to run out of registers while attempting to defer
comparisons.

I personally think that this particular deficiency of x86 ISA could be
fixed even now - it's not too late. Of coarse now it will cost more in
terms of lengthy encoding relatively to solutions that were possible
26 or even 19 years ago.

Mitch Alsup

unread,
Mar 10, 2004, 12:41:02 PM3/10/04
to
already...@yahoo.com (Michael S) wrote in message news:<f881b862.0403...@posting.google.com>...

> "Ken Hagan" <K.H...@thermoteknix.co.uk> wrote in message news:<c21lo1$e84$1$8300...@news.demon.co.uk>...
> >
> > Mitch Alsup wrote:
> > >
> > > Lots of instructions produce flags, not so many consume flags.
<snip>

> I think, you're looking at "FLAGS:" prefix from the wrong angle.
> The prefix it can be useful not because it reduces direct cost of the
> hardware. Quite to the contrary - it makes hardware slightly more
> complicated. The usefulness of the prefix (or PPC's multiple CRs or
> SPARC's multiple sets of flags) lays in new opportunities for the
> software to carry down ILP information.
<examples snipped>

> It's easy to see that on RISCs both comparisons could be done
> concurrently.
> On the x86 OoO hardware also can do comparisons concurrently, but if
> branch prediction fails the 2nd comparison should be redone.

In both Athlon and Opteron, microcode can and does use multiple
flags and multiple flag groups independently. Each GPR is
decorated with the output flags from that computation. In
effect the only problem in delivering this functionality to
the ISA is the ISA itself.

Mitch

0 new messages