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

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


I will say though that I'm reluctant to program any kind of automatic 
optimisation that is not thread-safe, even with the 'volatile' 
intrinsic.  A 'safe' directive is a way of telling the compiler that 
"this routine will not be affected by multi-threaded shenanigans" so is 
safe to make thread-unsafe optimisations, so long as aliasing and the 
like doesn't catch me off-guard.

At the same time, if you're feeling very ballsy (or you know exactly 
what you're doing), you could mark a routine as safe so most global 
values benefit from potential optimisations, but the one value that is 
not thread-safe you can put inside a volatile intrinsic.  At least 
that's the plan.  The idea is that directives and modifiers only remove 
compiler safety, not add to it because of an uncertain optimisation.

Gareth

On 04/05/2019 17:22, J. Gareth Moreton wrote:
> 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
>>
>>
> _______________________________________________
> 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