delphioptimizationvolatile

Are global and heap-based variables always volatile in Delphi?


I have seen similar questions (ex here and here) but never seen a definite answer. Suppose we have following code:

..
I:= 1;
I:= 2;
..

Is Delphi compiler guaranties that the first assignment will never be eliminated by optimizer, and implemented by writing the data to the memory address of I variable, not just to some processor register, if I is global or heap-based (ex. field of an object) variable?


Solution

  • With optimizations enabled, the code above will, at least in some situations, be optimised to remove the first assignment. So this is probably not a very good example!

    That this is so can be seen with this minimal example:

    program OptimiseMe;
    {$APPTYPE CONSOLE}
    {$O+}//switch optimisations on
    var
      I: Integer;
    begin
      I := 1;
      I := 2;
      if I>0 then
        ;
    end.
    

    However, I've never encountered problems with the compiler optimising global or heap based variables into registers. It always seems to write it back to the memory. But I'm sure you won't find anything in the documentation guaranteeing any of that.

    However, this is not the same as MSVC volatile since the cache is in the way and no memory barriers or fences are used. Even when the Delphi compiler emits instructions to write the value to memory, it will first of all go into the cache of the processor on which the code is running. Code executing on other processors will not be able to see that write until the caches have been synchronized.

    If you want to share such a variable between threads, probably the easiest approach is to use the InterlockedXXX functions to enforce the necessary barriers and ensure that all threads have a consistent view of the variable.

    Note: when you talk about volatile, you need to be careful as there are lots of different definitions. The meaning defined in the C and C++ standards is one. The MSVC compiler has a standards compliant but stronger definition. And it's different again in Java and C#. There's a lot of complexity here and the InterlockedXXX functions are a great way to hide that complexity.