[AVR] Wrapping a function return statement in ATOMIC_BLOCK - Page 1
Forum section: electronics / general

author: HwAoRrDk
author_rank: Super Contributor
timestamp: October 04, 2019, 12:45:12 am
content: I have a simple function, where all it needs to do is return a volatile multi-byte (uint32_t) global variable. Of course, being prudent, I should use the appropriate mechanisms to access this variable atomically, using ATOMIC_BLOCK. But, it seems inefficient to me to copy the global variable into a local variable inside the atomic block, then return the local one.So, the question is, can I do the following?Code:uint32_t get_foo() {ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {return foo; // A global volatile uint32_t}}I understand that ATOMIC_BLOCK uses some macro and compiler magic to ensure that SREG is saved and restored no matter what exit path from the block is taken, but does this apply to a return?I took a look at the resultant assembly, and Ithinkit's doing what it should, but I would be happy if someone more knowledgeable of AVR assembler were to look at it and confirm.Code:00000712 <get_foo>:712:2f b7inr18, 0x3f; 63714:f8 94cli716:60 91 03 02ldsr22, 0x0203; 0x800203 <foo>71a:70 91 04 02ldsr23, 0x0204; 0x800204 <foo+0x1>71e:80 91 05 02ldsr24, 0x0205; 0x800205 <foo+0x2>722:90 91 06 02ldsr25, 0x0206; 0x800206 <foo+0x3>726:2f bfout0x3f, r18; 63728:08 95retIf I'm understanding this correctly, it's saving SREG in r18, disabling interrupts, copying foo into function return registers, restoring SREG, and finally returning.If this is all correct and hunky-dory, and follows my intention to atomically access the foo variable, then great.All I need to do is take care of the compiler warning saying "control reaches end of non-void function". I guess I could whack in a second return statement (that will never be reached) outside the block.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: October 04, 2019, 01:13:55 am
content: This discusses the warning (and the same situation):https://www.avrfreaks.net/forum/atomicblock-control-reaches-end-non-void-functionYou can use a temporary variable, as listed above.Or: don't put it in a function at all. If this example is truly all that the function contains, then it is a trivial example, and should either be inlined (on -O3, this will probably happen automatically), put into a macro (#define get_foo ...), or just pasted into the calling function verbatim.Tim

author: HwAoRrDk
author_rank: Super Contributor
timestamp: October 04, 2019, 01:44:49 am
content: Coincidentally I found and have just been reading that linked thread.Yes, even though it's a trivial function, I need it to be a function because it will be a callback function pointer that is passed to something else. In fact, I have specifically marked it with an attribute to prevent it being inlined.I just tried putting in a second return statement ("return 0;" after the atomic block), and the compiler actually ignores it and emits no additional instructions for it.So, I guess I just need to know if the assembly I posted previously is actually doing the right thing. Hopefully someone can confirm my interpretation.

author: cv007
author_rank: Frequent Contributor
timestamp: October 04, 2019, 02:29:34 am
content: https://godbolt.org/z/B_y4c3Compilers are pretty smart, so usually no need to try to out-think it.

author: westfw
author_rank: Super Contributor
timestamp: October 04, 2019, 11:09:49 pm
content: I lot of compilers will implement a "return" in the middle of a function as a jump to the function epilogue, anyway. (that way they only need the epilogue once.) So all that's needed is to make sure that the re-enable of interrupts happens gets added to what gcc considers the epilogue of the function. IIRC, ATOMIC_BLOCK actually does some magic to make sure that this is the case...Ah, yes. Seehttps://blog.oddbit.com/post/2019-02-01-atomicblock-magic-in-avrlibc/