m68k gcc/egcs question

Zoltan Kocsi <zoltan@bendor.com.au>
20 Sep 1999 12:13:01 -0400

          From comp.compilers

Related articles
m68k gcc/egcs question zoltan@bendor.com.au (Zoltan Kocsi) (1999-09-20)
Re: m68k gcc/egcs question davidwilliams@ozemail.com.au (David Williams) (1999-09-24)
Re: m68k gcc/egcs question mrs@kithrup.com (1999-09-24)
Re: m68k gcc/egcs question jejones@microware.com (James Jones) (1999-09-27)
Re: m68k gcc/egcs question albert@korppi.cs.tut.fi (1999-09-28)
Re: m68k gcc/egcs question zalman@netcom3.netcom.com (Zalman Stern) (1999-10-01)
Re: m68k gcc/egcs question zoltan@bendor.com.au (Zoltan Kocsi) (1999-10-01)
[2 later articles]
| List of all articles for this month |

From: Zoltan Kocsi <zoltan@bendor.com.au>
Newsgroups: comp.sys.m68k,comp.compilers
Date: 20 Sep 1999 12:13:01 -0400
Organization: Bendor Research Pty. Ltd.
Keywords: GCC, question, 68000

Is anyone familiar with the m68k code generator of these compilers ?


I've got a few problems with them. One is the code efficiency:


The strcpy() code in this form:


char *a, *b;
while ( *a++ = *b++ );


compiles to this:


..L7
                move.b (%a0)+,%d0
                move.b %d0,(%a1)+
                jbne .L7


with gcc 2.7.2.3 using -O3; and to this:


..L2
                move.b (%a1)+,(%a0)
                tst.b (%a0)+
                jbne .L2


with egcs-1.1.2 (-O3). Interestingly, the latter code is actually
slower than what is generated by the older gcc (which was already
slower than it should have been) ...


In addition, neither gcc nor egcs seem to treat the 'volatile'
qualifier in any sensible way.


Imagine the situation when you have a write-only hardware register
to which you want to dump a string. That is, you want to do something
like this:


volatile char *hw_reg;
char *the_string;


      do {
*hw_reg = *the_string;
      } while ( *the_string++ != '\0' );


Compiling this creates the same code on both compilers, namely:


..L17:
                move.b (%a0),(%a1)
                tst.b (%a0)+
                jbne .L17


which is just fine and is *exactly* what's written.


However, you might feel tempted to write it the short way:


        while ( *hw_reg = *the_string++ );


expecting to get this more efficient assembly:


loop:
      move.b (a0)+,(a1)
      bne loop


Now this is where your SW/HW interaction blows up because this is
what you get instead (on both compilers):


..L21:
                move.b (%a0)+,(%a1)
                move.b (%a1),%d0
                jbne .L21


That is, they generate code that exactly maps to this C fragment:


    do {
        *hw_reg = *the_string++;
    } while ( *hw_reg != '\0' );


Whoops, reading a write-only register ...


Not to mention that it is not the same as the original while( ).
The original version said that get the data pointed by the (to be
postincremented) the_string pointer, stuff the data to the place
pointed by hw_reg and if the data was not zero, do it again.


What it does is this:
Get the data pointed by the (to be postincremented) the_string pointer,
stuff the data to the place pointed by hw_reg. Read a byte from the place
pointed by hw_reg and if non-zero, do the loop again.


Since hw_reg was declared volatile, the compiler should *not* assume that
writing to it then reading from it will give the same result.
I know that the standard states that any compiler can ignore the
volatile keyword. However, I had the apparently very dangerous assumption
that gcc et al treated volatile with some sensible way (i.e. the number
and order of read/write accesses is kept identical to what the C code
would do without optimisation).


Volatility of objects is obvious in regards to HW access. It should be
noted, however, that multithreaded code is a subject of the same
behaviour. Separate threads live in a common address space. Shared
variables (all globals, actually) are things which you can write to
and not necessarily read back the same value (because in the meantime
an other thread has overwritten it). For this very reason, when I tell
the compiler to put some data into a volatile location and, depending on
the *data*, do some action, it should change it to doing the action
depending on the volatile location's content instead.


Could anyone suggest me which forum / who should I contact to (hopefully)
get some resolution of that problem ?


Thanks,


Zoltan


--
+--------------------------------+---------------------------------+
| Zoltan Kocsi | I don't believe in miracles |
| Bendor Research Pty. Ltd. | but I rely on them. |
+--------------------------------+---------------------------------+
[Re volatile, the compiler is rereading the location exactly because it
can't assume that the same value is there. I've always claimed that
volatile isn't very useful, this is why. If you want reliable code to
deal with hardware registers, you need macros like write-to-location with
machine-specific implementations. -John]





Post a followup to this message

Return to the comp.compilers page.
Search the comp.compilers archives again.