RE: volatile const structure members in C++

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I altered my test program to:

struct sA { unsigned volatile       B;
            unsigned volatile const C;
            unsigned          const D;
            unsigned                E; };
void Function( sA & A ) { A.B; A.C; A.D; A.E; }

and got:

  .globl  _Z8FunctionR2sA
  .type _Z8FunctionR2sA, @function
_Z8FunctionR2sA:
  link.w %a6,#0
  move.l 8(%a6),%a0 | A, A
  move.l (%a0),%d0  | <variable>.B, <variable>.B
  unlk %a6
  rts

As you can see, the A.B is now being loaded but not A.C. No matter where
it is in the structure, I am finding that volatile const is not being
loaded.

My question is:

How should the compiler behave with volatile const (i.e. Does the
language specification require the load?)?

By my understanding (weak though it may be), const only specifies that
my code may not attempt to modify the object (other than
initialization, construction, etc...) and volatile specifies that the
object may change value without my code's intervention (and that loads
are not to be optimized out). These two concepts should be orthogonal.

The situation which exists in the original program is a bit more
complicated. We have hardware that looks like:

struct sCommand { enum eCommands { CommandAddress  = 1,
                                   CommandDisable  = 2,
                                   CommandIdle     = 3,
                                   CommandNone     = 0,
                                   CommandNop      = 7,
                                   CommandReceive  = 4,
                                   CommandTransmit = 5 };
                  enum eStates { StateDisabled        = 0,
                                 StateIdle            = 1,
                                 StateMaster          = 2,
                                 StateSlave           = 3,
                                 StateSlaveTerminated = 4,
                                 StateTransition      = 5 };

                  unsigned                                      : 6;
                  bool      volatile const TransmitDataFull     : 1;
                  bool      volatile const ReceiveDataAvailable : 1;
                  bool      volatile const Interrupt            : 1;
                  bool      volatile const Acknowledged         : 1;
                  eStates   volatile const State                : 3;
                  eCommands volatile       Command              : 3;
                }
Command;

This is a 16 bit register in memory. The Command member is the only part
which is writable, the other members are read-only (that is even if they
are written, the write has no effect). However, all of the members may
change in real-time without processor intervention (the Command member
gets cleared when the command being executed completes). The use of
volatile is to ensure that every load actually happens (since multiple
bits are loaded into processor registers, without volatile the compiler
may otherwise produce code that skips critical loads and uses stale
data). The use of const is to smoke out programmer mistakes at compile
time.

The actual failing code looks like:

  Xilinx.Fpga.I2c.Command.Command = Xilinx.Fpga.I2c.Command.CommandNone;
  switch ( Xilinx.Fpga.I2c.Command.State )
    {

for this fragment the compiler is producing:

	move.b Xilinx+139,%d0
	moveq.l #-8,%d1
	and.l %d1,%d0
	move.b %d0,Xilinx+139

	move.b %d0,%d2
	lsr.l #3,%d0
	moveq.l #7,%d4
	and.l %d4,%d0
	moveq.l #4,%d1
	cmp.l %d0,%d1
	jbcs .L322

Xilinx+138 is the address of the register. As you can see the compiler
is loading the lower 8 bits of the register, altering it, and storing
the result. Unfortunately, it then uses this result rather than
reloading the register to do the State switch. The program is actually
failing once every few million events because a hardware state change
happens after the Command write that the switch misses. 

While I can, and must, change my volatile const(s) to volatile(s) and
trust that none of the programmers will attempt an alteration, it seems
that the language has the features to do better.

I would like to generate a PR but I'm looking for confirmation that my
understanding about volatile const's semantics are correct.

-----Original Message-----
From: gcc-help-owner@xxxxxxxxxxx [mailto:gcc-help-owner@xxxxxxxxxxx] On
Behalf Of Daniel Berlin
Sent: Friday, August 26, 2005 6:04 AM
To: Steve Zook
Cc: gcc-help@xxxxxxxxxxx
Subject: Re: volatile const structure members in C++

On Thu, 2005-08-25 at 21:24 -0700, Steve Zook wrote:
> Using m68k-elf-gcc with either revision 3.3.3 or 3.4.4, I compile the 
> following test program (as a C++ program) at -O2 to an object file:
> 
> 
> struct sA { unsigned volatile const B;
>             unsigned volatile       C;
>             unsigned          const D;
>             unsigned                E; };
> void Function( sA & A ) { A.B; A.C; A.D; A.E; }
> 
> 
> The object file I get looks like (edited for brevity):
> 
> 	.globl	_Z8FunctionR2sA
> 	.type	_Z8FunctionR2sA, @function
> _Z8FunctionR2sA:
> 	link.w %a6,#0
> 	move.l 8(%a6),%a0	| A, A

This is a load of A.B.  It's the first member of the structure, and
thus, is at offset 0, and is also known as "A".

I imagine if you rearrange the struct so that B and C are farther into
the struct (IE add a dummy member in front, etc), you'd see the more
explicit loads you are looking for.

> 	move.l 4(%a0),%d0	| <variable>.C, <variable>.C
> 	unlk %a6
> 	rts
> 
> I was expecting that A.B and A.C would both generate loads since they 
> are both volatile, and that A.D and A.E would not, but only A.C loads.
> 
> Have I misunderstood how volatile const should work, or is this a bug 
> I should submit?
> 
> 



[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux