Statement as memory barrier for globals ("volatile") lazarus / 62-General ---------------------------------------------------------------------- kupferstecher · 2017-11-15 12:23 I found a discussion about why fpc doesn't need the volatile modifier for variables as it exists in C (Link below) and still is capable of doing optimisations. My understanding is that global variables are loaded or stored for each statement they are used at least once (implicit "volatile" for globals). And on contrast local variables are free for any optimisations, also throughout several statements or may be even optimised away. My question now is, which variables are 'global' and which are 'local' in the meaning of memory barriers? A variable defined in the units interface section is global (of course). A variable pointing to an absolute address is global (yes). Is a public variable of a class or object 'global'? Is a private variable of a class or object 'global'? Is a class variable 'global'? Is a variable defined in the implementation section 'global'? So i want to know if there is anything to consider regarding optimisations when using interrupt handlers for example (target embedded). Thanks! I cite: QuoteIn FPC, every statement is basically considered to be a compiler- level memory barrier for accesses to global variables. So within a single statement multiple accesses can be optimised, but that cannot happen not across statements. It's not perfect since it inhibits some optimisation, but on the flip side it's very simple and easy to reason about. [...] The reason the need for volatile on embedded systems is far less in FPC, is the existence of the "absolute" keyword. In C, you have to declare all of those memory mapped registers as volatile pointers, because otherwise things will get optimised wrongly. In FPC, you can declare them as variables that are "absolute" at some address, and the compiler will never optimise their accesses. Only if you would take the address of one of these variables and store it in a pointer, you would need "volatile" in this context.http://lists.freepascal.org/pipermail/fpc- pascal/2015-December/046055.html ---------------------------------------------------------------------- Thaddy · 2017-11-15 15:08 Volatile (C and derivatives) is the same as a Pascal writeable typed const ({$J+/-} It indicates a type of var (typed const) that needs an allocation instead of being optimized away to a fixed - const - value. It has a memory allocation on the heap instead of on the stack. Pascal had that *before* C and derivatives. Example: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program volatility;{$mode objfpc} function ShowVolatile:integer;{$push}{$J+}const t:integer = 0; // this equals a C type volatile....{$pop}begin  Result := t;  inc(t); // almost always an atomic operation for the native register sizeend; var i:integer;begin  for i := 0 to 9 do writeln(ShowVolatile);end. Which also demonstrates that your informant was wrong: Pascal sometimes needs a "volatile" and the language provides it.... Note that on most - but not all - platforms this is atomic for the native register size or less... (And NO C isn't any better..... worse) ---------------------------------------------------------------------- kupferstecher · 2017-11-15 15:58 Thats interesting. Why seems that nobody knows that? But how about the global variables, don't they provide the same? ---------------------------------------------------------------------- Thaddy · 2017-11-15 16:09 Quote from: kupferstecher on November 15, 2017, 04:58:35 pmThats interesting. Why seems that nobody knows that? But how about the global variables, don't they provide the same? Yes and no: global variables are global. Volatiles aren't. In the above example the volatile T is not accessible on a global level. Scoping. C used to use simple globals but that is at the risk of unintentionally modifying it. Pascal also allows that, though. And.... really old hands know.... All of'm... Maybe wikipedia helps (again, pretty accurate): https://en.wikipedia.org/wiki/Volatile_(computer_programming) Even after the wiki it can be confusing: scoping tells it all: a volatile can be scoped, whereas a global can not. ---------------------------------------------------------------------- kupferstecher · 2017-11-15 20:14 Scoping is clear so far. I did a little testing on target AVR: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i while not IsSet do;if IsSet is a local variable, then this will be kept as a register without address in the RAM, if its a field variable of an object, then it will be reloaded in each loop, even for the highest optimisation. For interrupt use this would normally be enough, but the question is if thats defined behaviour, or just a missing optimisation for that target. ---------------------------------------------------------------------- engkin · 2017-11-15 20:31 Quote from: Thaddy on November 15, 2017, 04:08:38 pmVolatile (C and derivatives) is the same as a Pascal writeable typed const ({$J+/-} Sounds like you confused volatile with static. ---------------------------------------------------------------------- Thaddy · 2017-11-15 21:31 Quote from: engkin on November 15, 2017, 09:31:59 pmQuote from: Thaddy on November 15, 2017, 04:08:38 pmVolatile (C and derivatives) is the same as a Pascal writeable typed const ({$J+/-} Sounds like you confused volatile with static. No. C people have a different understanding of static. We have the correct one... It is as I explained. As an afterthought, I put a wikipedia link for that reason. Read that. Or study computer science... ---------------------------------------------------------------------- engkin · 2017-11-16 02:33 Quote from: Thaddy on November 15, 2017, 10:31:51 pmQuote from: engkin on November 15, 2017, 09:31:59 pmQuote from: Thaddy on November 15, 2017, 04:08:38 pmVolatile (C and derivatives) is the same as a Pascal writeable typed const ({$J+/-} Sounds like you confused volatile with static. No. C people have a different understanding of static. We have the correct one... It is as I explained. As an afterthought, I put a wikipedia link for that reason. Read that. Or study computer science... Thank you for the clarification and for the advice. I still think that your Pascal function ShowVolatile translates into C more or less like: Code: C  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i int ShowVolatile(){    static int t = 0;     return (t++);} Where did I go wrong? ---------------------------------------------------------------------- kupferstecher · 2017-11-17 19:49 Thaddys example in my eyes also doesn't look like we are talking about the same topic, it seems to have nothing to do with optimisation. The wiki-link on the other hand is about the topic I asked about. Is there something in the documentation about that topic? I didn't find anything. Regards ---------------------------------------------------------------------- ASerge · 2017-11-17 21:59 Quote from: kupferstecher on November 15, 2017, 01:23:30 pmMy understanding is that global variables are loaded or stored for each statement they are used at least once (implicit "volatile" for globals). And on contrast local variables are free for any optimisations, also throughout several statements or may be even optimised away. My question now is, which variables are 'global' and which are 'local' in the meaning of memory barriers? Variables inside functions or procedures are local. Global variables are defined outside function or procedure, those, the variables of the units and the body of the main program. Class or object fields are often called member variables. They behave as global, because they are available in different functions, but as local ones, because only used in the context of a class variable. This is the scope property. Static is the lifetime of variable (until the end of the program). For example, all global variables. Or typed consts (local). Or class variables. The absolute variable has the same properties as the variable that it refers to. Those, can be global, local, static, etc. Volatile are variables in the C language that compiler must exclude from optimization, because their value can change outside the executed code. There is no corresponding directive in FPC. In C volatile can be static or not, global or local. Global, local, member, static, absolute variables can be optimized by the compiler (now or in the future). To exclude a variable from optimization, replace it with a function call. ---------------------------------------------------------------------- tetrastes · 2017-11-17 22:35 Quote from: Thaddy on November 15, 2017, 10:31:51 pmQuote from: engkin on November 15, 2017, 09:31:59 pmQuote from: Thaddy on November 15, 2017, 04:08:38 pmVolatile (C and derivatives) is the same as a Pascal writeable typed const ({$J+/-} Sounds like you confused volatile with static. No. C people have a different understanding of static. We have the correct one... It is as I explained. As an afterthought, I put a wikipedia link for that reason. Read that. Or study computer science... So much clever words. This is translation of your example to C: Code: C  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i #include     int ShowVolatile(void){    volatile int t = 0; // this IS a REAL C type volatile....    return t++;} void main(void){         int i;        for(i = 0; i < 10; i++) printf("%d\n", ShowVolatile());}   Compare the results. And then change volatile to static... ---------------------------------------------------------------------- kupferstecher · 2017-11-18 15:49 Quote from: ASerge on November 17, 2017, 10:59:49 pmGlobal, local, member, static, absolute variables can be optimized by the compiler (now or in the future). To exclude a variable from optimization, replace it with a function call. To use functions is quite ugly, there should be other methods. At least the globals with absolute adress have to work, otherwise the register definitions would be useless and registers only accessible through inline asm. Sorry that I'm sceptical, but there are already contradicting statements now (Writable typed constants, globals, not possible at all...). If there would be some reference, documentation... ---------------------------------------------------------------------- jamie · 2017-11-19 02:45 Volatile is not really in the Pascal language however, if you properly code you can come up with the same effect.  Volatile simply tells the compiler that this "VARIABLE" could change without notice and there for it should not be loaded in a Register for remaining code, the compiler should always reference the variable from memory each time it needs to Read it and not optimize code to load its value into a register for the remaining use of that variable in the current block.  The best use for volatile variables is for things like Thread control, interrupt status changes etc.  as for most Pascal generated code I think you'll notice it always reads from the original source.  the only time it would only read once would be in a control loop, where as, changing the value in the middle of a control loop would cause issues.  As for the rest of it here.  Writable constants are STATIC variables, defined at compile time and loaded as that value but can be changed..   They can be local to the procedure/function or global.  Does that help? ---------------------------------------------------------------------- kupferstecher · 2017-11-19 08:51 Quote from: jamie on November 19, 2017, 03:45:20 amVolatile is not really in the Pascal language however, if you properly code you can come up with the same effect.Thanks for your post. I try to get the understanding how to do it correctly, as for target embedded this is elementary. QuoteVolatile simply tells the compiler that this "VARIABLE" could change without notice and there for it should not be loaded in a Register for remaining code, the compiler should always reference the variable from memory each time it needs to Read it and not optimize code to load its value into a register for the remaining use of that variable in the current block.Yes, thats what I need. QuoteDoes that help?Well thats a somehow a fourth opinion now, I should keep track, see below. Volatiles are - all writable typed constants - all globals - not possible at all - variables that are not in loops Btw I tested with writable typed constants (as local constant in a procedure) and for Target AVR they are reloaded in each loop cycle, while "standard" local vars are only kept in a register (Even doesn't have a physical address). Tested with -O4. But Target AVR doesn't optimise that much anyways, and there surely should be some documentation about such behaviour. Does no one have a reference? ---------------------------------------------------------------------- engkin · 2017-11-21 02:26 Quote from: kupferstecher on November 19, 2017, 09:51:52 amDoes no one have a reference? I don't think anyone has a reference because it does not exist. What we can try to do is to test and prove the claims we see here. For instance, someone claimed that "volatile in Pascal is just a writable typed const". So we have to find one example where this claim does not seem to be true: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program project1; {$mode objfpc}{$H+} uses  {$IFDEF UNIX}{$IFDEF UseCThreads}  cthreads,  {$ENDIF}{$ENDIF}  Classes  { you can add units after this }; {$push}{$J+}const t:integer = 0;{$pop}var  i: integer;begin  t := 1;  i := t;  i := t;  i := t;  i := t;  i := t;  i := t;  i := t;  i := t;  i := t;  i := t;end. The compiler (using -O3) emitted the following assembly: Code: ASM  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i _main:# Var i located in register eax# [project3.lpr]# [18] begin        call    FPC_INITIALIZEUNITS        movl    $0,%eax# [19] t := 1;        movl  $1,TC_$P$PROJECT1_$$_T# Var i located in register eax# [20] i := t;      movl    $1,%eax# Var i located in register eax# [21] i := t;      movl    $1,%eax# Var i located in register eax# [22] i := t;        movl    $1,%eax# Var i located in register eax# [23] i := t;        movl    $1,%eax# Var i located in register eax# [24] i := t;        movl    $1,%eax# Var i located in register eax# [25] i := t;        movl    $1,%eax# Var i located in register eax# [26] i := t;        movl    $1,%eax# Var i located in register eax# [27] i := t;        movl    $1,%eax# Var i located in register eax# [28] i := t;        movl    $1,%eax# Var i located in register eax# [29] i := t;        movl    $1,%eax Notice how i := t got optimized to movl $1,%eax This refutes the claim that writable typed const in Pascal are equivalent to volatile variables in C. @tetrastes Thanks for the C example. ---------------------------------------------------------------------- jamie · 2017-11-21 22:33 I think you miss understand it. Volatile simple means that if for example in a loop you were to keep referring to a variable for a value, the compiler should not move that value into a register and never reference that variable from memory again while in that loop.  Moving values from memory to registers is a standard practice but the point is, the next time around the code is to examine that memory variable, it is to reload that register again from the same location!....  I really can't think of a case where fpc would do that anyway other than an internal value set at the start of a loop, like a for Loop statement. That counter can start from a memory variable or constant and be moved into a register for the remainder of the loop, but listen, it is part of the loop control not the monitoring of live data changes from sources out side your current block. ---------------------------------------------------------------------- engkin · 2017-11-22 05:16 Quote from: jamie on November 21, 2017, 11:33:55 pm Moving values from memory to registers is a standard practice but the point is, the next time around the code is to examine that memory variable, it is to reload that register again from the same location!.... FPC does not do that when using writable typed const, and that was the point I tried to show in my previous post. Hence the conclusion that writable typed const are not equivalent to volatile variables in C. Here is a similar C example: Code: C  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i int main(void){    volatile int t = 0;    t = 1;    int i;    i = t;    i = t;    i = t;    i = t;    i = t;    i = t;    i = t;    i = t;    i = t;    i = t;} Here is the relevant part of the emitted assembly: Code: ASM  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i LVL0:      .loc 1 5 0        movl    $0, 12(%esp)        .loc 1 6 0        movl    $1, 12(%esp)        .loc 1 8 0        movl    12(%esp), %eax        .loc 1 9 0        movl    12(%esp), %eax        .loc 1 10 0        movl    12(%esp), %eax        .loc 1 11 0        movl    12(%esp), %eax        .loc 1 12 0        movl    12(%esp), %eax        .loc 1 13 0        movl    12(%esp), %eax        .loc 1 14 0        movl    12(%esp), %eax        .loc 1 15 0        movl    12(%esp), %eax      .loc 1 16 0        movl    12(%esp), %eax        .loc 1 17 0        movl    12(%esp), %eax        .loc 1 18 0 Notice how it reads the value from memory every time: movl   12(%esp), %eax Quote from: jamie on November 21, 2017, 11:33:55 pm I really can't think of a case where fpc would do that anyway other than an internal value set at the start of a loop, like a for Loop statement. That counter can start from a memory variable or constant and be moved into a register for the remainder of the loop, but listen, it is part of the loop control not the monitoring of live data changes from sources out side your current block. I really think you should try to see the assembly code emitted for the following for loops: Code: C  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   for(i=0;i<10;i++)    t = i;   for(t=0;t<10;t++)    i = t; ---------------------------------------------------------------------- kupferstecher · 2017-11-22 10:45 Quote from: engkin on November 21, 2017, 03:26:13 amSo we have to find one example where this claim does not seem to be true:It's a good method, but could also mean the compiler is buggy I tried the same with globals and with globals with absolute modifier and some statemets are optimised away (Tested on i368). QuoteI don't think anyone has a reference because it does not exist.Seems like. At least for FPC in general. Perhaps the implementations for target embedded are different. As the registers are defined as globals with absolute address, this must work, otherwise it would be nonsence. ---------------------------------------------------------------------- engkin · 2017-11-22 18:57 Quote from: kupferstecher on November 22, 2017, 11:45:25 amQuote from: engkin on November 21, 2017, 03:26:13 amSo we have to find one example where this claim does not seem to be true:It's a good method, but could also mean the compiler is buggy It is hard to say, as it does not produce unexpected results, or violates the documentation. Maybe just lacks a feature. Quote from: kupferstecher on November 22, 2017, 11:45:25 amI tried the same with globals and with globals with absolute modifier and some statemets are optimised away (Tested on i368). As you can see, it is not there. FPC does not have any thing similar to volatile variables in C. Quote from: kupferstecher on November 22, 2017, 11:45:25 amQuoteI don't think anyone has a reference because it does not exist.Seems like. At least for FPC in general. Perhaps the implementations for target embedded are different. As the registers are defined as globals with absolute address, this must work, otherwise it would be nonsence. I doubt it. But even if a global variable with absolute modifier works, that by itself solves part of the problem, the other part when you need a variable for the general case, not one specific register. ---------------------------------------------------------------------- kupferstecher · 2017-11-22 19:57 So where to address that issue? In the bug tracker as feature request? ---------------------------------------------------------------------- engkin · 2017-11-22 20:26 YES, with a patch implementing it.  You tried here, and most likely no more responses will be added to this thread. So still two more places: the bug tracker and the mailing list. Most core developers seem to prefer the mailing list over the forums. ---------------------------------------------------------------------- kupferstecher · 2017-11-23 10:35 So I'll suppose the 'globals solution' in the bug tracker. Quote from: engkin on November 22, 2017, 09:26:02 pmwith a patch implementing it.  I would if I could~ Regards ---------------------------------------------------------------------- Thaddy · 2017-11-23 10:43 Quote from: engkin on November 22, 2017, 06:16:04 amFPC does not do that when using writable typed const, and that was the point I tried to show in my previous post. Hence the conclusion that writable typed const are not equivalent to volatile variables in C. It should be. Otherwise it is a bug and not a feature request. But you showed indeed a problem. Very eloquently. ---------------------------------------------------------------------- kupferstecher · 2017-11-23 11:17 I filed a feature request in the bug tracker: https://bugs.freepascal.org/view.php?id=32721 Thaddy, in the fpc language reference I didn't find anything that supports your claim. This means even if the way you say is the correct pascal way, than for fpc this would mean to be a new feature, right? ---------------------------------------------------------------------- Thaddy · 2017-11-23 11:41 "In computer programming, particularly in the C, C++, C#, and Java programming languages, the volatile keyword indicates that a value may change between different accesses, even if it does not appear to be modified. This keyword prevents an optimizing compiler from optimizing away subsequent reads or writes and thus incorrectly reusing a stale value or omitting writes." Which is EXACTLY the same as an assignable typed const behaves. I rest my plea... Back to school as far as I am concerned. ---------------------------------------------------------------------- ccrause · 2017-11-23 11:52 Volatile has been debated in the past, see e.g. this thread. This reply by Jonas to another thread suggests that (at least in 2015) in FPC there isn't a full equivalent of "volatile".  From Jonas's reply it appears that the use of the "absolute" keyword implies the compiler "will never optimize their accesses".  Also Jonas stated the following: "In FPC, every statement is basically considered to be a compiler-level memory barrier for accesses to global variables." ---------------------------------------------------------------------- Thaddy · 2017-11-23 11:55 I am quite sure Jonas will to some extend support my explanation. The difficulty on this forum is always that we have users (often extremely good programmers!) and users that are third grade computer scientists (like me) Funny thing is you did not read that answer carefully: "The reason the need for volatile on embedded systems is far less in FPC, is the existence of the "absolute" keyword. In C, you have to declare all of those memory mapped registers as volatile pointers, because otherwise things will get optimised wrongly. In FPC, you can declare them as variables that are "absolute" at some address, and the compiler will never optimise their accesses. Only if you would take the address of one of these variables and store it in a pointer, you would need "volatile" in this context. " Dunno what you think, but..... Probably overlooked assignable typed constants and mentioned absolute. All covered. < very, very, grumpy  > ---------------------------------------------------------------------- kupferstecher · 2017-11-23 12:13 Quote from: Thaddy on November 23, 2017, 12:41:55 pm"indicates that a value may change between different accesses, even if it does not appear to be modified."Means the following code line   writeln(Inttostr(aVolatile)); writeln(Inttostr(aVolatile)); may print two different values. The volatile concept is clear. But where do you connect it to the writable typed constant? From the language reference: Quote2.2 Typed constants [...] Contrary to ordinary constants, a value can be assigned to them at run-time. This is an old concept from Turbo Pascal, which has been replaced with support for initialized variables: For a detailed description, see section 4.4, page 223. [...]Again where do you see the connection? It doesn't say anything about optimisation, it just says that the constant will behave like a variable. @ccrause: The sentence "In FPC, every statement is basically considered to be a compiler-level memory barrier for accesses to global variables." isn't true for current compilers (optimisation is done by the compiler). For target embedded it may be true, but its not documented. ---------------------------------------------------------------------- engkin · 2017-11-23 14:32 Quote from: Thaddy on November 23, 2017, 11:43:29 amQuote from: engkin on November 22, 2017, 06:16:04 amFPC does not do that when using writable typed const, and that was the point I tried to show in my previous post. Hence the conclusion that writable typed const are not equivalent to volatile variables in C. It should be. Otherwise it is a bug and not a feature request. But you showed indeed a problem. Very eloquently. Your insistence is impressive. When was it functioning? I just tried an older development version of FPC (2.7.1 from 2013). The results are funnier.It is not documented, can you explain why? Do you think a bug report is needed against the documentation?How about Delphi, is it the same? Can you test the code in this post using Delphi (any version)? ---------------------------------------------------------------------- Martin_fr · 2017-11-23 18:20 Quote from: Thaddy on November 23, 2017, 12:41:55 pmWhich is EXACTLY the same as an assignable typed const behaves. NO! It is not. typed (writable) constants are prevented from being inlined. That is all. Otherwise they can still be optimized Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i const a: integer = 1;...begin  b := a;  c := a;end;  The compiler can optimize this to - load a into a register - write the register to b - write the register to c meaning b and c will always be the same. In case of volatile b and c may differ, if a was changed by something outside the programs flow. Therefore "volatile" prevents caching of a in a register between the 2 statements ---------------------------------------------------------------------- engkin · 2017-11-25 17:36 Quote from: Martin_fr on November 23, 2017, 07:20:14 pmQuote from: Thaddy on November 23, 2017, 12:41:55 pmWhich is EXACTLY the same as an assignable typed const behaves. NO! It is not.Thaddy is still holding his position but this time in the bug tracker. Nothing will change his mind, nothing.  OTOH, Remy Lebeau on SO: QuoteStarting with Delphi 10.1 Berlin, the desktop compilers now support [volatile] as well. http://docwiki.embarcadero.com/RADStudio/Berlin/en/Compiler_Attributes #Volatile ---------------------------------------------------------------------- jamie · 2017-11-26 00:53 I understand your pain.. Really....  Its called Software politics, Resistance is FUTILE.  At least Embarcadero knows what it's for. ---------------------------------------------------------------------- engkin · 2017-11-26 01:28 Quote from: jamie on November 26, 2017, 01:53:22 am At least Embarcadero knows what it's for. FPC has more cases where volatile would be needed. ---------------------------------------------------------------------- ccrause · 2017-11-26 05:17 Lets do some checks with the following concept code Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program testVarAccess;var i: word;begin  i := 255;  if i > 0 then     i := 0;   while True do  begin    if i = 1234 then      i := 0;  end;end.Compiled with: Code: [Select] -Tembedded -Pavr -CpAVR5 -MObjFPC -Sm -O4 -vabq -Filib/avr-embedded -Fu. -FUlib/avr-embedded -FE../ -Wpatmega328p -g -a -XPavr- -al -Sm -Si -dF_CPU:=16000000Note -O4. Generated code for main: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i begin  9e: 0e 94 5c 00     call    0xb8    ; 0xb8   i := 255;  a2:   2f ef           ldi     r18, 0xFF       ; 255  a4:   21 2d           mov     r18, r1  if i > 0 then     i := 0;  a6:   31 2d         mov     r19, r1  a8:   21 2d           mov     r18, r1   while True do  begin    if i = 1234 then  aa:   32 3d           cpi     r19, 0xD2       ; 210  ac:   44 e0           ldi     r20, 0x04       ; 4  ae:   24 07           cpc     r18, r20  b0:   e1 f7           brne    .-8             ; 0xaa       i := 0;  b2:   31 2d         mov     r19, r1  b4:   21 2d           mov     r18, r1  while True do  b6:   f9 cf           rjmp    .-14            ; 0xaa Clearly variable i is treated as a register variable only, which in this case is both correct and generates compact code. Now test what happens if an interrupt is also added to the mix: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program testVarAccess; var i: word; procedure Timer0Overflow; alias: 'TIMER0_OVF_ISR'; interrupt;begin  inc(i);end; begin  i := 255;  if i > 0 then     i := 0;   while True do  begin    if i = 1234 then      i := 0;  end;end.Generated code: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure Timer0Overflow; alias: 'TIMER0_OVF_ISR'; interrupt;begin  9e:   af 93         push    r26  a0:   4f 93           push    r20  a2:   3f 93         push    r19  a4:   2f 93           push    r18  a6:   0f 92         push    r0  a8:   0f b6           in      r0, 0x3f        ; 63  aa:   0f 92           push    r0  inc(i);  ac:   40 91 00 01     lds   r20, 0x0100  b0:   30 91 01 01     lds     r19, 0x0101  b4:   21 e0         ldi     r18, 0x01       ; 1  b6:   42 0f           add     r20, r18  b8:   31 1d           adc     r19, r1  ba:   40 93 00 01   sts     0x0100, r20  be:   30 93 01 01     sts     0x0101, r19end;  c2:   0f 90           pop     r0  c4:   0f be           out     0x3f, r0        ; 63  c6:   0f 90           pop     r0  c8:   2f 91         pop     r18  ca:   3f 91           pop     r19  cc:   4f 91         pop     r20  ce:   af 91           pop     r26  d0:   18 95           reti 000000d2 : begin  d2:   0e 94 8d 00     call    0x11a   ; 0x11a   i := 255;  d6:   3f ef           ldi   r19, 0xFF       ; 255  d8:   21 2d           mov     r18, r1  da: 30 93 00 01     sts     0x0100, r19  de:   20 93 01 01     sts     0x0101, r18  if i > 0 then  e2:   30 91 00 01     lds     r19, 0x0100  e6:   20 91 01 01     lds     r18, 0x0101  ea:   13 16           cp    r1, r19  ec:   12 06           cpc     r1, r18  ee:   30 f4         brcc    .+12            ; 0xfc      i := 0;  f0:   21 2d           mov     r18, r1  f2:   31 2d           mov     r19, r1  f4:   20 93 00 01     sts     0x0100, r18  f8:   30 93 01 01     sts     0x0101, r19   while True do  begin    if i = 1234 then  fc:   20 91 00 01     lds     r18, 0x0100 100:   30 91 01 01     lds     r19, 0x0101 104:   22 3d           cpi     r18, 0xD2       ; 210 106: 24 e0           ldi     r18, 0x04       ; 4 108:   32 07           cpc     r19, r18 10a:   c1 f7           brne    .-16            ; 0xfc       i := 0; 10c:   31 2d           mov     r19, r1 10e:   21 2d           mov     r18, r1 110:   30 93 00 01     sts   0x0100, r19 114:   20 93 01 01     sts     0x0101, r18  while True do 118:   f1 cf           rjmp    .-30            ; 0xfc Clearly the interrupt functionality requires that variable i be read from memory on every access.  The generated code above clearly demonstrates this is the case. So the compiler seems to recognize when not to optimize memory access away, at least in this rather trivial test case.  Now if only this behaviour is guaranteed and documented the whole need for volatile is redundant. ---------------------------------------------------------------------- molly · 2017-11-26 17:14 Quote from: ccrause on November 26, 2017, 06:17:59 amSo the compiler seems to recognize when not to optimize memory access away, at least in this rather trivial test case.  Now if only this behaviour is guaranteed and documented the whole need for volatile is redundant. And i believe that is also what Thaddy was hinting on. The documentation states: QuoteContrary to ordinary constants, a value can be assigned to them at run-time. In case the compiler optimized things away between different calls then it is the compiler/optimizer at fault, not respecting the consequences of the statement made in the documentation. Do note that code optimization is really not my area of knowledge, so a compiler developer might argue that the default behaviour in such cases is undetermined. Is that mentioned somewhere in the documentation or should that be considered common knowledge ? In that regards i also don't fully understand why there would be need for a compiler hint to force this or that, unless it isn't possible to guarantee the compiler behaviour in any other way. ---------------------------------------------------------------------- engkin · 2017-11-26 23:29 Quote from: ccrause on November 26, 2017, 06:17:59 amSo the compiler seems to recognize when not to optimize memory access away, at least in this rather trivial test case. As you can see, we are guessing and we don't know the rules. Quote from: ccrause on November 26, 2017, 06:17:59 amNow if only this behaviour is guaranteed and documented+1 Quote from: ccrause on November 26, 2017, 06:17:59 am the whole need for volatile is redundant. I disagree, volatile would help both the programmer and the compiler not to guess. Here is a test where an interrupt procedure is *not* used: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program testVarAccess; var  b1, b2: byte;//  pb1, pb2: pbyte; begin{  pb1 := @b1;  pb2 := @b2;  //}   b1 := 255;  if b1 > 0 then     b2 := 0;   while True do  begin    if b2 = 123 then      b1 := 0;  end;end. Code: ASM  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i .globl  mainmain:# Var b1 located in register r18# Var b2 located in register r19# [Blinky.lpr]# [7] begin        call    FPC_INIT_FUNC_TABLE# Var b1 located in register r18# [11] b1 := 255;        ldi     r26,-1      mov     r18,r26# Var b2 located in register r19# [13] b2 := 0;      mov     r19,r1.Lj3:# [17] if b2 = 123 then        cpi     r19,123      brne    .Lj3# [18] b1 := 0;        mov     r18,r1# [15] while True do        rjmp    .Lj3# [20] end. See what happens when you add pointers: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program testVarAccess; var  b1, b2: byte;  pb1, pb2: pbyte; begin  pb1 := @b1;  pb2 := @b2;  //}   b1 := 255;  if b1 > 0 then     b2 := 0;   while True do  begin    if b2 = 123 then      b1 := 0;  end;end. Code: ASM  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i .globl  mainmain:# Var pb1 located in register ??:r18# Var pb2 located in register ??:r18# [Blinky.lpr]# [7] begin        call    FPC_INIT_FUNC_TABLE# [8] pb1 := @b1;        ldi     r18,lo8(U_sPsTESTVARACCESS_ss_B1)        ldi     r19,hi8(U_sPsTESTVARACCESS_ss_B1)# Var pb1 located in register r18# [9] pb2 := @b2;  //}        ldi     r18,lo8(U_sPsTESTVARACCESS_ss_B2)        ldi     r19,hi8(U_sPsTESTVARACCESS_ss_B2)# Var pb2 located in register r18# [11] b1 := 255;        ldi     r26,-1        mov     r18,r26        sts     (U_sPsTESTVARACCESS_ss_B1),r18# [12] if b1 > 0 then        lds     r18,(U_sPsTESTVARACCESS_ss_B1)        cp      r1,r18        brsh    .Lj5# [13] b2 := 0;        mov     r18,r1      sts     (U_sPsTESTVARACCESS_ss_B2),r18.Lj5:# [17] if b2 = 123 then      lds     r18,(U_sPsTESTVARACCESS_ss_B2)        cpi     r18,123      brne    .Lj5# [18] b1 := 0;        mov     r18,r1        sts     (U_sPsTESTVARACCESS_ss_B1),r18# [15] while True do        rjmp    .Lj5# [20] end. Notice how b1 and b2 without pointers where optimized in registers, while with pointers they were treated as volatile variables. It gets complicated when you use pointers, and the compiler tries the safest way and assumes these variables to be volatile which was not necessary. More over, you used a small chip that does not take an external memory. Volatile is of more importance when the compiler deals with what seems to the CPU (or MC) as a normal [external] memory access while in fact is an I/O port. Without volatile the compiler will optimize the code wrongly. On top of the above: Why did Embarcadero add volatile to Delphi?What about compatibility with Delphi? ---------------------------------------------------------------------- engkin · 2017-11-27 00:31 Quote from: molly on November 26, 2017, 06:14:58 pmIn that regards i also don't fully understand why there would be need for a compiler hint to force this or that, unless it isn't possible to guarantee the compiler behaviour in any other way. Nothing in the documentation prevents the compiler from keeping a constant in a register, and based on {$J} it may allow/prevent a change to its value. On the other hand, accessing a volatile variable means accessing the memory every time, no matter what. Simple example: Imagine a set of ten temperature sensors memory mapped to one location. Every time you read that location you actually read a different sensor. So to read the same sensor twice you have to read that location 11 times!! The first reading holds the first value of that sensor, and the 11th reading holds the second value. Without volatile, the compiler will give you the first reading always. Of course there are solutions, like using assembly, or using a function. Both imply that there is no equivalent to volatile in Pascal. ---------------------------------------------------------------------- jamie · 2017-11-27 02:51 Running some more test, it seem that writeable constants for the moment, at least the test I did was always being referenced however, there is also a optimizer issue here.  If I were to assign several variables with the same constant writeable value, then it simply waste code space and time reloading each one when the first load could load that into a register and then use that Reg to define the rest...    because someone decided to make writeable constants act this way even when it means bloated code generation, when not needed, you have no choice to force the compiler to act inefficiently..    If the key word VOLATILE was employed, you can then have writeable constants be register loaded for a serials of defines when there is no volatile issue but, when there is a volatile issue, one could prefix it with the keyword VOLATILE or mark the writeable constant as Volatile, then the compiler can do what it is currently doing now, and that is keep reloading from the constant source.  as it is now, it makes for bloated code if that is the actual intention behind it or it just maybe a fluke that it just happen to end up that way out of convenience.  I would feel better if the VOLATILE keyword was employed so that we know for sure the compiler is behaving like it should be and when not using the volatile we could assume the compiler will take advantage of optimizing the writeable constants. ---------------------------------------------------------------------- kupferstecher · 2017-11-27 12:27 Quote from: molly on November 26, 2017, 06:14:58 pmThe documentation states: QuoteContrary to ordinary constants, a value can be assigned to them at run-time. In case the compiler optimized things away between different calls then it is the compiler/optimizer at fault, not respecting the consequences of the statement made in the documentation.For optimisation there is only trouble in case of multithreading, because the constant could be changed in any moment of time and the other thread could be at any place in the code. But exactly the same holds for ALL* variables. (*Only procedure local variables surely cannot be changed from outside). And I start to believe that this is actually the current situation, i.e. that all variables that are used in more than one procedure (or are published to other units) are treated as volatiles, at least something alike. E.g. the "Terminated" variable of TThread is normally polled in a loop in the Execute method:   while not Terminated do Also in most cases the code within the loop doesn't modify the variable "Terminated", but by an other thread to indicate that the thread should terminate itself. For a compiler seeing "Terminated" as NON-volatile this would mean, its either an infinite loop, or the loop isn't even entered once. Obviously, such optimisation isn't done. Looking at optimisations, I would expect that the following lines   AComponent.value:= 12;   [...]   AComponent.value:= AComponent.value * a; are optimized to something like   AComponent.value:= 12 * a; On the other hand if the variable is used e.g. as locking mechanism:   AComponent. Lockstate:= 2;   [...]   AComponent. Lockstate:= 3; they may not be optimized, otherwise it breaks functionality. So my question from the initial post still is open: Are these kinds of variables are treated like volatiles and if yes in what extend. If the answer is yes, then introducing a volatile modifier actually would mean to introduce non-volatile variables and with that allow deeper optimisations. That may break existing code, though. If the answer is no, then some improvements are neccessary to make fpc usable on target embedded. QuoteIn that regards i also don't fully understand why there would be need for a compiler hint to force this or that, unless it isn't possible to guarantee the compiler behaviour in any other way. If all variables are volatile by default then of course the compiler behaviour is guaranteed and no optimisation issues can arise (because there couldn't be any variable optimisation be done). EDIT: From the programmers guide: Quote11.1.13    Register variables When using the -Or switch, local variables or parameters which are used very often will be moved to registers for faster access.ftp://ftp.freepascal.org/pub/fpc/docs- pdf/prog.pdf#subsection.11.1.13 ---------------------------------------------------------------------- molly · 2017-12-04 16:31 Thank you for your clear examples engkin Quote from: engkin on November 27, 2017, 01:31:53 amNothing in the documentation prevents the compiler from keeping a constant in a register, That is where we kind of disagree I quote again from documentation: QuoteContrary to ordinary constants, a value can be assigned to them at run-time. Just like a ordinary variable, this special type of constant can be assigned a value at runtime. That is a convention to which, i assume, we both agree. Again i note my naive approach that tells me that if i can assign a value to it at runtime that the compiler (or optimizer) would have to take that convention into account. By not doing so, the convention to which we agreed is worth nothing as the compiler/optimizer breaks that convention, producing code that is unpredictable. In that regards i'm more in line with kupferstecher/ccrause's posts and the remark about this kind of constant always being 'volatile'. Quoteand based on {$J} it may allow/prevent a change to its value. On the other hand, accessing a volatile variable means accessing the memory every time, no matter what. I agree with you engkin that in case it is unclear that it would be more helpful to hint/instruct the compiler, i just fail to see why it should be the other way around (unless the motivation for that would be that other compilers implement it that way). Quote from: kupferstecher on November 27, 2017, 01:27:16 pmFrom the programmers guide: Quote11.1.13    Register variables When using the -Or switch, local variables or parameters which are used very often will be moved to registers for faster access.ftp://ftp.freepascal.org/pub/fpc/docs- pdf/prog.pdf#subsection.11.1.13 Thank you for that link kupferstecher. I seem to have missed that. Still, my naive approach tells me that if anything breaks there is something at fault. Would using normal variables break my code in a similar fashion do we then agree we should use a special keyword to keep code from breaking when using optimization ? ---------------------------------------------------------------------- kupferstecher · 2017-12-04 17:08 Quote from: molly on December 04, 2017, 05:31:49 pmStill, my naive approach tells me that if anything breaks there is something at fault. As I wrote in my post before, the only way to achive that nothing gets broken by optimisations is not to optimize on variable level at all (only procedure local variables are safe). I have the feeling that this is the current situation of fpc, but low optimisation isn't something good for advertise. QuoteBy not doing so, the convention to which we agreed is worth nothing as the compiler/optimizer breaks that convention, producing code that is unpredictable.The convention is totally fine in parts of the programm where context isn't switched and that I'd say is most of the code in programs. Why should typed constants be more suitable for multithreading than normal variables? Quote i just fail to see why it should be the other way around It would be imagable to introduce a variable modifier that does allow code optimisation for the marked variable (only). But normally most of the variables should be considered for optimisation. And only a very few in a programm are subject to context changes and thus are not allowed to be optimised. Also hardware register access of course may never be optimised. QuoteWould using normal variables break my code in a similar fashion do we then agree we should use a special keyword to keep code from breaking when using optimization ?As the examples showed they do At least in rare cases. ---------------------------------------------------------------------- engkin · 2017-12-05 03:33 Quote from: molly on December 04, 2017, 05:31:49 pmQuote from: engkin on November 27, 2017, 01:31:53 amNothing in the documentation prevents the compiler from keeping a constant in a register, That is where we kind of disagree In this case you also disagree with the compiler. In this example the compiler optimized i := t into movl $1,%eax despite the fact that t is a writable constant. Consider that code as part of the example of temperature sensors. I am trying to read the values of the sensors, but the compiler decided to give me a fixed value 1. I am trying to read the tenth sensor. Here is how it is done using C. How can I read that sensor using Pascal?. Quote from: molly on December 04, 2017, 05:31:49 pmI quote again from documentation: QuoteContrary to ordinary constants, a value can be assigned to them at run-time. Just like a ordinary variable, this special type of constant can be assigned a value at runtime. The implementation is left out. It does not specify whether this value is going to be assigned to a memory location or register(s), or used as an immediate value. Quote from: molly on December 04, 2017, 05:31:49 pmThat is a convention to which, i assume, we both agree. Again i note my naive approach that tells me that if i can assign a value to it at runtime that the compiler (or optimizer) would have to take that convention into account. By not doing so, the convention to which we agreed is worth nothing as the compiler/optimizer breaks that convention, producing code that is unpredictable. In that regards i'm more in line with kupferstecher/ccrause's posts and the remark about this kind of constant always being 'volatile'. kupferstecher did not get a satisfactory answer, yet. ccrause does not seem to believe that writable constants are volatile. Jonas based on ccrause's quote "in FPC there isn't a full equivalent of "volatile"" Martin made it clear writable constants are not volatile. ASerge knows there is no corresponding directive in FPC Molly, two questions: Why did Embarcadero add volatile to Delphi?How do I read my temperature sensors using pure Pascal? ---------------------------------------------------------------------- molly · 2017-12-05 06:40 Quote from: engkin on December 05, 2017, 04:33:52 amIn this case you also disagree with the compiler. In this example the compiler optimized i := t into movl $1,%eax despite the fact that t is a writable constant. Yes, that is affirmative. To be consistent that generated code would also have to be considered 'wrong'. QuoteConsider that code as part of the example of temperature sensors. I am trying to read the values of the sensors, but the compiler decided to give me a fixed value 1. Understood. QuoteI am trying to read the tenth sensor. Here is how it is done using C. How can I read that sensor using Pascal?. Declaring your t as threadvar should be able to do the trick ? But i don't know how your sensor is declared exactly so that might perhaps not be an option for your case ? Note that i did got the underlying message there  QuoteThe implementation is left out. It does not specify whether this value is going to be assigned to a memory location or register(s), or used as an immediate value. Yes, it is left out. We are not in disagreement there. However, being able to assign to it at runtime also means that whenever the value is changed, the generated code should account for that situation, otherwise the part "a value can be assigned to them at run-time" has no meaning whatsoever. When using the naive approach, i don't care about what the compiler or optimizer does, as long as it obeys the statement (and corresponding implications that goes along with that statement). Either that or the documentation is incorrect (in which case it should add: but it doesn't matter what you write to them because the compiler simply ignores what you write to it... in certain circumstances, while in others it will work as intended by the programmer). Yes, the underlying message  Quotekupferstecher did not get a satisfactory answer, yet. ccrause does not seem to believe that writable constants are volatile. Jonas based on ccrause's quote "in FPC there isn't a full equivalent of "volatile"" Martin made it clear writable constants are not volatile. ASerge knows there is no corresponding directive in FPC Thank you for the links. I've read the thread though :-) So from those we are able to conclude that writable constant don't act as volatile under shown examples/remarks. QuoteMolly, two questions: Why did Embarcadero add volatile to Delphi?Because they are secretly converting their compiler into a transpiler which in the end will use gcc in order to be able to support more platforms  But on a more serious note: Is there a particular reason to have a fix for this 'problem' using a volatile solution ? I can already sense the Delphi compatibility argument coming up there. QuoteHow do I read my temperature sensors using pure Pascal?Using a threadvar ? See also my comment above. ---------------------------------------------------------------------- molly · 2017-12-05 06:54 Quote from: kupferstecher on December 04, 2017, 06:08:52 pmAs I wrote in my post before, the only way to achive that nothing gets broken by optimisations is not to optimize on variable level at all (only procedure local variables are safe). I have the feeling that this is the current situation of fpc, but low optimisation isn't something good for advertise. You've got a very valid point there. QuoteThe convention is totally fine in parts of the programm where context isn't switched and that I'd say is most of the code in programs. Why should typed constants be more suitable for multithreading than normal variables? I think we have a misunderstanding there as also engkin seems to believe i am in favour of using typed constant to 'solve' the issue. Let me clarify that this isn't what i attempted to advertise. Based on thaddy's remarks I was merely suggesting that it could be possible that a typed constants currently act that way by default. QuoteIt would be imagable to introduce a variable modifier that does allow code optimisation for the marked variable (only). But normally most of the variables should be considered for optimisation. And only a very few in a programm are subject to context changes and thus are not allowed to be optimised. Also hardware register access of course may never be optimised. Also a very valid point and is a very good argument to not do it the other way around as i suggested. I also prefer your remark about using a variable modifier or perhaps a specific section for those variables that aren't allowed to be 'optimized away'. QuoteAs the examples showed they do At least in rare cases. Yes, that indeed deserves a ---------------------------------------------------------------------- ccrause · 2017-12-06 03:15 Quote from: engkin on December 05, 2017, 04:33:52 am...How do I read my temperature sensors using pure Pascal? Quote from: engkin on November 27, 2017, 01:31:53 amSimple example: Imagine a set of ten temperature sensors memory mapped to one location. To me it seems as if the original Pascal sample code you reference isn't memory mapped.  t is simply an assignable const.  I think your example started as a test of Thaddy's volatile = {$J+} const assertion.  So expanding your example to map variable t to a memory location does produce the expected (at least what I expected ) code: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program project1; var  t: byte absolute 1;  temp: byte; begin  t := 255;  temp := t;  WriteLn(temp);end. The generated assembler for the main code (on x86_64 linux), optimization level -O4: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i # [8] t := 255;        movq    $1,%rax        movb    $255,(%rax).Ll3:# [9] temp := t;        movq    $1,%rax        movb    (%rax),%al        movb    %al,U_$P$PROJECT1_$$_TEMP(%rip).Ll4:# [10] WriteLn(temp);        call    fpc_get_output@PLT# etc.Memory is accessed both when writing and reading (if my limited understanding of AT&T assembler is correct).  Of course it generates a runtime error since the operating system is interfering... ---------------------------------------------------------------------- Martin_fr · 2017-12-06 03:32 Using the generated asm is really meaningless. Just because current FPC does not apply a specific optimization, does not mean that future FPC wont either. If it isn't documented, then it can not be relied upon. The doc for typed constant https://www.freepascal.org/docs- html/3.0.2/ref/refse10.html sets them equal to initialized global variables. That doc does not guarantee that not in future -O5 may optimize those variables to a register. (A variable cached in a register is still writeable) So either their is no volatile, or (if all globals are meant to be volatile) the doc for that is missing. ---------------------------------------------------------------------- engkin · 2017-12-06 05:43 Quote from: ccrause on December 06, 2017, 04:15:34 amCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program project1; var  t: byte absolute 1;  temp: byte; begin  t := 255;  temp := t;  WriteLn(temp);end.Thank you for this example. I took your code and recompiled it using your options and adding {$Optimization REGVAR+}. Here is the emitted assembly: Code: ASM  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i _main:; [project1.lpr]; [9] begin                push    ebx                push    esi; Var temp located in register bl                call    FPC_INITIALIZEUNITS                mov     al,0; [10] t := 255;              mov     bl,255; Var temp located in register bl              mov     byte ptr [+1],bl; [12] WriteLn(temp);...You ask the compiler to emit code for: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   t := 255;  temp := t;and the result -remember temp is in bl-: Code: ASM  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i               mov     bl,255                mov     byte ptr [+1],blwhich is more like: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   temp := 255;  t := temp; There are TWO problems with the emitted assembly: For temp := t the compiler did *NOT* read the value from the memory location. Instead it used an immediate value mov   bl,255It assigned the value 255 to temp (bl) *BEFORE* writing it to t, unlike the order of instructions in your codeBoth problems should not exist when dealing with volatile variables. In your example the compiler failed to read the first temperature sensor.  @Martin, thank you. ---------------------------------------------------------------------- ccrause · 2017-12-07 12:17 Quote from: Martin_fr on December 06, 2017, 04:32:56 amIf it isn't documented, then it can not be relied upon. Agreed, my interest in this discussion is finding out what is currently possible even though it isn't documented. Quote from: engkin on December 06, 2017, 06:43:13 amI took your code and recompiled it using your options and adding {$Optimization REGVAR+}. Indeed this shows the problem of not having an explicit modifier for volatile. Quote from: engkin on December 06, 2017, 06:43:13 amIn your example the compiler failed to read the first temperature sensor.  I guess you have to indicate what constitutes "reading a sensor".  My interpretation was that a specific memory location is read and assigned to a different variable for further processing. ---------------------------------------------------------------------- engkin · 2017-12-07 16:55 Quote from: ccrause on December 07, 2017, 01:17:34 pmQuote from: engkin on December 06, 2017, 06:43:13 amIn your example the compiler failed to read the first temperature sensor.  I guess you have to indicate what constitutes "reading a sensor".  My interpretation was that a specific memory location is read and assigned to a different variable for further processing. Your interpretation is correct. The problem the compiler did *not* emit any code to read the location you specified in your example. ---------------------------------------------------------------------- ccrause · 2017-12-07 19:35 Quote from: engkin on December 07, 2017, 05:55:32 pmQuote from: ccrause on December 07, 2017, 01:17:34 pmQuote from: engkin on December 06, 2017, 06:43:13 amIn your example the compiler failed to read the first temperature sensor.  I guess you have to indicate what constitutes "reading a sensor".  My interpretation was that a specific memory location is read and assigned to a different variable for further processing. Your interpretation is correct. The problem the compiler did *not* emit any code to read the location you specified in your example. I thought the assembler code generated for my example did exactly that: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i # [9] temp := t;        movq    $1,%rax        movb    (%rax),%al        movb    %al,U_$P$PROJECT1_$$_TEMP(%rip)My interpretation of the instruction sequence is: move value 1 into register RAX (variable t was specified at address 1 in the example), then move the byte value at the address pointed to by RAX into register AL (so AL now contain the content of memory location 1), then move the content of register AL into memory location for variable temp.  I had to reference this page to decode the syntax, so I may be wrong. ---------------------------------------------------------------------- engkin · 2017-12-07 19:44 Quote from: ccrause on December 07, 2017, 08:35:11 pmQuote from: engkin on December 07, 2017, 05:55:32 pmQuote from: ccrause on December 07, 2017, 01:17:34 pmQuote from: engkin on December 06, 2017, 06:43:13 amIn your example the compiler failed to read the first temperature sensor.  I guess you have to indicate what constitutes "reading a sensor".  My interpretation was that a specific memory location is read and assigned to a different variable for further processing. Your interpretation is correct. The problem the compiler did *not* emit any code to read the location you specified in your example. I thought the assembler code generated for my example did exactly that: Not when I used {$Optimization REGVAR+}. ---------------------------------------------------------------------- Thaddy · 2017-12-07 20:00 Quote from: engkin on December 07, 2017, 08:44:11 pmQuote from: ccrause on December 07, 2017, 08:35:11 pmQuote from: engkin on December 07, 2017, 05:55:32 pmQuote from: ccrause on December 07, 2017, 01:17:34 pmQuote from: engkin on December 06, 2017, 06:43:13 amIn your example the compiler failed to read the first temperature sensor.  I guess you have to indicate what constitutes "reading a sensor".  My interpretation was that a specific memory location is read and assigned to a different variable for further processing. Your interpretation is correct. The problem the compiler did *not* emit any code to read the location you specified in your example. I thought the assembler code generated for my example did exactly that: Not when I used {$Optimization REGVAR+}. Should not happen when: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program project1;{$WRITEABLECONST ON}var t:byte absolute 1;const    temp: byte = 0; begin  t := 255;  temp := t;  WriteLn(temp);end. Because- as I explained before - they are memory locations. ---------------------------------------------------------------------- engkin · 2017-12-07 20:06 Quote from: Thaddy on December 07, 2017, 09:00:07 pmQuote from: engkin on December 07, 2017, 08:44:11 pmQuote from: ccrause on December 07, 2017, 08:35:11 pmQuote from: engkin on December 07, 2017, 05:55:32 pmQuote from: ccrause on December 07, 2017, 01:17:34 pmQuote from: engkin on December 06, 2017, 06:43:13 amIn your example the compiler failed to read the first temperature sensor.  I guess you have to indicate what constitutes "reading a sensor".  My interpretation was that a specific memory location is read and assigned to a different variable for further processing. Your interpretation is correct. The problem the compiler did *not* emit any code to read the location you specified in your example. I thought the assembler code generated for my example did exactly that: Not when I used {$Optimization REGVAR+}. Should not happen when: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program project1;{$WRITEABLECONST ON}const  t: byte absolute 1;  temp: byte; begin  t := 255;  temp := t;  WriteLn(temp);end.Because- as I explained before - they are memory locations. You might be right. Let me try. ---------------------------------------------------------------------- Thaddy · 2017-12-07 20:09 I tried and had to change the example a bit. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program project1;{$WRITEABLECONST ON}var t:byte absolute 1; //forced memory locationconst    temp: byte = 0; // memory location because of J+ begin  t := 255;  temp := t;  WriteLn(temp);end. {$OPTIMIZATION REGVAR+} has a bug if it does not work..... BUT it works on arm: Code: Text  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i main:      stmfd   r13!,{r4,r14}        bl      fpc_initializeunits        ldr   r1,.Lj3   ; address 1        mov     r0,#255   ; load the var value        ldr     r2,.Lj3   ; address 1        strb    r0,[r1]   ; store value at address 1........Lj3:        .long   1..... ---------------------------------------------------------------------- engkin · 2017-12-07 20:31 Well, it turned out that absolute can not be used with constants. IOW, this does not compile: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i const  t: byte absolute 1;or  t: byte = 2 absolute 1; Meaning you can not give a constant a specific address. Quote from: Thaddy on December 07, 2017, 09:09:15 pmI tried and had to change the example a bit. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program project1;{$WRITEABLECONST ON}var t:byte absolute 1; //forced memory locationconst    temp: byte = 0; // memory location because of J+ begin  t := 255;  temp := t;  WriteLn(temp);end. {$OPTIMIZATION REGVAR+} has a bug if it does not work..... Let me assume that it works. What are the rules? Are you saying that if you give a variable a specific address using absolute then: You can write to it and it will be written to the memory always no matter what.But to read from that memory location you have to use a writable typed constant? ---------------------------------------------------------------------- Thaddy · 2017-12-07 20:41 - If the memory is not ROM or EEPROM but any form of RAM that is mapped in by the OS.. - If sufficient rights Then, yes, the absolute guarantees a fixed location and - at least on arm - the compiler obeys this even with regvar+. To prevent the compiler from optimizing the second , I used the trick of J+ which *guarantees* a memory location. Now what I see on arm is that it works like planned. Any assignment is done on the register level, but the result is written back. (Note of course this example will crash (loc 1 is not safe!) and just meant to examine its assembler output, but it works for e.g. the GPIO addresses on the Raspberry Pi.) ---------------------------------------------------------------------- kupferstecher · 2017-12-07 23:39 Quote from: Thaddy on December 07, 2017, 09:09:15 pmBUT it works on arm: If I read the assembly correctly then temp is not stored to memory, but handled in a register, isn't? Then why would you use a writable typed constant instead of a variable? QuoteI tried and had to change the example a bit. The only difference I saw in your code is the initialisation of the typed constant, right? Why was that necessary? ---------------------------------------------------------------------- molly · 2017-12-07 23:51 Quote from: kupferstecher on December 08, 2017, 12:39:11 amWhy was that necessary? Code: [Select]Fatal: Syntax error, "=" expected but ";" foundIt is how constants work, also typed constants. ---------------------------------------------------------------------- engkin · 2017-12-08 04:31 For i386: Code: ASM  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i ; [10] t := 255;                mov     al,255                mov     byte ptr [+1],al; [11] temp := t;                mov     byte ptr [TC_$P$PROJECT1_$$_TEMP],al  Notice how it did *not* read anything from the memory location specified by absolute . The optimizer is doing a good job for usual variables, but not what is needed here for volatile variables. Let's try AVR: Code: ASM  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i # [10] t := 255;        ldi     r26,-1        mov     r18,r26        sts     (+1),r18# [11] temp := t;        lds     r0,(+1)        sts     (TC_sPsPROJECT1_ss_TEMP),r0 At first it seems like it is doing what we need, but in fact there seem to be no optimization. See the highlighted line? Again, no equivalent to volatile. As Martin said: QuoteIf it isn't documented, then it can not be relied upon. ---------------------------------------------------------------------- kupferstecher · 2017-12-08 09:23 Quote from: molly on December 08, 2017, 12:51:26 amIt is how constants work, also typed constants. Of course. Stupid me ---------------------------------------------------------------------- ccrause · 2017-12-08 15:35 Quote from: engkin on December 08, 2017, 05:31:15 amLet's try AVR: Code: ASM  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i # [10] t := 255;        ldi     r26,-1        mov     r18,r26        sts     (+1),r18# [11] temp := t;        lds     r0,(+1)        sts     (TC_sPsPROJECT1_ss_TEMP),r0 At first it seems like it is doing what we need, but in fact there seem to be no optimization. See the highlighted line? Again, no equivalent to volatile. The intention of the assignment Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i temp := t;(if this is still about my example) is that a value is read from a memory location - the instruction on line 6 loads a value from memory location 1 into register r0. This is exactly the intended behaviour and confirmed also on ARM by Thaddy. You also refer to the unnecessary register move on line 6, this is a completely separate issue that does not invalidate the correctness of the code, only the optimality of the code size. ---------------------------------------------------------------------- engkin · 2017-12-08 17:24 Quote from: ccrause on December 08, 2017, 04:35:18 pmQuote from: engkin on December 08, 2017, 05:31:15 amLet's try AVR: Code: ASM  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i # [10] t := 255;        ldi     r26,-1        mov     r18,r26        sts     (+1),r18# [11] temp := t;        lds     r0,(+1)        sts     (TC_sPsPROJECT1_ss_TEMP),r0 At first it seems like it is doing what we need, but in fact there seem to be no optimization. See the highlighted line? Again, no equivalent to volatile. The intention of the assignment Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i temp := t;(if this is still about my example) is that a value is read from a memory location - the instruction on line 6 loads a value from memory location 1 into register r0. This is exactly the intended behaviour and confirmed also on ARM by Thaddy. How do you explain the emitted code for I386? As you can see it is not the intended behaviour. Even Thaddy called it "a trick". Quote from: ccrause on December 08, 2017, 04:35:18 pmYou also refer to the unnecessary register move on line 6, this is a completely separate issue that does not invalidate the correctness of the code, only the optimality of the code size. I highlighted line 6 to make it clear that the optimizer (assuming there is any) for AVR is not as mature as the optimizer for i386. It is not a separate issue, as volatile simply prevents certain optimizations. But if the compiler does not optimize at all, then the output would seem correct. As Martin said: QuoteUsing the generated asm is really meaningless. Just because current FPC does not apply a specific optimization, does not mean that future FPC wont either. If it isn't documented, then it can not be relied upon. I use the generated asm to negate claims. It can not be used to prove these claims. ---------------------------------------------------------------------- Thaddy · 2017-12-10 10:57 It is still my belief that the intended behaviour for both absolute and typed const are like it is. That the compiler - at this point in time - does not optimize can be because devs did not look into optimizing such code yet. Which basically reverses the argument: If that is the case, it is not a trick but not-optimal code generation. My reasoning is that : - absolute *guarantees* a fixed memory address when used on an absolute address: it is not a register - a Typed const guarantees that its contents are modifiable anywhere, which implies a fixed memory location. If that reasoning is correct, the compiler behaves correct. It just does not optimise the special case where fixed memory locations are forced. Which is what volatile essentially is and essentially works. Maybe a compiler dev can shed some light on it. If I am correct, it is not a trick and we have "volatile". (Other than that a typed const on an absolute address should maybe take its value from that address and not demand an initial value) Otherwise I will revise my opinion. But anyway: e.g. a bitpacked record declared over a range that starts with an absolute value (GPIO on Raspberry Pi for example) can be considered volatile. ---------------------------------------------------------------------- kupferstecher · 2017-12-10 12:55 Quote from: Thaddy on December 10, 2017, 11:57:08 amThat the compiler - at this point in time - does not optimize can be because devs did not look into optimizing such code yet. Which basically reverses the argument: If that is the case, it is not a trick but not-optimal code generation.Agreed, but the thing is, as long as volatility is not described in the documentation, i.e. as long as its not agreed on a general concept, then nobody can work on optimisations in this direction. I started this thread to learn if there is a general concept. And I still think "every variable but function locals are volatile" it currently is (even if its no strict volatility). Introducing a volatile modifier of course only makes sense if that principle is omitted, which could break existing code. For example the property TThread.Terminated is a boolean property. Again it could be defined that properties are always volatile (which probably is useful). But existing code may use instance variables as flag between threads and if they are not treated as volatiles any more, this could destroy the intented behaviour. How does the variable load and storage of shared variables in multithreading applications actually work? When is OS-support needed and when can variables be accessed directly? IMHO TThread.Terminated does require volatile behaviour, otherwise the loop   while not Terminated do ... could be "optimised" to   if not Terminated then while true do ... QuoteIf I am correct, it is not a trick and we have "volatile".Sure, a change to a volatile modifier would be a bigger thing. On the other hand, if by now because of missing optimisation everything is near volatile anyways, than the introduction of "volatile" itself should be not too complex (but without consequences to generated code) and higher efforts in the compiler development just start when optimisations are actually implemented. For the user it would show a clear concept and for the compiler developers it provides the possibility for further optimisations. QuoteMy reasoning is that : - absolute *guarantees* a fixed memory address when used on an absolute address: it is not a registerAgreed, I also don't see an other usecase for the absolute address. But strict volatility is required, i.e. if I code twelve consecutive read accesses then the compiler has to translate to exactly twelve read accesses. Quote- a Typed const guarantees that its contents are modifiable anywhere, which implies a fixed memory location.You could reason like that for a future implementation, but as there seems to be not even a side note about volatility in the documentation, you couldn't say any different behaviour means its a bug. On the other hand, if there is no optimisation done on variable level, why use typed constants to ensure something that normal variables are already doing?