Thanks JM!

John


----- Ursprüngliche Nachricht -----
Von: John Regehr
Gesendet am: 15.Oktober.2009 05:06:27


I'd agree that in the code Rohit sent, it is perhaps not reasonable for
teh compiler to know that byte accesses are disallowed.

The casting-away-volatile issue is a red herring I think: notice that the
struct elements are themselves volatile.

The problem in this case is not that the struct is or is not volatile. The 
volatile flag applies to the location, not the value itself. So it just changes 
the way the compiler accesses source and destination location. The
volatile flag in the struct just tell the compiler that there may no 
read-modify-write being used to set the single bits in the struct. Actually it 
is superfluous in this case, as it is only of any importance when defining the
address of the hardware register and not for any variables of the same type.

What I meant is that the compiler should not do any byte-level access if the 
source is a volatile word. Since the source is defined as volatile, the 
compiler cannot assume that two byte transfers will give the same
result as one word transfer. So the compiler should in any case make a word 
transfer, even if into a temporary register.
But by casting away the volatile attribute from the source, it is allowed to do 
byte level access to the source address, leading into trouble. And it does. Why 
it wants to, in this special case,is another thing (see your
other posting).

Anyway, you could do something like
int x=getCtl0().adc12sc
where the low byte of the source wouldn't be necessary at all.
Since the unoptimized code should still do a word access to the source before 
extravting the MSB, even after optimisation there should be still a word access 
despite the fact the the low byte is not necessary at all.



I tried some other thing and got the following result:

volatile adc12ctl0_t ADC12CTL0 __asm ("0x01A0");

static inline adc12ctl0_t getCtl0(void) { return ADC12CTL0; }

volatile  adc12ctl0_t adc = {};

void test (void){
 adc=getCtl0_x();
}

test:
 59:ez3.c         ****   adc=getCtl0_x();
225 0002 3F40 A001              mov     #0x01A0, r15
226 0006 F14F 0000              mov.b   @r15+, @r1
227 000a F14F 0100              mov.b   @r15+, 1(r1)
231 000e 0F41                   mov     r1, r15
232 0010 F24F 0000              mov.b   @r15+, &adc
233 0014 F24F 0000              mov.b   @r15+, &adc+1
234 0006 3041                   ret

which is different but still incorrect.

removing the packed attribute from the struct gives - surprise -

test:
226 0000 9242 A001              mov     &0x01A0, &adc
229 0006 3041                   ret



What I'd like to call your attention to is that face that the msp430-gcc
currently used by TinyOS does the right thing with the test code,
producing this output at -Os:

getCtl0:
   mov  &0x01A0, r15
>  ret

Pehaps this is a symptom of a more serious regression?

Maybe. I'd say that the handling of packed structs has been 'improved', leading 
to unwanted side-effects.

I'm nor sure about the 'does the right thing'. It is of course the (in this 
case) desired result, but is it the right thing?
The struct is defined as being packed. So the compiler cannot (and may not) 
rely on anything inside the struct as being word-aligned.
In case of a register as destination, of course it is. But since the code is 
defined inline, it is of no interest what happens in the function body. 
Therefore I have pasted what the compiler generates inline.
And there is no r15 register for returning a function result.

Anyway, when looking at the function body, I see the same crappy result as I 
got for the original code (with -Os):
539                     getCtl0:
549 0176 5E42 A001              mov.b   &0x01A0, r14
550 017a 5F42 A101              mov.b   &0x01A0+1, r15
551 017e 8F10                   swpb    r15
554 0180 0FDE                   bis     r14, r15
555 0182 3041                   ret

And it immediately disappears when I remove the packed attribute from the 
struct.

Remember that the processor silently ignores the LSB of any word-access 
address. so the code above would be the right way to access (read) any word 
value that is probably not word-aligned. And unfortunately the
wrong way for the 16bit I/O area.

My guess is that there has been a fix for alignment problems, leading to 
problems with 16 bit I/O space (which probably nobody has thought of before)
Anyway, you must consider that the address of the source is not known to the 
compiler as it is an ASM assignment and therefore an 'unknown thing', even if 
it resolves to an absolute address in the assembler stage.
As long as it was an INT type, the compiler could have assumed word alignment. 
But type has forcibly changed. So since the type of the source now is a packed 
and therefore probably not aligned struct, the compiler
may not assume that the given source location (which is still just an arbitrary 
identifier string)  will point to an aligned location. Hence the byte-level 
access. In case of an int, the compiler will trust the programmer that
ints are word-aligned and will do a word access.

Try the following: change the address to 0x01A1. You'll see that with _your_ 
compiler version the compiler will generate a word access to 0x01A1 (trusting 
you that ints are aligned), which leads to unpredictable
results.

With older compiler versions I got into trouble when putting packed structs 
with bytes and words with odd size into a byte stream, accessing the structs 
later with a pointer into the byte stream. Then the ints inside
the structs were not word aligned and the compiler generated faulty word-access 
code. It seems that in newer versions this has been fixed with the now showing 
side-effects of fragile code being broken.
I solved the problem by defining every non-byte-sized element of my structure 
as char[], extracting the values using macros. Maybe this is no longer 
necessary.  But since the macro approach also solved possible
problems with big- and little-endian machines, doing an implicit translation on 
one side, I'm quite happy with it.


From your other posting:

At -Os the older mspgcc also turns this:

adc12ctl0_t getCtl0(void )
{
int i = ADC12CTL0;
return * (adc12ctl0_t *)&i;
}

into:

getCtl0:
        mov     &0x01A0, r15
        ret

Rather than this:

212 0000 2183                   sub     #2, r1  ;       2, fpn 0
218 0002 9142 A001              mov     &0x01A0, @r1
221 0008 6E41                   mov.b   @r1, r14
222 000a 5F41 0100              mov.b   1(r1), r15
223 000e 8F10                   swpb    r15
227 0010 0FDE                   bis     r14, r15
230 0012 2153                   add     #2, r1
231 0014 3041                   ret


Yes, the code looks ugly and unnecessarily bloated, but this is also because 
the compiler in the first step tries to avoid possible alignment problems and 
then in the optimization phase isn't smart enough to 'see' that
it could be optimized in this case.
Remember that between line 218 and 221 the storage place has changed its type 
from an assumed word-aligned int into a packed struct that is not necessarily 
word-aligned (and could be placed at an uneven stack
address as well), so it is read byte by byte and assembled to the word-sized 
return value.

If I remove the packed attribute from the struct, I get the same result as you 
(or rather, as it is inlined code):
 53:ez3.c         **** void test (void){
224 0000 9242 A001              mov     &0x01A0, &adc
224      0000
 54:ez3.c         ****   adc=getCtl0();
 55:ez3.c         **** }
227 0006 3041                   ret


So on the bottom line three advices remain:

Don't add a packed qualifier where it isn't necessary, as it forces the 
compiler to use byte-access to avoid alignment problems (similar for volatile, 
as it prevents much optimization)
and
Don't do typecasting that removes and adds attributes or qualifiers from and to 
pointers, unless you know of the side-effects.
and
Don't take compiler warnings lightly. Discover where they come from and what 
problems they might indicate. And then change the code to remove them.

In most cases this only leads to non-optimal code (even with optimization).
But in this special case it has lead to trouble. And I really see no reason why 
there is a volatile and packed in the struct.

JMGross


------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
Mspgcc-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mspgcc-users

Reply via email to