4

I've looked through the TI C/C++ compiler v6.1 user's guide (spru514e) but didn't find anything.

The asm statement doesn't seem to provide anything in this regard, the manual even warns against changing values of variables (p132). The GNU extension for declaring effects on variables is not implemented (p115).

I also didn't find any intrinsic for memory barriers (like __memory_changed() in Keil's armcc).

Searching the web or the TI forums also turned up nothing.

Any other hints how to proceed?

starblue
  • 55,348
  • 14
  • 97
  • 151
  • The ordering requirement seems to be simply with regards to compiler optimizations and scheduling. I don't suppose this could be worked around by moving the `asm` statement out into a static inline function, returning the value you want updated? – unixsmurf Oct 09 '12 at 10:38
  • The [wiki](http://processors.wiki.ti.com/index.php/GCC_Extensions_in_TI_Compilers) says the compiler does not support [Atomic Builtins](http://gcc.gnu.org/onlinedocs/gcc-4.5.1/gcc/Atomic-Builtins.html#Atomic-Builtins). Probably, your only hope is that volatile accesses aren't reordered. And you may need to insert some nops to avoid unprotected pipeline conflicts as explained in the Pipeline chapter of the CPU and Instruction Set Reference guide. If you have multiple CPUs, things can get messier. – Alexey Frunze Oct 09 '12 at 10:43
  • @unixsmurf I don't want to do anything in assembly. An empty inline assembly statement that says it modifies memory is just a way to do a memory barrier in gcc. – starblue Oct 09 '12 at 16:05
  • @Alexey Frunze Thanks for the link, I didn't know that gcc has an explicit memory barrier (´__sync_synchronize()´). As for the TI compiler, `volatile` seems to work, but I want to avoid it, since it would prevent too many compiler optimizations. – starblue Oct 09 '12 at 16:09
  • First, a memory barrier cannot guarantee that you read latest datafrom the memory. It can enforce ordering on the read operations, though. If you really want a memory barrier, why not create a logical one, then? Using volatile keyword in C is acceptable, there a few tricks on how to use volatile, that might reduce your code size while achieving what you want. Or did I divert from your question? – askmish Oct 11 '12 at 17:16
  • The datasheet indicates this is a simple single-core processor. No hint of any out-of-order memory access. So high odds you can't find anything about memory barriers simply because they are unnecessary. Contact TI support to be sure. – Hans Passant Oct 14 '12 at 14:29
  • @Hans Passant The issue is not so much the hardware (actually reads can overtake writes in the pipeline if I understand correctly) but rather the compiler, I want to prevent it from reordering memory accesses in specific places. Currently I can only use very weak optimization (-O1), and the code stops working for more aggressive optimization. – starblue Oct 15 '12 at 10:31
  • @starblue, can you share your code? Not all, of course, just the "problem part". – qehgt Oct 17 '12 at 01:34
  • It's often not a compiler's issue, but the memory model of C/C++. For example, the compiler can assume that `float*` and `int*` pointers are not pointed to same region of a memory. So, the compiler can generate binary with "wrong behavior". – qehgt Oct 17 '12 at 01:39
  • Also, do you use any threads in your code? Interrupts? – qehgt Oct 17 '12 at 01:40
  • @qehgt No, I can't share it, there is no single isolated problem part. It is concurrent with interrupts accessing global data (mostly numbers or static structures containing numbers, almost no pointers, nothing on the heap), and there clearly is insufficient synchronization (nothing is declared volatile). No, we don't do dirty things with pointers (there is not a single void pointer in the code). – starblue Oct 17 '12 at 15:48
  • Well, did you try to declare all data with access from different threads/interrupts as `volatile`? The compiler knows nothing about your interrupts handlers, so it can optimize all access to your global data (and it has rights to do it). – qehgt Oct 17 '12 at 15:59
  • I did some quick tests which helped somewhat, so I'm sure I could make it work by using `volatile`. But as I wrote above I want to avoid that, because it would prevent too many optimizations by the compiler. – starblue Oct 17 '12 at 16:26
  • @starblue You don't need to declare all your global structures as `volatile`. Only part of a `struct` can be declared as `volatile`. Also, you can do needed reads/writes via another `volatile` pointer, but in this case you must be very careful. – qehgt Oct 17 '12 at 17:24
  • 1
    @starblue Also, I remember that we used `asm("")` (with empty string) statement to force compiler to finish all post effects. It was used long ago with very old version of TI compiler. But you can check it, may it still works. Just put this `asm("");` before and after needed reads and writes. – qehgt Oct 17 '12 at 17:35

1 Answers1

8

Memory barriers are about the ordering of memory accesses, but you also have to ensure that values do not stay in registers but are written to memory at all.

The only way to enforce this with TI's compiler is to use volatile.

Please note that volatile, while being a modifier of a variable, is in its implementation not about the variable itself (i.e., its memory), but about all the accesses to this variable. So if you want to avoid the effects of too little optmization, write your program so that only some variable accesses are volatile.

To do this, declare your variables normally, and add volatile only when you want to force a read or write of a variable. You can use helper functions like this:

inline void force_write(int *ptr, int value)
{
    *(volatile int *)ptr = value;
}

or use this nifty macro stolen from Linux, usable for both reading/writing and for all types:

#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
...
if (ACCESS_ONCE(ready) != 0)
    ACCESS_ONCE(new_data) = 42;

(The name has historical reasons; better call it FORCE_ACCESS.)

CL.
  • 173,858
  • 17
  • 217
  • 259