I'll be brief because it's beer time here. yes, I'm convinced that you get the same code with opts and that there's a bug; but, I can't agree to the atomicity of the writes, or at least I didn't explain myself.
Here's what is dangerous with irq enabled: two = P6IN + P6IN; // or any other way in which you write directly to "two" beacuse you inevitably get 2 instructions that sequentially write at the memory address of "two": if an interrupt happens between, it's a mess..... I can't see what you mean with atomicity.
The compiler does not know or care about interrupt functions - it assumes that it has full control of "two" while generating code, and can do what it likes with it.
it's true: YOU have to take care of writing C code correctly so that the compiler won't do too much of what it likes This is safer: tmp = P6IN + P6IN; // or any other way that I would better like two = tmp; because this is what atomic write to a global variable means. And about the usage of the compiler, I've seen that they are typically more effective in removing unnecessary variables (i.e. re-using registers), rather then deciding what is the best allocation....this helps to ensure that the instructions work on register operands as often as possible. Declaring and using locals has no drawback. Cheers, R. 2006/7/3, David Brown <da...@westcontrol.com>:
----- Original Message ----- From: "Roberto Padovani" <padovan...@gmail.com> To: "GCC for MSP430 - http://mspgcc.sf.net" <mspgcc-users@lists.sourceforge.net> Sent: Monday, July 03, 2006 3:35 PM Subject: Re: [Mspgcc-users] Code generation question > >> if you really want that single instruction as a function by itself and > >> you want it to write directly in the global variable, then you should > >> at least declare it naked. > >> > > > >Perhaps this is a case where we have misunderstood each other - as far as I > >can tell, you said that Grant's code should be split with an extra function, > >and I disagreed. Did I misunderstand you? > > if this was the source: > ------------VERSION 1 ------------------ > #include .... > unsigned int two; > > void foo(){ > two = P6IN + P6IN; > } > > void main(){ > .... > foo(); > .... > ..make something with "two"... > } > --------------------------- > > I would have rather rewritten it as: > > > -----------------VERSION 2-------- > #include .... > unsigned int two; > > unsigned int foo(){ > unsigned int tmp; > > tmp = P6IN; > tmp += P6IN; > return tmp; > } > > void main(){ > .... > two = foo(); > .... > ..make something with "two"... > } > ----------------------------- > > and I would especially avoid writing IOCCC style code like: > > unsigned int foo(){ > unsigned int tmp = P6IN; > return tmp + P6IN; > } > It can make sense to avoid having foo() access a global variable - avoiding globals is frequently considered good practice. But it is only useful if "two" is local to main() - if you do decide to use "two" as a global, it is preferable for it to be written inside foo() rather than in main(), assuming that's it's only use in the program. It's a matter of encapsulating the change - consider "foo" to be a function that sets "two", rather than a function that returns a double sample from P6IN. I fail to see that your "IOCCC" style is significantly worse than your original style, although personally I put parenthesis around calculated return values to make them a little clearer. You have still failed to convince me that using "tmp" has any merit - I think (assuming you don't want to set "two" in "foo") the shorter and neater version is better: unsigned int foo(void) { return (P6IN + P6IN); } But ultimately, we are arguing style here - and that is definitely a matter of taste. I hope I have shown you by now that there is no difference in the generated code for such short functions, regardless of whether "tmp" is used or not. > which is exactly the same, but it's the highway to coffe and GDB. > > > >> I came across a similar problem writing for another processor architecture > >> (er OK I admit it a PIC). The line > >> > >> P2 = a+b+c; > >> > > > >In this case, either P2 was declared incorrectly (i.e., it was not declared > >as a volatile), or the compiler generated incorrect code. > > > >In general, yes, the compiler is free to use "two" to store half the > >calculation. In practice, of course, it will not - as you say, it will use > >a register (on the PIC, it makes sense to use the global as a temporary > >storage, since it has no real registers). But the only way to make > >absolutely sure that "two" is not written in two steps is to make "two" a > >volatile as well. > > Apart from the fact that my limited knowledge of volatiles prevents me > to understand how it is possible to ensure that two is not written in > two steps, John highlighted the most important reason for which you > should write that foo function the way I think. > The way in which global data is written is only partially governed by the use of "volatile". In particular, you need an understanding of atomic accesses - "volatile" is no guarentee of atomicity. What you can be sure of is that on a msp430, any simple type of 16-bit or 8-bit size will be writen atomically. This is not guarenteed by C (and is not necessarily true on other architectures - a 16-bit DSP may not be able to write 8-bit data atomically). You can also be confident that the compiler will never write to a global variable more often than you tell it to - the compiler never intentionally generates such sub-optimal code (again, this is not necessarily the case on C-unfriendly architectures). If the variable is volatile, it will be written *exactly* as often as you specify (once the bug is fixed!). But larger variables, such as a 32-bit variable, cannot be written atomically without disabling interrupts. > If you get an interrupt in the middle of the two readings of version > 1, you'll find yourself with an inconsistent value of "two".....and > Murphy assures you that the service routine will be using "two" for > some critical stuff. > In this case, you should declare version 1 of foo() as "critical", > with all the pros and cons of that kind of functions. > It is important to know when and how your global data is read and written, as it forms part of the interface between the functions. Using "critical" is one way to ensure the safety of the code - but it is not the only way. Examining the generated code and understanding the underlying architecture is also a valid way to tell when you can assume "two" is written atomically (it's safe with msp430-gcc, but not with avr-gcc, for example). > With version 2 of foo(), there's never an inconsitency...in the worst > case you'll have an old value of "two" (not updated yet), but this is > a far more predictable behaviour to handle. > That's not actually correct - and possibly even a dangerous assumption if you believe it applies to other sorts of data (such as 32-bit data). You have no more or less guarentees with version 2 code. Consider that the compiler can happily inline the foo() code into main() and eliminate the extra temporary variable - these are perfectly valid optimisations. The resulting internal version of the code is the same in both versions. In each case, the compiler need only ensure that "two" contains the correct, consistent value before calling any code it cannot see while generating the code for main() and/or foo(). The compiler does not know or care about interrupt functions - it assumes that it has full control of "two" while generating code, and can do what it likes with it. If you want to be more precise, your only recourse is to make "two" volatile, and again it does not matter which version you use. Having said that, in practice the compiler will write to "two" atomically in each case, regardless of whether it is set in main() or foo(), and regardless of whether you add an extra local variable or not. As I said, it is important to know how your compiler and your target work, in particular when using interrupts. mvh., David > R. > > Using Tomcat but need to do more? Need to support web services, security? > Get stuff done quickly with pre-integrated technology to make your job easier > Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo > http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642 > _______________________________________________ > Mspgcc-users mailing list > Mspgcc-users@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/mspgcc-users > > > Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642 _______________________________________________ Mspgcc-users mailing list Mspgcc-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mspgcc-users