[fpc-devel] Possible idea... "safe" subroutines/methods

J. Gareth Moreton gareth at moreton-family.com
Sat May 4 18:22:19 CEST 2019


Ah, slightly misinterpreted the aliasing thing... yeah, that is a danger 
to consider.  I'll have to think about that one.  That alone may make 
safe procedures, at least ones with var and out parameters, relatively 
impossible.

Gareth aka. Kit

On 04/05/2019 17:06, J. Gareth Moreton wrote:
> This is why I posted to the group!  You can catch things that I might 
> miss.
>
> For the aliasing issue, I envisioned that var parameters wouldn't be 
> affected.  Since the address is already in a register or on the stack, 
> it's relatively efficient already.
>
> For the subroutine call, that is indeed a little more difficult, and 
> the compiler would have to consider that a subroutine call may modify 
> one of the non-local values.
>
> C/C++ was never my first language, so generally I try not to mirror 
> it.  I even joked that seeing C-style standards in Pascal source is 
> tantamount to colonialism!
>
> I've noticed that my take on coding is somewhat different to others at 
> times.  I tend not to trust the compiler to make the most efficient 
> code.  I think the best analogy would be the difference between the 
> Quake and the Unreal engines... Quake does all the BSP and portal 
> building itself during a map compilation stage, while with the Unreal 
> engine, the mapper decides where portals and the like go.  It is a 
> tiny bit more work, but it allowed for highly detailed and optimised 
> maps so long as you used a bit of logical thinking.
>
> The reason why I suggested a modifier directive is for similar reasons 
> why I'm doing the same thing with pure functions... for compilation 
> speed.  If a function is marked as pure, the compiler will have to do 
> a lot more processing and analysis, so if all functions are implicitly 
> considered pure until proven otherwise, it will slow down compilation 
> significantly.  A similar thing may happen with safe functions because 
> it will have to undertake data flow analysis.  It's hard to say if the 
> compiler performance hit will be significant or not, but you may be 
> right in that safe procedures can be merged with data-flow analysis if 
> it becomes a major part of the compiler.  The only risk is with 
> multi-threading again - if a procedure suddenly behaves differently 
> under the highest optimisation settings because of the lack of a 
> 'volatile' intrinsic, I personally consider it a bug (which is why I'm 
> not a fan of -O4 with its advertised 'may cause side-effects').
>
> It does make for some interesting discussion though!
>
> Gareth aka. Kit
>
>
> On 04/05/2019 09:37, Jonas Maebe wrote:
>> On 2019-05-03 19:37, J. Gareth Moreton wrote:
>>> By telling the compiler that the procedure (or maybe a whole class) is
>>> thread-safe, you are telling it that you can guarantee that any
>>> objects, fields or global variables that you access are guaranteed to
>>> not suddenly change mid-routine (because another thread has modified
>>> it).  This would allow the compiler to move commonly-accessed fields
>>> into local registers or the stack for faster access, especially if the
>>> fields are only read and not written, since they'll be guaranteed to
>>> contain a constant value.
>>
>> Multi-threading is not the main issue. The main problems are aliasing 
>> and subroutine calls:
>>
>> 1) Aliasing
>>
>> type
>>   tc = class
>>     a: longint;
>>     procedure test(var l: longint);
>>   end;
>>
>> procedure tc.test(var l: longint);
>> begin
>>   if a<>5 then
>>     begin
>>       l:=1;
>>       // the above will change c.a to 1, but if c.a is in a register 
>> that will not be detected
>>       if a<>1 then
>>         writeln('error');
>>     end;
>> end;
>>
>> var
>>   c: tc;
>> begin
>>   c:=tc.create;
>>   c.a:=6;
>>   c.test(c.a);
>>   c.free;
>> end.
>>
>>
>> 2) subroutine calls
>>
>> type
>>   tc = class
>>     a: longint;
>>     procedure test;
>>   end;
>>
>> var
>>   c: tc;
>>
>> procedure change;
>> begin
>>   c.a:=1;
>> end;
>>
>> procedure tc.test;
>> begin
>>   if a<>5 then
>>     begin
>>       change;
>>       if a<>1 then
>>         writeln('error');
>>     end;
>> end;
>>
>> begin
>>   c:=tc.create;
>>   c.a:=6;
>>   c.test;
>>   c.free;
>> end.
>>
>> In both cases, many additional scenarios are possible (there are many 
>> different way to alias memory and to perform modifications in 
>> subroutine calls).
>>
>> For the former, you need inter-procedural alias analysis, or limit 
>> yourself to routines that only write to local variables. For the 
>> latter, you need to limit yourself to routines that don't call other 
>> routines, and/or record various function attributes that indicate 
>> what these other routines do. See e.g. the function attributes from 
>> LLVM (http://llvm.org/docs/LangRef.html#function-attributes) like 
>> inaccessiblememonly, inaccessiblemem_or_argmemonly, readnone, 
>> readonly, writeonly, and argmemonly. Since LLVM found a use for them 
>> in terms of optimising code, they're probably a good a start.
>>
>> I wish to stress that I do _not_ propose or support adding any of 
>> those attributes to the language; most of those attributes don't 
>> exist in C/C++ either. They get added by LLVM itself while optmising 
>> and analysing the functions, or by compiler backends for 
>> auto-generted functions.
>>
>> However, you could add compiler analyses that add those, or similar, 
>> attributes to the implementation procdef flags 
>> (tprocdef.implprocoptions), and then make use of those attributes 
>> even in cross-unit calls (in case the body of the function in the 
>> other unit has already been compiled, similar to inlining). Or in 
>> case of whole-program optimisation, they could written and loaded for 
>> the entire program, so you can use them even when function bodies 
>> have not yet been parsed.
>>
>> As far as the threading issue is concerned: trunk has support for the 
>> "volatile" intrinsic. At most, I would add an optimizer option that 
>> prevents optimisations that may break things in case "volatile" is 
>> missing. This should happen in very few places though, since it can 
>> only change the behaviour of a well-defined program if you are 
>> busy-waiting on a single value that another thread may change (and do 
>> nothing else with values produced by this other thread, unless you 
>> also add a bunch of memory barriers and, depending on the 
>> architecture, also acquire/release helpers).
>>
>>
>> Jonas
>> _______________________________________________
>> fpc-devel maillist  -  fpc-devel at lists.freepascal.org
>> http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
>>
>>
>
> ---
> This email has been checked for viruses by Avast antivirus software.
> https://www.avast.com/antivirus
>
> _______________________________________________
> fpc-devel maillist  -  fpc-devel at lists.freepascal.org
> http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
>
>



More information about the fpc-devel mailing list